8199643: [TESTBUG] Open source common VM testbase code
Reviewed-by: vlivanov, erikj, mseledtsov, gthornbr
--- a/make/test/JtregNativeHotspot.gmk Mon Apr 30 20:29:19 2018 -0400
+++ b/make/test/JtregNativeHotspot.gmk Mon Apr 30 18:10:24 2018 -0700
@@ -48,6 +48,21 @@
BUILD_HOTSPOT_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/hotspot/jtreg
+################################################################################
+# Former VM TestBase tests.
+################################################################################
+
+VM_TESTBASE_DIR := $(TOPDIR)/test/hotspot/jtreg/vmTestbase
+
+VM_SHARE_INCLUDES := \
+ -I$(VM_TESTBASE_DIR)/vm/share \
+ -I$(VM_TESTBASE_DIR)/nsk/share/native \
+ -I$(VM_TESTBASE_DIR)/nsk/share/jni
+
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
+
+################################################################################
+
# Platform specific setup
ifneq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
BUILD_HOTSPOT_JTREG_EXCLUDE += liboverflow.c exeThreadSignalMask.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/ExecDriver.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ */
+
+import jdk.test.lib.Platform;
+import jdk.test.lib.Utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+/**
+ * Starts a new process to execute a command.
+ * <p>Usage: --java|--cmd|--launcher <arg>+
+ * <p>If {@code --cmd} flag is specified, the arguments are treated as
+ * a program to run and its arguments. Non-zero exit code of the created process
+ * will be reported as an {@link AssertionError}.
+ * <p>If {@code --java} flag is specified, the arguments are passed to {@code java}
+ * from JDK under test. If exit code doesn't equal to 0 or 95, {@link AssertionError}
+ * will be thrown.
+ * <p>If {@code --launcher} flag is specified, the arguments treated similar as
+ * for {@code --cmd}, but the started process will have the directory which
+ * contains {@code jvm.so} in dynamic library path, and {@code test.class.path}
+ * as CLASSPATH environment variable. Exit codes are checked as in
+ * {@code --java}, i.e. 0 or 95 means pass.
+ */
+public class ExecDriver {
+ public static void main(String[] args) throws IOException, InterruptedException {
+ boolean java = false;
+ boolean launcher = false;
+
+ String type = args[0];
+ switch (type) {
+ case "--java":
+ String[] oldArgs = args;
+ int count;
+ String libraryPath = System.getProperty("test.nativepath");
+ if (libraryPath != null && !libraryPath.isEmpty()) {
+ count = 4;
+ args = new String[args.length + 3];
+ args[3] = "-Djava.library.path=" + libraryPath;
+ } else {
+ count = 3;
+ args = new String[args.length + 2];
+ }
+ args[0] = javaBin();
+ args[1] = "-cp";
+ args[2] = Utils.TEST_CLASS_PATH;
+ System.arraycopy(oldArgs, 1, args, count, oldArgs.length - 1);
+ java = true;
+ break;
+ case "--launcher":
+ java = true;
+ launcher = true;
+ case "--cmd":
+ args = Arrays.copyOfRange(args, 1, args.length);
+ break;
+ default:
+ throw new Error("unknown type: " + type);
+ }
+ // adding 'test.vm.opts' and 'test.java.opts'
+ if (java) {
+ String[] oldArgs = args;
+ String[] testJavaOpts = Utils.getTestJavaOpts();
+ if (testJavaOpts.length > 0) {
+ args = new String[args.length + testJavaOpts.length];
+ // bin/java goes before options
+ args[0] = oldArgs[0];
+ // then external java options
+ System.arraycopy(testJavaOpts, 0, args, 1, testJavaOpts.length);
+ // and then options and args from a test
+ System.arraycopy(oldArgs, 1, args, 1 + testJavaOpts.length, oldArgs.length - 1);
+ }
+ }
+ String command = Arrays.toString(args);
+ System.out.println("exec " + command);
+
+ ProcessBuilder pb = new ProcessBuilder(args);
+ // adding jvm.so to library path
+ if (launcher) {
+ Path dir = Paths.get(Utils.TEST_JDK);
+ String name;
+ if (Platform.isWindows()) {
+ dir = dir.resolve("bin")
+ .resolve(variant())
+ .toAbsolutePath();
+ name = "PATH";
+ } else {
+ dir = dir.resolve("lib")
+ .resolve(variant())
+ .toAbsolutePath();
+ name = Platform.isOSX() ? "DYLD_LIBRARY_PATH" : "LD_LIBRARY_PATH";
+ }
+
+ System.out.println(" with " + name + " = " +
+ pb.environment()
+ .merge(name, dir.toString(), (x, y) -> y + File.pathSeparator + x));
+ System.out.println(" with CLASSPATH = " +
+ pb.environment()
+ .put("CLASSPATH", Utils.TEST_CLASS_PATH));
+ }
+ Process p = pb.start();
+ // inheritIO does not work as expected for @run driver
+ new Thread(() -> copy(p.getInputStream(), System.out)).start();
+ new Thread(() -> copy(p.getErrorStream(), System.out)).start();
+ int exitCode = p.waitFor();
+
+ if (exitCode != 0 && (!java || exitCode != 95)) {
+ throw new AssertionError(command + " exit code is " + exitCode);
+ }
+ }
+
+ private static String variant() {
+ if (Platform.isServer()) {
+ return "server";
+ } else if (Platform.isClient()) {
+ return "client";
+ } else if (Platform.isMinimal()) {
+ return "minimal";
+ } else {
+ throw new Error("TESTBUG: unsuppported vm variant");
+ }
+ }
+
+
+ private static void copy(InputStream is, OutputStream os) {
+ byte[] buffer = new byte[1024];
+ int n;
+ try (InputStream close = is) {
+ while ((n = is.read(buffer)) != -1) {
+ os.write(buffer, 0, n);
+ }
+ os.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static String javaBin() {
+ return Paths.get(Utils.TEST_JDK)
+ .resolve("bin")
+ .resolve("java")
+ .toAbsolutePath()
+ .toString();
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/PropertyResolvingWrapper.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Replaces all {@code ${<X>}} with value of corresponding property({@code X}),
+ * resulting string is handled similarly to {@code @run main} in jtreg.
+ * In other words, {@code main} of first token will be executed with the rest
+ * tokens as arguments.
+ *
+ * If one of properties can't be resolved, {@link Error} will be thrown.
+ */
+public class PropertyResolvingWrapper {
+ private static final Properties properties;
+ static {
+ Properties p = System.getProperties();
+ String name = p.getProperty("os.name");
+ String arch = p.getProperty("os.arch");
+ String family;
+ String simple_arch;
+
+ // copy from jtreg/src/share/classes/com/sun/javatest/regtest/config/OS.java
+ if (name.startsWith("AIX"))
+ family = "aix";
+ else if (name.startsWith("Linux"))
+ family = "linux";
+ else if (name.startsWith("Mac") || name.startsWith("Darwin"))
+ family = "mac";
+ else if (name.startsWith("OS400") || name.startsWith("OS/400") )
+ family = "os400";
+ else if (name.startsWith("SunOS") || name.startsWith("Solaris"))
+ family = "solaris";
+ else if (name.startsWith("Windows"))
+ family = "windows";
+ else
+ family = name.replaceFirst("^([^ ]+).*", "$1"); // use first word of name
+
+ if (arch.contains("64")
+ && !arch.equals("ia64")
+ && !arch.equals("ppc64")
+ && !arch.equals("ppc64le")
+ && !arch.equals("zArch_64")
+ && !arch.equals("aarch64"))
+ simple_arch = "x64";
+ else if (arch.contains("86"))
+ simple_arch = "i586";
+ else if (arch.equals("ppc") || arch.equals("powerpc"))
+ simple_arch = "ppc";
+ else if (arch.equals("s390x") || arch.equals("zArch_64"))
+ simple_arch = "s390x";
+ else
+ simple_arch = arch;
+
+ p.setProperty("os.family", family);
+ p.setProperty("os.simpleArch", simple_arch);
+ properties = p;
+ }
+
+ public static void main(String[] args) throws Throwable {
+ List<String> command = new ArrayList<>(args.length);
+ for (int i = 0; i < args.length; ++i) {
+ StringBuilder arg = new StringBuilder(args[i]);
+ while (i < args.length - 1
+ && (arg.chars()
+ .filter(c -> c == '"')
+ .count() % 2) != 0) {
+ arg.append(" ")
+ .append(args[++i]);
+ }
+ command.add(eval(arg.toString()));
+ }
+ System.out.println("run " + command);
+ try {
+ Class.forName(command.remove(0))
+ .getMethod("main", String[].class)
+ .invoke(null, new Object[]{command.toArray(new String[0])});
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getCause();
+ t = t != null ? t : e;
+ throw t;
+ }
+ }
+
+ private static String eval(String string) {
+ int index;
+ int current = 0;
+ StringBuilder result = new StringBuilder();
+ while (current < string.length() && (index = string.indexOf("${", current)) >= 0) {
+ result.append(string.substring(current, index));
+ int endName = string.indexOf('}', index);
+ current = endName + 1;
+ String name = string.substring(index + 2, endName);
+ String value = properties.getProperty(name);
+ if (value == null) {
+ throw new Error("can't find property " + name);
+ }
+ result.append(value);
+ }
+ if (current < string.length()) {
+ result.append(string.substring(current));
+ }
+ int length = result.length();
+
+ if (length > 1 && result.charAt(0) == '"' && result.charAt(length - 1) == '"') {
+ result.deleteCharAt(length - 1);
+ result.deleteCharAt(0);
+ }
+ return result.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/README.md Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,10 @@
+# VM Testbase landing
+
+This directory serves as a _temporary_ landing place for tests converted from so-called VM testbase.
+Most of these tests have been written a long time ago, don't meet modern coding
+standards, guidelines and are in need of reworking.
+Eventually, all the tests located here should be reworked and moved accordingly to
+regular JTReg test suite directory layout convention, i.e. following the same
+layout as product code as close as possible.
+
+New tests must **not** be added into this directory.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/AbstractGoldChecker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+import java.io.UnsupportedEncodingException;
+
+public abstract class AbstractGoldChecker {
+
+ private final StringBuffer sb = new StringBuffer();
+
+ protected abstract String getGoldenString();
+
+ public void print(boolean b) {
+ sb.append(String.valueOf(b));
+ }
+
+ public void print(byte b) {
+ sb.append(String.valueOf(b));
+ }
+
+ public void print(char c) {
+ sb.append(String.valueOf(c));
+ }
+
+ public void print(int i) {
+ sb.append(String.valueOf(i));
+ }
+
+ public void print(long l) {
+ sb.append(String.valueOf(l));
+ }
+
+ public void print(float f) {
+ sb.append(String.valueOf(f));
+ }
+
+ public void print(double d) {
+ sb.append(String.valueOf(d));
+ }
+
+ public void print(String s) {
+ sb.append(s);
+ }
+
+ public void println() {
+ sb.append('\n');
+ }
+
+ public void println(boolean b) {
+ sb.append(String.valueOf(b));
+ sb.append('\n');
+ }
+
+ public void println(byte b) {
+ sb.append(String.valueOf(b));
+ sb.append('\n');
+ }
+
+ public void println(char c) {
+ sb.append(String.valueOf(c));
+ sb.append('\n');
+ }
+
+ public void println(int i) {
+ sb.append(String.valueOf(i));
+ sb.append('\n');
+ }
+
+ public void println(long l) {
+ sb.append(String.valueOf(l));
+ sb.append('\n');
+ }
+
+ public void println(float f) {
+ sb.append(String.valueOf(f));
+ sb.append('\n');
+ }
+
+ public void println(double d) {
+ sb.append(String.valueOf(d));
+ sb.append('\n');
+ }
+
+ public void println(String s) {
+ sb.append(s);
+ sb.append('\n');
+ }
+
+ public void check() {
+ String testOutput;
+ try {
+ testOutput = new String(sb.toString().getBytes("US-ASCII"), "US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new TestFailure(e);
+ }
+
+ String goldOutput = getGoldenString();
+ if (!compare(testOutput, goldOutput)) {
+ throw new TestFailure(
+ "Gold comparison failed\n" +
+ "\n" +
+ "Test output:\n" +
+ "============\n" +
+ "\n" +
+ testOutput +
+ "\n" +
+ "------------\n" +
+ "\n" +
+ "Gold output:\n" +
+ "============\n" +
+ "\n" +
+ goldOutput +
+ "\n" +
+ "------------\n" +
+ "\n"
+ );
+ }
+ }
+
+ public boolean compare(String src, String dst) {
+ int i1 = 0;
+ int i2 = 0;
+
+ int src_len = src.length();
+ int dst_len = dst.length();
+
+ while ((i1 < src_len) && (i2 < dst_len)) {
+
+ char c1 = src.charAt(i1++);
+ if ((c1 == '\r') && (i1 < src_len)) {
+ c1 = src.charAt(i1++);
+ }
+
+ char c2 = dst.charAt(i2++);
+ if ((c2 == '\r') && (i2 < dst_len)) {
+ c2 = dst.charAt(i2++);
+ }
+
+ if (c1 != c2) {
+ return false;
+ }
+ }
+ return (i1 == src_len) && (i2 == dst_len);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ArgumentParser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.*;
+
+import nsk.share.test.StressOptions;
+import nsk.share.test.Stresser;
+
+/**
+ * Parser for JDI test's command-line arguments.
+ * <p>
+ * Test's command line may contain two kind of arguments, namely:
+ * <ul>
+ * <li> options for ArgumentParser
+ * <li> other arguments for the test itself
+ * </ul>
+ * <p>
+ * We call <i>raw arguments</i> the <code>args[]</code> array
+ * passed to the test's method <code>main(String args[])</code>.
+ * ArgumentParser instance initialized with raw arguments serves to parse
+ * these two kinds of arguments. Use <code>ArgumentParser(args[])</code>
+ * constructor, or <code>setRawArguments(args[])</code> method
+ * to initialize a ArgumentParser instance with particular raw arguments.
+ * <p>
+ * Arguments, started with ``<code>-</code>'' symbol are called <i>options</i>.
+ * They are recognized by ArgumentParser and are used by support classes
+ * (such as Log, Binder, etc.).
+ * These options should be specified in the following general form:
+ * <ul>
+ * <li> <code>-option=<i>value</i></code>
+ * </ul>
+ * or
+ * <ul>
+ * <li> <code>-option <i>value</i></code>
+ * </ul>
+ * List of the recognized options with their values may be obtained by
+ * invoking method <code>getOptions()</code> that returnes
+ * a <code>Properties</code> object with options values.
+ * It is not recommended to get options value directly. An appropriate methods
+ * such as <code>verbose()</code>, <code>getArch()</code>, etc. should be used
+ * instead.
+ * Options may appear in the test command line in any order.
+ * <p>
+ * All the other arguments of command line are called <i>test arguments</i>
+ * (or simply <i>arguments</i>). These arguments should be handled by test itself.
+ * Full list of the test arguments in the same order as they appears in the command line
+ * may be obtained by invoking method <code>getArguments()</code>.
+ * <p>
+ * Following is the list of basic options accepted by AgrumentParser:
+ * <ul>
+ * <li> <code>-arch=</code><<i>${ARCH}</i>> -
+ * architecture name
+ * <li> <code>-waittime=</code><<i>minutes</i>> -
+ * timeout in minutes for waiting events or so
+ * <li> <code>-verbose</code> -
+ * verbose Log mode (default is quiet)
+ * <li> <code>-trace.time</code> -
+ * prefix log messages with timestamps (default is no)
+ * </ul>
+ * Also AgrumentParser supports following stress options (see nsk.share.test.StressOptions for details):
+ * <ul>
+ * <li> <code>-stressTime</code>
+ * <li> <code>-stressIterationsFactor</code>
+ * <li> <code>-stressThreadsFactor</code>
+ * <li> <code>-stressDebug</code>
+ * </ul>
+ * <p>
+ * Note, that the tests from the particular subsuites have its own argument handlers
+ * wich accepts additional options. See <code>jpda.DebugeeArgumentHandler</code>,
+ * <code>jdi.ArgumentHandler</code>, <code>jdwp.ArgumentHandler</code>.
+ *
+ * @see #setRawArguments(String[])
+ * @see #getRawArguments()
+ * @see #getArguments()
+ * @see #getOptions()
+ *
+ * @see nsk.share.jpda.DebugeeArgumentHandler
+ * @see nsk.share.jdwp.ArgumentHandler
+ * @see nsk.share.jdi.ArgumentHandler
+ * @see nsk.share.jvmti.ArgumentHandler
+ * @see nsk.share.monitoring.ArgumentHandler
+ */
+public class ArgumentParser {
+
+ /**
+ * Raw array of command-line arguments.
+ *
+ * @see #setRawArguments(String[])
+ * @see #getRawArguments()
+ */
+ protected String rawArguments[] = null;
+
+ /**
+ * Refined arguments -- raw arguments but options.
+ *
+ * @see #options
+ * @see #getArguments()
+ */
+ protected String arguments[] = null;
+
+ /**
+ * Recognized options for ArgumentParser class.
+ *
+ * @see #arguments
+ * @see #getOptions()
+ */
+ protected Properties options = new Properties();
+
+ /**
+ * Make new ArgumentParser object with default values of otions.
+ * This constructor is used only to obtain default values of options.
+ *
+ * @see #setRawArguments(String[])
+ */
+ protected ArgumentParser() {
+ String[] args = new String[0];
+ setRawArguments(args);
+ }
+
+ /**
+ * Keep a copy of raw command-line arguments and parse them;
+ * but throw an exception on parsing error.
+ *
+ * @param args Array of the raw command-line arguments.
+ *
+ * @throws BadOption If option values are invalid.
+ *
+ * @see #setRawArguments(String[])
+ * @see BadOption
+ */
+ public ArgumentParser(String args[]) {
+ setRawArguments(args);
+ }
+
+ /**
+ * Return a copy of the raw command-line arguments kept by
+ * this ArgumentParser instance.
+ *
+ * @throws NullPointerException If raw arguments were not
+ * set for this instance.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String[] getRawArguments() {
+ return (String[]) rawArguments.clone();
+ }
+
+ /**
+ * Return given raw command-line argument.
+ *
+ * @param index index of argument
+ * @return value of raw argument
+ */
+ public String getRawArgument(int index) {
+ return rawArguments[index];
+ }
+
+ /**
+ * Return refined array of test arguments (only those of the raw
+ * arguments which are not recognized as options for ArgumentParser).
+ *
+ * <p>Note, that sintax of test arguments was not checked;
+ * while syntax of arguments describing ArgumentParser's options
+ * was checked while raw arguments were set to this ArgumentParser
+ * instance.
+ *
+ * @throws NullPointerException If raw arguments were not
+ * set for this instance.
+ *
+ * @see #setRawArguments(String[])
+ * @see #getOptions()
+ */
+ public String[] getArguments() {
+ return (String[]) arguments.clone();
+ }
+
+ /**
+ * Return list of recognized otions with their values in the form of
+ * <code>Properties</code> object.
+ * If no options has been recognized, this list will be empty.
+ *
+ * @see #setRawArguments(String[])
+ * @see #getArguments()
+ */
+ public Properties getOptions() {
+ return (Properties) options.clone();
+ }
+
+ /**
+ * Join specified arguments into one line using given quoting
+ * and separator symbols.
+ *
+ * @param args Array of the command-line arguments
+ * @param quote Symbol used to quote each argument
+ * @param separator Symbol used as separator between argumnets
+ * @return Single line with arguments
+ */
+ static public String joinArguments(String args[], String quote, String separator) {
+ if (args.length <= 0) {
+ return "";
+ }
+ String line = quote + args[0] + quote;
+ for (int i = 1; i < args.length; i++) {
+ line += separator + quote + args[i] + quote;
+ }
+ return line;
+ }
+
+ /**
+ * Join specified arguments into one line using given quoting symbol
+ * and space as a separator symbol.
+ *
+ * @param args Array of the command-line arguments
+ * @param quote Symbol used to quote each argument
+ * @return Single line with arguments
+ */
+ static public String joinArguments(String args[], String quote) {
+ return joinArguments(args, quote, " ");
+ }
+
+ /**
+ * Keep a copy of command-line arguments and parse them;
+ * but throw an exception on parsing error.
+ *
+ * @param args Array of the raw command-line arguments.
+ *
+ * @throws BadOption If an option has invalid value.
+ *
+ * @see #getRawArguments()
+ * @see #getArguments()
+ */
+ public void setRawArguments(String args[]) {
+ this.rawArguments = (String[]) args.clone();
+ parseArguments();
+ }
+
+ /**
+ * Add or replace given option value in options list and in raw arguments list.
+ * Use specified <code>rawPrefix</code> while adding to raw arguments list.
+ *
+ * @see #getRawArguments()
+ * @see #getOptions()
+ */
+ public void setOption(String rawPrefix, String name, String value) {
+ String prefix = rawPrefix + name + "=";
+ String arg = prefix + value;
+
+ options.setProperty(name, value);
+
+ int length = rawArguments.length;
+ boolean found = false;
+ for (int i = 0; i < length; i++) {
+ if (rawArguments[i].startsWith(prefix)) {
+ found = true;
+ rawArguments[i] = arg;
+ break;
+ }
+ }
+
+ if (!found) {
+ String[] newRawArguments = new String[length + 1];
+ for (int i = 0; i < length; i++) {
+ newRawArguments[i] = rawArguments[i];
+ }
+ newRawArguments[length] = arg;
+ rawArguments = newRawArguments;
+ }
+ }
+
+ /**
+ * Return current architecture name from ArgumentParser's
+ * options.
+ *
+ * <p>Note that null string is returning if test argument
+ * <code>-arch</code> has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String getArch() {
+ return options.getProperty("arch");
+ }
+
+ /**
+ * Timeout (in minutes) for test's critical section like:
+ * (a) awaiting for an event, or conversly (b) making sure
+ * that there is no unexpected event.
+ *
+ * <p>By default, <i>2</i> minutes is returned if option
+ * <code>-waittime</code> is not set with command line.
+ *
+ * @see TimeoutHandler
+ */
+ public int getWaitTime() {
+ String val = options.getProperty("waittime", "2");
+ int minutes;
+ try {
+ minutes = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not integer value of \"waittime\" argument: " + val);
+ }
+ return minutes;
+ }
+
+ /**
+ * Return boolean value of current Log mode:
+ * <ul>
+ * <li><i>true</i> if Log mode is verbose.
+ * <li><i>false</i> otherwise.
+ *
+ * <p>Note that default Log mode is quiet if test argument
+ * <code>-verbose</code> has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean verbose() {
+ return options.getProperty("verbose") != null;
+ }
+
+ /**
+ * Return boolean value of setting of timestamp for log messages:
+ * <ul>
+ * <li><i>true</i> if Log messages are timestamp'ed.
+ * <li><i>false</i> otherwise.
+ *
+ * <p>Note that by default Log messages won't be timestamp'ed until
+ * <code>-trace.time</code> has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean isTimestamp() {
+ return options.getProperty("trace.time") != null;
+ }
+
+ /**
+ * Return level of printing tracing mesages for debugging purpose.
+ * Level <i>0</i> means no tracing messages at all.
+ *
+ * <p>Note that by default no tracing messages will be printed out
+ * until <code>-trace.level</code> has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public int getTraceLevel() {
+ String value = options.getProperty("trace.level", Integer.toString(Log.TraceLevel.DEFAULT));
+ try {
+ int level = Integer.parseInt(value);
+ return level;
+ } catch (NumberFormatException e) {
+ throw new Failure("Not integer value of -trace.level option: " + value);
+ }
+ }
+
+ /**
+ * Parse arguments from rawArgumnets, extact recognized options,
+ * check legality of options values options and store non-option
+ * arguments.
+ *
+ * @throws NullPointerException If raw arguments were not set
+ * for this ArgumentParser instance.
+ * @throws BadOption If Option name is not accepted or
+ * option has illegal value.
+ *
+ * @see #setRawArguments(String[])
+ * @see #checkOption(String, String)
+ * @see #checkOptions()
+ */
+ protected void parseArguments() {
+ String selected[] = new String [rawArguments.length];
+ Properties properties = new Properties();
+ int count = 0;
+ for (int i=0; i<rawArguments.length; i++) {
+ String argument = rawArguments[i];
+ if (argument.startsWith("-")) {
+ int pos = argument.indexOf("=", 1);
+ String option, value;
+ if (pos < 0) {
+ option = argument.substring(1);
+ if (i + 1 < rawArguments.length && !rawArguments[i + 1].startsWith("-")) {
+ value = rawArguments[i + 1];
+ ++i;
+ } else
+ value = "";
+ } else {
+ option = argument.substring(1, pos);
+ value = argument.substring(pos + 1);
+ }
+ if (!checkOption(option, value)) {
+ throw new BadOption("Unrecognized command line option: " + argument);
+ }
+ properties.setProperty(option, value);
+ } else {
+ selected[count++] = rawArguments[i];
+ }
+ }
+ // Strip away the dummy tail of the selected[] array:
+ arguments = new String [count];
+ System.arraycopy(selected,0,arguments,0,count);
+ options = properties;
+ checkOptions();
+ }
+
+ public StressOptions getStressOptions() {
+ return new StressOptions(rawArguments);
+ }
+
+ /**
+ * Check if the specified option is allowed and has legal value.
+ * <p>
+ * Derived classes for hadling test arguments in particular sub-suites
+ * override this method to allow to accept sub-suite specific options.
+ * However, they should invoke this method of the base class to enshure
+ * that the basic options will be accepted too.
+ *
+ * @return <i>true</i> if option is allowed and has legel value
+ * <i>false</I> if option is unknown
+ *
+ * @throws BadOption If value of the allowed option is illegal.
+ *
+ * @see #setRawArguments(String[])
+ * @see #parseArguments()
+ */
+ protected boolean checkOption(String option, String value) {
+
+ // accept arguments of nsk.share.test.StressOptions
+ if (StressOptions.isValidStressOption(option))
+ return true;
+
+ // options with any string value
+ if (option.equals("arch")) {
+ return true;
+ }
+
+ // options with positive integer value
+ if (option.equals("waittime")
+ || option.equals("trace.level")) {
+ try {
+ int number = Integer.parseInt(value);
+ if (number < 0) {
+ throw new BadOption(option + ": value must be a positive integer");
+ }
+ } catch (NumberFormatException e) {
+ throw new BadOption(option + ": value must be an integer");
+ }
+ return true;
+ }
+
+ // options without any value
+ if (option.equals("verbose")
+ || option.equals("vbs")
+ || option.equals("trace.time")) {
+ if (!(value == null || value.length() <= 0)) {
+ throw new BadOption(option + ": no value must be specified");
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check that the value of all options are not inconsistent.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @throws BadOption If value of the options are inconsistent
+ *
+ * @see #parseArguments()
+ */
+ protected void checkOptions() {
+ // do nothing
+ }
+
+ /**
+ * Thrown if invalid option or option value is found.
+ */
+ public static class BadOption extends IllegalArgumentException {
+ /**
+ * Explain the reason.
+ *
+ * @param message Printing message.
+ */
+ public BadOption(String message) {
+ super(message);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassFileFinder.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.File;
+import java.nio.file.Paths;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.util.Arrays;
+
+public class ClassFileFinder {
+ private ClassFileFinder() { }
+ /**
+ * Searches for a classfile for the specified class in the specified
+ * classpath.
+ *
+ * @param name a classname
+ * @param classPath @{link File.pathSeparator} separated directories
+ * @return an absolute path to the found classfile, or null if it cannot be
+ * found
+ */
+ public static Path findClassFile(String name, String classPath) {
+ return Arrays.stream(classPath.split(File.pathSeparator))
+ .map(java.nio.file.Paths::get)
+ .map(p -> p.resolve(name.replace('.', File.separatorChar) + ".class"))
+ .filter(p -> java.nio.file.Files.exists(p))
+ .map(Path::toAbsolutePath)
+ .findAny()
+ .orElse(null);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ */
+
+/*
+ * Warning! Using this component need VM option -XX:-UseGCOverheadLimit
+ *
+ */
+
+package nsk.share;
+
+import java.util.*;
+import nsk.share.gc.gp.*;
+import nsk.share.test.ExecutionController;
+import nsk.share.test.Stresser;
+
+/**
+ * The <code>ClassUnloader</code> class allows to force VM to unload class(es)
+ * using memory stressing technique.
+ *
+ * <p>The method <code>unloadClass()</code> is provided which eats memory
+ * to enforce GC to cleanup the heap. So, if all references to a class
+ * and its loader are canceled, this may result in unloading the class.
+ *
+ * <p>ClassUnloader mainly intends to unload a class which was loaded
+ * with especial <code>ClassUnloader.loadClass()</code> method.
+ * A class is considered unloaded if its class loader is finalized.
+ * If there no finalization of class loader detected for some timeout,
+ * class is considered still loaded and method returns <i>false</i>.
+ *
+ * <p>Such finalization control applies only to a class loaded by
+ * ClassUnloader's <code>loadClass()</code> method. Otherwise, if there
+ * was no such class loaded, <code>unloadClass()</code> doesn't wait
+ * for a timeout and always returns <i>false</i>.
+ *
+ * <p>By default internal class loader of <code>CustomClassLoader</code> class
+ * is used for loading classes. This class loader can load class from .class file
+ * located in the specified directory.
+ * Application may define its own class loader, which may load classes using
+ * any other technique. Such class loader should be derived from base
+ * <code>CustomClassLoader</code> class, and set by <code>setClassLoader()</code>
+ * method.
+ *
+ * @see #setClassLoader(CustomClassLoader)
+ * @see #loadClass(String)
+ * @see #loadClass(String, String)
+ * @see #unloadClass()
+ */
+public class ClassUnloader {
+
+ /**
+ * Class name of default class loader.
+ */
+ public static final String INTERNAL_CLASS_LOADER_NAME = "nsk.share.CustomClassLoader";
+
+ /**
+ * Whole amount of time in milliseconds to wait for class loader finalization.
+ */
+ private static final int WAIT_TIMEOUT = 15000;
+
+ /**
+ * Piece of time in milliseconds to wait in a loop for class loader finalization.
+ */
+ private static final int WAIT_DELTA = 1000;
+
+ /**
+ * Has class loader been finalized or not.
+ */
+ volatile boolean finalized = false;
+
+ /**
+ * Current class loader used for loading classes.
+ */
+ private CustomClassLoader customClassLoader = null;
+
+ /**
+ * List of classes loaded with current class loader.
+ */
+ private Vector<Class<?>> classObjects = new Vector<Class<?>>();
+
+ /**
+ * Class object of the first class been loaded with current class loader.
+ * To get the rest loaded classes use <code>getLoadedClass(int)</code>.
+ * The call <code>getLoadedClass()</code> is effectively equivalent to the call
+ * <code>getLoadedClass(0)</code>
+ *
+ * @return class object of the first loaded class.
+ *
+ * @see #getLoadedClass(int)
+ */
+ public Class<?> getLoadedClass() {
+ return classObjects.get(0);
+ }
+
+ /**
+ * Returns class objects at the specified index in the list of classes loaded
+ * with current class loader.
+ *
+ * @return class objects at the specified index.
+ */
+ public Class<?> getLoadedClass(int index) {
+ return classObjects.get(index);
+ }
+
+ /**
+ * Creates new instance of <code>CustomClassLoader</code> class as the current
+ * class loader and clears the list of loaded classes.
+ *
+ * @return created instance of <code>CustomClassLoader</code> class.
+ *
+ * @see #getClassLoader()
+ * @see #setClassLoader(CustomClassLoader)
+ */
+ public CustomClassLoader createClassLoader() {
+ customClassLoader = new CustomClassLoader(this);
+ classObjects.removeAllElements();
+
+ return customClassLoader;
+ }
+
+ /**
+ * Sets new current class loader and clears the list of loaded classes.
+ *
+ * @see #getClassLoader()
+ * @see #createClassLoader()
+ */
+ public void setClassLoader(CustomClassLoader customClassLoader) {
+ this.customClassLoader = customClassLoader;
+ classObjects.removeAllElements();
+ customClassLoader.setClassUnloader(this);
+ }
+
+ /**
+ * Returns current class loader or <i>null</i> if not yet created or set.
+ *
+ * @return class loader object or null.
+ *
+ * @see #createClassLoader()
+ * @see #setClassLoader(CustomClassLoader)
+ */
+ public CustomClassLoader getClassLoader() {
+ return customClassLoader;
+ }
+
+ /**
+ * Loads class for specified class name using current class loader.
+ *
+ * <p>Current class loader should be set and capable to load class using only
+ * given class name. No other information such a location of .class files
+ * is passed to class loader.
+ *
+ * @param className name of class to load
+ *
+ * @throws ClassNotFoundException if no bytecode found for specified class name
+ * @throws Failure if current class loader is not specified;
+ * or if class was actually loaded with different class loader
+ *
+ * @see #loadClass(String, String)
+ */
+ public void loadClass(String className) throws ClassNotFoundException {
+
+ if (customClassLoader == null) {
+ throw new Failure("No current class loader defined");
+ }
+
+ Class<?> cls = Class.forName(className, true, customClassLoader);
+
+ // ensure that class was loaded by current class loader
+ if (cls.getClassLoader() != customClassLoader) {
+ throw new Failure("Class was loaded by unexpected class loader: " + cls.getClassLoader());
+ }
+
+ classObjects.add(cls);
+ }
+
+ /**
+ * Loads class from .class file located into specified directory using
+ * current class loader.
+ *
+ * <p>If there is no current class loader, then default class loader
+ * is created using <code>createClassLoader()</code>. Parameter <i>classDir</i>
+ * is passed to class loader using <code>CustomClassLoader.setClassPath()</code>
+ * method before loading class.
+ *
+ * @param className name of class to load
+ * @param classDir path to .class file location
+ *
+ * @throws ClassNotFoundException if no .class file found
+ * for specified class name
+ * @throws Failure if class was actually loaded with different class loader
+ *
+ * @see #loadClass(String)
+ * @see CustomClassLoader#setClassPath(String)
+ */
+ public void loadClass(String className, String classDir) throws ClassNotFoundException {
+
+ if (customClassLoader == null) {
+ createClassLoader();
+ }
+
+ customClassLoader.setClassPath(classDir);
+ loadClass(className);
+ }
+
+ /**
+ * Forces GC to unload previously loaded classes by cleaning all references
+ * to class loader with its loaded classes and eating memory.
+ *
+ * @return <i>true</i> if classes unloading has been detected
+ or <i>false</i> otherwise
+ *
+ * @throws Failure if exception other than OutOfMemoryError
+ * is thrown while eating memory
+ *
+ * @see #eatMemory()
+ */
+ public boolean unloadClass(ExecutionController stresser) {
+
+ finalized = false;
+
+ // free references to class and class loader to be able for collecting by GC
+ long waitTimeout = (customClassLoader == null) ? 0 : WAIT_TIMEOUT;
+ classObjects.removeAllElements();
+ customClassLoader = null;
+
+ // force class unloading by eating memory pool
+ eatMemory(stresser);
+
+ // give GC chance to run and wait for finalization
+ long timeToFinish = System.currentTimeMillis() + waitTimeout;
+ while (!finalized && System.currentTimeMillis() < timeToFinish) {
+ if (!stresser.continueExecution()) {
+ return false;
+ }
+ try {
+ // suspend thread for a while
+ Thread.sleep(WAIT_DELTA);
+ } catch (InterruptedException e) {
+ throw new Failure("Unexpected InterruptedException while class unloading: " + e);
+ }
+ }
+
+ // force GC to unload marked class loader and its classes
+ if (finalized) {
+ Runtime.getRuntime().gc();
+ return true;
+ }
+
+ // class loader has not been finalized
+ return false;
+ }
+
+ public boolean unloadClass() {
+ Stresser stresser = new Stresser() {
+
+ @Override
+ public boolean continueExecution() {
+ return true;
+ }
+
+ };
+ return unloadClass(stresser);
+ }
+
+ /**
+ * Stresses memory by allocating arrays of bytes.
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * @throws Failure if exception other than OutOfMemoryError
+ * is thrown while eating memory
+ */
+ public static void eatMemory(ExecutionController stresser) {
+ GarbageUtils.eatMemory(stresser, 50, 1024, 2);
+
+ /*
+ * System.runFinalization() may potentially fail with OOM. This is why
+ * System.runFinalization() is repeated several times.
+ */
+ for (int i = 0; i < 10; ++i) {
+ try {
+ if(!stresser.continueExecution()) {
+ return;
+ }
+ System.runFinalization();
+ break;
+ } catch (OutOfMemoryError e) {
+ }
+ }
+ }
+
+ /**
+ * Stresses memory by allocating arrays of bytes.
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * @throws Failure if exception other than OutOfMemoryError
+ * is thrown while eating memory
+ */
+ public static void eatMemory() {
+ Stresser stresser = new Stresser() {
+
+ @Override
+ public boolean continueExecution() {
+ return true;
+ }
+
+ };
+ GarbageUtils.eatMemory(stresser, 50, 1024, 2);
+ /*
+ * System.runFinalization() may potentially fail with OOM. This is why
+ * System.runFinalization() is repeated several times.
+ */
+ for (int i = 0; i < 10; ++i) {
+ try {
+ if(!stresser.continueExecution()) {
+ return;
+ }
+ System.runFinalization();
+ break;
+ } catch (OutOfMemoryError e) {
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Consts.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * This class defines constants
+ *
+ */
+public class Consts {
+
+ /**
+ * Exit code when test passed
+ */
+ public final static int TEST_PASSED = 0;
+
+ /**
+ * Exit code when test failed
+ */
+ public final static int TEST_FAILED = 2;
+
+ /**
+ * Shift of exit code
+ */
+ public final static int JCK_STATUS_BASE = 95;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/CustomClassLoader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.*;
+
+/**
+ * The <code>CustomClassLoader</code> class is used in <code>ClassUnloader</code>.
+ *
+ * <p>This class loader can load classes and notify <code>ClassUnloader</code>
+ * about own finalization to make sure that all loaded classes have been unloaded.
+ *
+ * <p>By default this class loader loads class from .class file located in directory
+ * specified with <code>setClassPath()</code> method. To use any other technique
+ * of class loading one should implement derived class, which would override
+ * <code>findClass</code> method.
+ *
+ * @see nsk.share.ClassUnloader
+ *
+ * @see #setClassPath(String)
+ * @see #findClass(String)
+ */
+public class CustomClassLoader extends ClassLoader {
+
+ private ClassUnloader classUnloader;
+ protected String classPath;
+
+ /**
+ * Initializes a newly created <code>CustomClassloader</code> object
+ * not yet linked with any <code>ClassUnloader</code> object.
+ *
+ */
+ public CustomClassLoader() {
+ super(CustomClassLoader.class.getClassLoader());
+ this.classUnloader = null;
+ }
+
+ /**
+ * Initializes a newly created <code>CustomClassloader</code> object
+ * linked with specified <code>ClassUnloader</code> object.
+ *
+ * @param classUnloader an instance of <code>ClassUnloader</code>
+ */
+ public CustomClassLoader(ClassUnloader classUnloader) {
+ super(CustomClassLoader.class.getClassLoader());
+ this.classUnloader = classUnloader;
+ }
+
+ /**
+ * Links this class loader with specified <code>ClassUnloader</code> object.
+ *
+ * @param classUnloader an instance of <code>ClassUnloader</code>
+ */
+ public void setClassUnloader(ClassUnloader classUnloader) {
+ this.classUnloader = classUnloader;
+ }
+
+ /**
+ * Specifies path to .class file location.
+ *
+ * @param classPath a path to .class file location
+ */
+ public void setClassPath(String classPath) {
+ this.classPath = classPath;
+ }
+
+ /**
+ * Finds and loads class for specified class name.
+ * This method loads class from .class file located in a directory
+ * previously specified by <code>setClassPath()</code>.
+ *
+ * @param name The name of the class.
+ *
+ * @throws ClassNotFoundException if no .class file found
+ * for specified class name
+ *
+ * @see #setClassPath(String)
+ */
+ protected synchronized Class findClass(String name) throws ClassNotFoundException {
+ java.nio.file.Path path = ClassFileFinder.findClassFile(name, classPath);
+ if (path == null) {
+ throw new ClassNotFoundException(name);
+ }
+ String classFileName = path.toString();
+
+ FileInputStream in;
+ try {
+ in = new FileInputStream(classFileName);
+ if (in == null) {
+ throw new ClassNotFoundException(classFileName);
+ }
+ } catch (FileNotFoundException e) {
+ throw new ClassNotFoundException(classFileName, e);
+ }
+
+ int len;
+ byte data[];
+ try {
+ len = in.available();
+ data = new byte[len];
+ for (int total = 0; total < data.length; ) {
+ total += in.read(data, total, data.length - total);
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(classFileName, e);
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ throw new ClassNotFoundException(classFileName, e);
+ }
+ }
+
+ return defineClass(name, data, 0, data.length);
+ }
+
+ /**
+ * Notifies <code>ClassUnloader</code> about finalization.
+ */
+ protected void finalize() throws Throwable {
+
+ // notify ClassUnloader about finalization
+ if (classUnloader != null) {
+ classUnloader.finalized = true;
+ }
+
+ super.finalize();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Debug.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class Debug
+{
+ // tests assertion to be valid, otherwise FAIL test with message
+ static public void Assert(boolean condition, String message)
+ {
+ if (!condition)
+ Debug.Fail(message);
+ }
+
+ // print message and FAIL test
+ static public void Fail(String message)
+ {
+ System.out.println(message);
+ System.exit(100);
+ }
+
+ static public void Fail(Throwable e)
+ {
+ Fail(e.toString());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Denotation.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.*;
+
+/**
+ * Denotation implies a pair of algorithms for naming and
+ * indexing of some objects.
+ *
+ * <p>No matter what kind of objects, just make sure that:
+ * <ul>
+ * <li><tt>indexFor(nameFor(index))</tt> equals to <tt>index</tt>
+ * </li>
+ * <li><tt>nameFor(indexFor(name))</tt> is equivalent to <tt>name</tt>
+ * </li>
+ * </ul>
+ *
+ * <p>The notions of indeces equality and names equivalence
+ * are formalized by the methods <tt>equality()</tt> and
+ * <tt>equivalence()</tt> correspondingly.
+ *
+ * <p>For better understanding of Denotation, you may want to
+ * see the TreeNodesDenotation class as an implementation example.
+ *
+ * @see #equality(int[],int[])
+ * @see #equivalence(String,String)
+ * @see TreeNodesDenotation
+ */
+abstract public class Denotation {
+ /**
+ * Check if the <tt>name</tt> is legal, and return the
+ * numeric index for that object denoted by the given
+ * <tt>name</tt>.
+ *
+ * @throws IllegalArgumentException If the <tt>name</tt>
+ * is illegal.
+ */
+ abstract public int[] indexFor(String name);
+
+ /**
+ * Check if the <tt>index[]</tt> is legal, and return
+ * a symbolic name for the object denoted by the given
+ * <tt>index[]</tt>.
+ *
+ * @throws IllegalArgumentException If the <tt>index[]</tt>
+ * is illegal.
+ */
+ abstract public String nameFor(int[] index);
+
+ /**
+ * Re-call to <tt>nameFor(int[])</tt> with the 1-element
+ * array <tt>{i}</tt> as the <tt>index</tt> argument.
+ *
+ * @see #nameFor(int[])
+ */
+ public String nameFor(int i) {
+ return nameFor(new int[] { i });
+ }
+
+ /**
+ * Re-call to <tt>nameFor(int[])</tt> with the 2-elements
+ * array <tt>{i0,i1}</tt> as the <tt>index</tt> argument.
+ *
+ * @see #nameFor(int[])
+ */
+ public String nameFor(int i0, int i1) {
+ return nameFor(new int[] {i0, i1});
+ }
+
+ /**
+ * Re-call to <tt>nameFor(int[])</tt> with the 3-elements
+ * array <tt>{i0,i1,i2}</tt> as the <tt>index</tt> argument.
+ *
+ * @see #nameFor(int[])
+ */
+ public String nameFor(int i0, int i1, int i2) {
+ return nameFor(new int[] {i0, i1, i2});
+ }
+
+ /**
+ * Indeces equality means equality of objects they denote.
+ *
+ * <p>Indeces <tt>index1[]</tt> and <tt>index2[]</tt> are
+ * equal, if they are equal as <tt>int[]</tt> arrays. But,
+ * there is no index equal to <tt>null</tt>; particularly,
+ * <tt>null</tt> is not equal to itself.
+ *
+ * @see Arrays#equals(int[],int[])
+ */
+ public boolean equality(int[] index1, int[] index2) {
+ if (index1 == null || index2 == null)
+ return false;
+ return Arrays.equals(index1,index2);
+ }
+
+ /**
+ * Names equivalence means equality of objects they denote.
+ *
+ * <p>Strings <tt>name1</tt> and <tt>name2</tt> are equivalent,
+ * if correspondent indeces are equal. There is no <tt>name</tt>
+ * equivalent to <tt>null</tt>; particularly, <tt>null</tt> is
+ * not equivalent to itself.
+ *
+ * @see #equality(int[],int[])
+ */
+ public boolean equivalence(String name1, String name2) {
+ if (name1 == null || name2 == null)
+ return false;
+ return equality(indexFor(name1),indexFor(name2));
+ }
+
+ /**
+ * Dummy constructor.
+ */
+ protected Denotation() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/DummyClassLoader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * This loader's <tt>findClass()</tt> method is dummy.
+ */
+public class DummyClassLoader extends ClassLoader {
+ /**
+ * Cannot instantiate w/o a parent loader.
+ */
+ protected DummyClassLoader() {
+ }
+
+ /**
+ * Delegate everything to the <tt>parent</tt> loader.
+ */
+ public DummyClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Do nothing: parent loader must load everything.
+ *
+ * @throws ClassNotFoundException In any case.
+ */
+ public Class findClass(String name) throws ClassNotFoundException {
+ throw new ClassNotFoundException(name);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Failure.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.*;
+
+/**
+ * Thrown to indicate failure caused by some occasional reason,
+ * which does not indicate a problem in the JVM being tested.
+ */
+public class Failure extends RuntimeException {
+ /** Enwrap another throwable. */
+ public Failure(Throwable throwable) {
+ super(throwable);
+ }
+
+ /** Explain particular failure. */
+ public Failure(String message) {
+ super(message);
+ }
+
+ public Failure(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/FileUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+
+public class FileUtils {
+ private FileUtils() {
+ }
+
+ /**
+ * Read whole file.
+ *
+ * @param file file
+ * @return contents of file as byte array
+ */
+ public static byte[] readFile(File file) throws IOException {
+ InputStream in = new FileInputStream(file);
+ long countl = file.length();
+ if (countl > Integer.MAX_VALUE)
+ throw new IOException("File is too huge");
+ int count = (int) countl;
+ byte[] buffer = new byte[count];
+ int n = 0;
+ try {
+ while (n < count) {
+ int k = in.read(buffer, n, count - n);
+ if (k < 0)
+ throw new IOException("Unexpected EOF");
+ n += k;
+ }
+ } finally {
+ in.close();
+ }
+ return buffer;
+ }
+
+ /**
+ * Read whole file.
+ *
+ * @param name file name
+ * @return contents of file as byte array
+ */
+ public static byte[] readFile(String name) throws IOException {
+ return readFile(new File(name));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizable.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * Finalizable interface allows <tt>Finalizer</tt> to perform finalization of an object.
+ * Each object that requires finalization at VM shutdown time should implement this
+ * interface and activate a <tt>Finalizer</tt> hook.
+ *
+ * @see Finalizer
+ */
+public interface Finalizable {
+
+ /**
+ * This method will be invoked by <tt>Finalizer</tt> when virtual mashine
+ * shuts down.
+ *
+ * @throws Throwable if any throwable exception thrown during finalization
+ */
+ public void finalizeAtExit() throws Throwable;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/FinalizableObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * This class is an simple exalmple of finalizable object, that implements interface
+ * <code>Finalizable</code> and invokes standard <code>finalize()</code> method
+ * as finalization.
+ *
+ * @see Finalizable
+ * @see Finalizer
+ */
+public class FinalizableObject implements Finalizable {
+
+ /**
+ * This method will be invoked by <tt>Finalizer</tt> when virtual mashine
+ * shuts down.
+ * For <code>FinalizableObject</code> this method just invoke
+ * <code>finalize()</code>.
+ *
+ * @throws Throwable if any throwable exception thrown during finalization
+ *
+ * @see Object#finalize()
+ * @see Finalizer
+ */
+ public void finalizeAtExit() throws Throwable {
+ finalize();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Finalizer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.Stack;
+
+/**
+ * Finalizer performs object finalization when virtual mashine shuts down.
+ * Finalizer is a thread that acts as a VM shutdown hook.
+ * This thread will be activated as VM shuts down because of
+ * invocation of <code>exit()</code> or termination. After activation
+ * Finalizer just calls <code>finalizeAtExit()</code> method of the specified object.
+ * The finalizable object should implement interface <code>Finalizable</code>.
+ *
+ * @see Finalizable
+ */
+public class Finalizer {
+
+ /** Finalizer thread to register as a VM shutdown hook. */
+ private static FinalizerThread finalizerThread = null;
+
+ /** An object to finalize. */
+ private Finalizable object;
+
+ /**
+ * Create finalizer for the specified object.
+ */
+ public Finalizer(Finalizable object) {
+ this.object = object;
+ }
+
+ /**
+ * Register finalizer for finalization at VM shutdown.
+ */
+ public void activate() {
+ if (finalizerThread == null) {
+ finalizerThread = new FinalizerThread("FinalizerThread for Finalizable objects");
+ finalizerThread.activate();
+ }
+ finalizerThread.add(object);
+ }
+
+ /**
+ * Unregister finalizer for finalization at VM shutdown.
+ */
+ public void deactivate() {
+ if (finalizerThread == null)
+ return;
+ finalizerThread.remove(object);
+ }
+
+ /**
+ * Static inner thread that is registered as a VM shutdown hook
+ * and performs finalization of all registered finalizable objects.
+ */
+ private static class FinalizerThread extends Thread {
+
+ /** Stack of objects registered for finalization. */
+ private Stack<Object> objects = new Stack<Object>();
+
+ /** Make new instance of FinalizerThread with given thread name. */
+ public FinalizerThread(String threadName) {
+ super(threadName);
+ }
+
+ /**
+ * Push an object to the stack of registered objects.
+ */
+ public void add(Finalizable object) {
+ objects.push(object);
+ }
+
+ /**
+ * Remove an object from the stack of registered objects.
+ */
+ public void remove(Finalizable object) {
+ objects.remove(object);
+ }
+
+ /**
+ * Register finalizer thread as a VM shutdown hook.
+ */
+ public void activate() {
+ Runtime.getRuntime().addShutdownHook( this );
+ }
+
+ /**
+ * Unregister finalizer thread as a VM shutdown hook.
+ */
+ public void deactivate() {
+ Runtime.getRuntime().removeShutdownHook( this );
+ }
+
+ /**
+ * Pop all registered objects from the stack and finalize them.
+ */
+ public void run() {
+ while (!objects.empty()) {
+ Finalizable object = (Finalizable)objects.pop();
+ try {
+ object.finalizeAtExit();
+ } catch (ThreadDeath e) {
+ throw e;
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ } // end of FinalizerThread
+
+} // end of Finalizer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/GoldChecker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+import java.io.*;
+
+public class GoldChecker extends AbstractGoldChecker
+{
+ private final String goldOutput;
+
+ public GoldChecker(String main_class_name) {
+ goldOutput = readGoldStr(main_class_name + ".gold");
+ }
+
+ @Override
+ protected String getGoldenString() {
+ return goldOutput;
+ }
+
+ private String readGoldStr(String gold_file_name) {
+ RandomAccessFile f;
+
+ try {
+ f = new RandomAccessFile(gold_file_name, "r");
+ } catch (FileNotFoundException e) {
+ throw new TestBug("Unable to open golden file '" + gold_file_name + "' for reading");
+ }
+
+ byte[] data;
+
+ try {
+ int len = (int)f.length();
+ data = new byte[len];
+ f.read(data);
+ } catch (IOException e) {
+ throw new TestBug("Error reading from golden file'" + gold_file_name + "'");
+ }
+
+ try {
+ f.close();
+ } catch (IOException e) {
+ }
+
+ try {
+ return new String(data, "US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new TestFailure( e );
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Grep.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * Emulator of perl's grep function.
+ * This class uses java.util.regexp classes which appear in
+ * JDK1.4 API. This implies the restriction for this class
+ * to not be used with the tests against JDKs prior to 1.4.
+ *
+ * @see java.util.regex.Pattern
+ * @see java.util.regex.Matcher
+ */
+
+public class Grep {
+
+ String[] stringArray;
+ /**
+ * Takes String array as character sequence for matching the pattern.
+ */
+ public Grep (String[] stringArray) {
+ this.stringArray = stringArray;
+ }
+
+ /**
+ * Returns number of non-interleaved occurences of groups which match the pattern.
+ */
+ public int find (String regExpPattern) {
+ if (regExpPattern.length() == 0) {
+ throw new Failure("Empty string as input parameter for Grep.find(regExpPattern) method");
+ }
+ Pattern pattern = Pattern.compile(regExpPattern);
+ int counter = 0;
+ for (int i = 0; i < stringArray.length; i++) {
+
+ String string = stringArray[i];
+ if (string != null) {
+ // Create matcher for this string
+ Matcher matcher = pattern.matcher(string);
+
+ // Find all non-interleaved occurences of pattern in this string
+ for (int ind = 0; ind < string.length(); ) {
+ if (matcher.find(ind)) {
+ counter++;
+ ind = matcher.end();
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return counter;
+ }
+
+ /**
+ * Returns first string of stringArray with group which matches
+ * the pattern or empty string othrewise.
+ */
+ public String findFirst (String regExpPattern) {
+ if (regExpPattern.length() == 0) {
+ throw new Failure("Empty string as input parameter for Grep.findFirst(regExpPattern) method");
+ }
+ Pattern pattern = Pattern.compile(regExpPattern);
+ String result = "";
+ for (int i = 0; i < stringArray.length; i++) {
+
+ String string = stringArray[i];
+ if (string != null) {
+ // Create matcher for this string
+ Matcher matcher = pattern.matcher(string);
+ if (matcher.find()) {
+ result = string;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Harakiri.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * Harakiri is used to terminate a stress test with PASS exit status
+ * before the test is terminated as timed out (and so failed).
+ *
+ * <p>Harakiri class holds a thread which sleeps for the given amount
+ * of time, and then wakes up and executes <tt>System.exit()</tt>
+ * with the given exit status. That thread is daemon, so it doesn't
+ * prevent application from exiting once all its threads finish
+ * before it's time for harakiri. Appointing harakiri in zero
+ * delay implies immediate <tt>exit()</tt>.
+ *
+ * <p>There is a limitation: you may appoint no more than one harakiri
+ * per application.
+ */
+public class Harakiri {
+ /**
+ * Use specific <tt>appoint()</tt> method to appoint harakiri.
+ *
+ * @see #appoint(int)
+ * @see #appoint(int,int)
+ */
+ protected Harakiri() {}
+
+ /**
+ * One harakiri per application, or <tt>null</tt> (by default).
+ */
+ private static Thread harakiri = null;
+
+ /**
+ * <p>Return timeout (or waittime) value munus the margin
+ * value (which is assumed 1 minute by default).
+ *
+ * <p>Treat <tt>args[0]</tt> as <tt>$TIMEOUT</tt> value, or seek for
+ * <tt>-waittime=$WAITTIME</tt> value. If both parameters
+ * (or either none of them) are assigned, throw an exception to
+ * report parameters inconsistency.
+ *
+ * <p>Also, seek for <tt>-margin=...</tt> assignment, or assume margin
+ * is 1 minute.
+ *
+ * @param args Is usually obtained via the application's command-line.
+ *
+ * @throws IllegalArgumentException If <tt>args[]</tt> is inconsistent.
+ *
+ * @see #appoint(int)
+ * @see #appoint(int,int)
+ */
+ public static int parseAppointment(String args[]) {
+ int timeout=-1, margin=1;
+ int timeouts=0, waittimes=0, margins=0;
+ for (int i=0; i<args.length; i++) {
+ if (args[i].startsWith("-")) {
+ if (args[i].startsWith("-waittime=")) {
+ timeout = Integer.parseInt(args[i].substring(10));
+ waittimes++;
+ }
+ if (args[i].startsWith("-margin=")) {
+ margin = Integer.parseInt(args[i].substring(8));
+ margins++;
+ }
+ } else {
+ if (i == 0) {
+ timeout = Integer.parseInt(args[i]);
+ timeouts++;
+ }
+ }
+ };
+ if (timeouts==0 && waittimes==0)
+ throw new IllegalArgumentException(
+ "no $TIMEOUT, nor -waittime=$WAITTIME is set");
+ if (waittimes > 1)
+ throw new IllegalArgumentException(
+ "more than one -waittime=... is set");
+ if (margins > 1)
+ throw new IllegalArgumentException(
+ "more than one -margin=... is set");
+
+ int result = timeout - margin;
+ if (result <= 0)
+ throw new IllegalArgumentException(
+ "delay appointment must be greater than "+margin+" minutes");
+ return result;
+ }
+
+ /**
+ * Appoint harakiri after the given amount of <tt>minutes</tt>,
+ * so that exit status would be 95 (to simulate JCK-like PASS
+ * status).
+ *
+ * @throws IllegalStateException If harakiri is already appointed.
+ *
+ * @see #appoint(int,int)
+ * @see #parseAppointment(String[])
+ */
+ public static void appoint(int minutes) {
+ appoint(minutes,95); // JCK-like PASS status
+ }
+
+ /**
+ * Appoint Harakiri for the given amount of <tt>minutes</tt>,
+ * so that the given <tt>status</tt> would be exited when time
+ * is over.
+ *
+ * @throws IllegalStateException If harakiri is already appointed.
+ *
+ * @see #appoint(int)
+ * @see #parseAppointment(String[])
+ */
+ public static void appoint(int minutes, int status) {
+ if (harakiri != null)
+ throw new IllegalStateException("Harakiri is already appointed.");
+
+ final long timeToExit = System.currentTimeMillis() + 60*1000L*minutes;
+ final int exitStatus = status;
+
+ harakiri = new Thread(Harakiri.class.getName()) {
+ public void run() {
+ long timeToSleep = timeToExit - System.currentTimeMillis();
+ if (timeToSleep > 0)
+ try {
+ //
+ // Use wait() instead of sleep(), because Java 2
+ // specification doesn't guarantee the method
+ // sleep() to yield to other threads.
+ //
+ Object someDummyObject = new Object();
+ synchronized (someDummyObject) {
+ someDummyObject.wait(timeToSleep);
+ }
+ } catch (InterruptedException exception) {
+ exception.printStackTrace(System.err);
+ //
+ // OOPS, the dagger for harakiri looks broken:
+ //
+ return;
+ };
+ //
+ // OK, lets do it now:
+ //
+ System.err.println(
+ "#\n# Harakiri: prescheduled program termination.\n#");
+ System.exit(exitStatus); // harakiri to all threads
+ }
+ };
+
+ harakiri.setPriority(Thread.MAX_PRIORITY);
+ harakiri.setDaemon(true);
+ harakiri.start();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/IORedirector.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.*;
+
+/**
+ * This class implements a thread transfering bytes from
+ * a given InputStream to a given OutputStream.
+ */
+public class IORedirector extends Thread {
+ private BufferedReader bin = null;
+ private PrintStream pout = null;
+ private Log log = null;
+
+ /**
+ * Few symbols to precede every text line being redirected.
+ */
+ private String prefix = "";
+
+ /**
+ * Input and output streams must be specified.
+ */
+ private IORedirector() {
+ super("IORedirector");
+ }
+
+ /**
+ * Redirect <code>in</code> to <code>out</code>.
+ *
+ * @deprecated Use newer constructor.
+ *
+ * @see #IORedirector(BufferedReader,Log,String)
+ */
+ public IORedirector(InputStream in, OutputStream out) {
+ this();
+ bin = new BufferedReader(new InputStreamReader(in));
+ pout = new PrintStream(out);
+ }
+
+ /**
+ * Redirect <code>in</code> to <code>log</code>; and assign
+ * few <code>prefix</code> symbols to precede each text line
+ * being redirected.
+ */
+ public IORedirector(BufferedReader in, Log log, String prefix) {
+ this();
+ this.prefix = prefix;
+ this.bin = in;
+ this.log = log;
+ }
+
+ /**
+ * Set the prefix for redirected messages;
+ */
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ private boolean cancelled = false;
+ private boolean stopped = false;
+ private boolean started = false;
+
+ /**
+ * Signal to <code>run()</code> method that it should terminate,
+ * and wait until it is finished.
+ */
+ public void cancel () {
+ cancelled = true;
+ while (this.isAlive())
+ try {
+ this.join();
+ } catch (InterruptedException ie) {
+ throw new Failure(ie);
+ };
+ // stopped==true here.
+ }
+
+ /**
+ * Pass data bytes from <code>in</code> to <code>out</code> stream
+ * until EOF is read, or this IORedirector is cancelled.
+ */
+ public void run () {
+ started = true;
+ String logPrefix = "IORedirector-" + prefix;
+ if (bin == null || (pout == null && log == null))
+ return;
+ try {
+ while (!cancelled) {
+ String line = bin.readLine();
+ if (line == null)
+ break; //EOF
+ String message = prefix + line;
+ if (log != null) {
+ // It's synchronized and auto-flushed:
+ log.println(message);
+ } else if (pout != null) {
+ synchronized (pout) {
+ pout.println(message);
+ pout.flush();
+ }
+ }
+ }
+ } catch (IOException e) {
+ // e.printStackTrace(log.getOutStream());
+ String msg = "# WARNING: Caught IOException while redirecting output stream:\n\t" + e;
+ if (log != null) {
+ log.println(msg);
+ } else if (pout != null) {
+ synchronized (pout) {
+ pout.println(msg);
+ pout.flush();
+ }
+ } else {
+ System.err.println(msg);
+ System.err.flush();
+ }
+ };
+ stopped = true;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ */
+
+#include "jvmdi.h"
+#include "JVMDITools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char const *TranslateEvent(jint kind) {
+ switch (kind) {
+ case JVMDI_EVENT_SINGLE_STEP:
+ return ("JVMDI_EVENT_SINGLE_STEP");
+ case JVMDI_EVENT_BREAKPOINT:
+ return ("JVMDI_EVENT_BREAKPOINT");
+ case JVMDI_EVENT_FRAME_POP:
+ return ("JVMDI_EVENT_FRAME_POP");
+ case JVMDI_EVENT_EXCEPTION:
+ return ("JVMDI_EVENT_EXCEPTION");
+ case JVMDI_EVENT_USER_DEFINED:
+ return ("JVMDI_EVENT_USER_DEFINED");
+ case JVMDI_EVENT_THREAD_START:
+ return ("JVMDI_EVENT_THREAD_START");
+ case JVMDI_EVENT_THREAD_END:
+ return ("JVMDI_EVENT_THREAD_END");
+ case JVMDI_EVENT_CLASS_PREPARE:
+ return ("JVMDI_EVENT_CLASS_PREPARE");
+ case JVMDI_EVENT_CLASS_UNLOAD:
+ return ("JVMDI_EVENT_CLASS_UNLOAD");
+ case JVMDI_EVENT_CLASS_LOAD:
+ return ("JVMDI_EVENT_CLASS_LOAD");
+ case JVMDI_EVENT_FIELD_ACCESS:
+ return ("JVMDI_EVENT_FIELD_ACCESS");
+ case JVMDI_EVENT_FIELD_MODIFICATION:
+ return ("JVMDI_EVENT_FIELD_MODIFICATION");
+ case JVMDI_EVENT_EXCEPTION_CATCH:
+ return ("JVMDI_EVENT_EXCEPTION_CATCH");
+ case JVMDI_EVENT_METHOD_ENTRY:
+ return ("JVMDI_EVENT_METHOD_ENTRY");
+ case JVMDI_EVENT_METHOD_EXIT:
+ return ("JVMDI_EVENT_METHOD_EXIT");
+ case JVMDI_EVENT_VM_INIT:
+ return ("JVMDI_EVENT_VM_INIT");
+ case JVMDI_EVENT_VM_DEATH:
+ return ("JVMDI_EVENT_VM_DEATH");
+ default:
+ return ("<Unknown Event>");
+ }
+}
+
+char const *TranslateError(jvmdiError err) {
+ switch (err) {
+ case JVMDI_ERROR_NONE:
+ return ("JVMDI_ERROR_NONE");
+ case JVMDI_ERROR_OUT_OF_MEMORY:
+ return ("JVMDI_ERROR_OUT_OF_MEMORY");
+ case JVMDI_ERROR_ACCESS_DENIED:
+ return ("JVMDI_ERROR_ACCESS_DENIED");
+ case JVMDI_ERROR_UNATTACHED_THREAD:
+ return ("JVMDI_ERROR_UNATTACHED_THREAD");
+ case JVMDI_ERROR_VM_DEAD:
+ return ("JVMDI_ERROR_VM_DEAD");
+ case JVMDI_ERROR_INTERNAL:
+ return ("JVMDI_ERROR_INTERNAL");
+ case JVMDI_ERROR_INVALID_THREAD:
+ return ("JVMDI_ERROR_INVALID_THREAD");
+ case JVMDI_ERROR_INVALID_FIELDID:
+ return ("JVMDI_ERROR_INVALID_FIELDID");
+ case JVMDI_ERROR_INVALID_METHODID:
+ return ("JVMDI_ERROR_INVALID_METHODID");
+ case JVMDI_ERROR_INVALID_LOCATION:
+ return ("JVMDI_ERROR_INVALID_LOCATION");
+ case JVMDI_ERROR_INVALID_FRAMEID:
+ return ("JVMDI_ERROR_INVALID_FRAMEID");
+ case JVMDI_ERROR_NO_MORE_FRAMES:
+ return ("JVMDI_ERROR_NO_MORE_FRAMES");
+ case JVMDI_ERROR_OPAQUE_FRAME:
+ return ("JVMDI_ERROR_OPAQUE_FRAME");
+ case JVMDI_ERROR_NOT_CURRENT_FRAME:
+ return ("JVMDI_ERROR_NOT_CURRENT_FRAME");
+ case JVMDI_ERROR_TYPE_MISMATCH:
+ return ("JVMDI_ERROR_TYPE_MISMATCH");
+ case JVMDI_ERROR_INVALID_SLOT:
+ return ("JVMDI_ERROR_INVALID_SLOT");
+ case JVMDI_ERROR_DUPLICATE:
+ return ("JVMDI_ERROR_DUPLICATE");
+ case JVMDI_ERROR_THREAD_NOT_SUSPENDED:
+ return ("JVMDI_ERROR_THREAD_NOT_SUSPENDED");
+ case JVMDI_ERROR_THREAD_SUSPENDED:
+ return ("JVMDI_ERROR_THREAD_SUSPENDED");
+ case JVMDI_ERROR_INVALID_OBJECT:
+ return ("JVMDI_ERROR_INVALID_OBJECT");
+ case JVMDI_ERROR_INVALID_CLASS:
+ return ("JVMDI_ERROR_INVALID_CLASS");
+ case JVMDI_ERROR_CLASS_NOT_PREPARED:
+ return ("JVMDI_ERROR_CLASS_NOT_PREPARED");
+ case JVMDI_ERROR_NULL_POINTER:
+ return ("JVMDI_ERROR_NULL_POINTER");
+ case JVMDI_ERROR_ABSENT_INFORMATION:
+ return ("JVMDI_ERROR_ABSENT_INFORMATION");
+ case JVMDI_ERROR_INVALID_EVENT_TYPE:
+ return ("JVMDI_ERROR_INVALID_EVENT_TYPE");
+ case JVMDI_ERROR_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_INVALID_THREAD_GROUP:
+ return ("JVMDI_ERROR_INVALID_THREAD_GROUP");
+ case JVMDI_ERROR_INVALID_PRIORITY:
+ return ("JVMDI_ERROR_INVALID_PRIORITY");
+ case JVMDI_ERROR_NOT_FOUND:
+ return ("JVMDI_ERROR_NOT_FOUND");
+ case JVMDI_ERROR_INVALID_MONITOR:
+ return ("JVMDI_ERROR_INVALID_MONITOR");
+ case JVMDI_ERROR_ILLEGAL_ARGUMENT:
+ return ("JVMDI_ERROR_ILLEGAL_ARGUMENT");
+ case JVMDI_ERROR_NOT_MONITOR_OWNER:
+ return ("JVMDI_ERROR_NOT_MONITOR_OWNER");
+ case JVMDI_ERROR_INTERRUPT:
+ return ("JVMDI_ERROR_INTERRUPT");
+ case JVMDI_ERROR_INVALID_TYPESTATE:
+ return ("JVMDI_ERROR_INVALID_TYPESTATE");
+ case JVMDI_ERROR_INVALID_CLASS_FORMAT:
+ return ("JVMDI_ERROR_INVALID_CLASS_FORMAT");
+ case JVMDI_ERROR_CIRCULAR_CLASS_DEFINITION:
+ return ("JVMDI_ERROR_CIRCULAR_CLASS_DEFINITION");
+ case JVMDI_ERROR_ADD_METHOD_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_ADD_METHOD_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_FAILS_VERIFICATION:
+ return ("JVMDI_ERROR_FAILS_VERIFICATION");
+#ifdef JVMDI_VERSION_1_2
+ case JVMDI_ERROR_UNSUPPORTED_VERSION:
+ return ("JVMDI_ERROR_UNSUPPORTED_VERSION");
+ case JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_NAMES_DONT_MATCH:
+ return ("JVMDI_ERROR_NAMES_DONT_MATCH");
+ case JVMDI_ERROR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED");
+ case JVMDI_ERROR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED:
+ return ("JVMDI_ERROR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED");
+#endif
+ default:
+ return ("<Unknown Error>");
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMDITools.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char const *TranslateEvent(jint kind);
+char const *TranslateError(jvmdiError err);
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1276 @@
+/*
+ * Copyright (c) 2004, 2018, 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.
+ */
+
+/*
+ *
+ * JVMTI agent used for run every test from the testbase in a special
+ * debug mode. This mode is intended to be part of serviceability
+ * reliability testing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <jvmti.h>
+
+#include "nsk_tools.h"
+#include "jni_tools.h"
+#include "JVMTITools.h"
+#include "jvmti_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static jvmtiEnv *jvmti = NULL; /* JVMTI env */
+static jvmtiEventCallbacks callbacks;
+static jrawMonitorID eventLock; /* raw monitor used for exclusive ownership of HotSwap function */
+
+static volatile int debug_mode = 0; /* 0 - verbose mode off;
+ 1 - verbose mode on;
+ 2 - verbose mode on including all JVMTI events reporting,
+ produces a huge number of messages */
+
+/* stress level */
+static volatile int stress_lev = 0; /* 0 - default mode: generation of all events except
+ ExceptionCatch,
+ MethodEntry/Exit, SingleStep;
+ 1 - generation of all events except
+ MethodEntry/Exit,
+ SingleStep;
+ 2 - generation of all events except
+ SingleStep;
+ 3 - generation of all events, including
+ ExceptionCatch,
+ MethodEntry/Exit,
+ SingleStep
+ */
+
+#define TRUE 1
+#define FALSE 0
+
+/**** the following is used for "postVM_DEATH" events watching ****/
+static volatile int vm_death_occured = FALSE;
+/************************************************/
+
+/**** the following is used for HotSwap mode ****/
+
+/* HotSwap modes:
+ HOTSWAP_OFF - default mode: HotSwap off;
+ HOTSWAP_EVERY_METHOD_ENTRY - HotSwap tested class in every method entry event
+ of running test
+ HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS - HotSwap tested class in every
+ method entry event of every class
+ HOTSWAP_EVERY_SINGLE_STEP - HotSwap tested class in every single step event
+ of running test
+ HOTSWAP_EVERY_EXCEPTION - HotSwap tested class in every exception event
+ of running test
+ HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS - HotSwap tested class in every
+ exception event of every class
+ */
+
+#define HOTSWAP_OFF 0
+#define HOTSWAP_EVERY_METHOD_ENTRY 2
+#define HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS 20
+#define HOTSWAP_EVERY_SINGLE_STEP 3
+#define HOTSWAP_EVERY_EXCEPTION 4
+#define HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS 40
+
+static int hotswap = HOTSWAP_OFF;
+
+typedef struct { /* test class info */
+ char *clazzsig; /* class signature */
+ jclass cls; /* a class to be redefined */
+ jint bCount; /* number of bytes defining the class */
+ jbyte *clsBytes; /* bytes defining the class */
+ struct class_info *next;
+} class_info;
+
+
+static const char *shortTestName = NULL; /* name of the test without package prefix */
+static jclass rasCls; /* reference to the auxiliary class RASagent used for HotSwap */
+static class_info *clsInfo = NULL, *clsInfoFst = NULL;
+
+static void lock(JNIEnv*);
+static void unlock(JNIEnv*);
+static jint allocClsInfo(JNIEnv*, char*, jclass);
+static void deallocClsInfo(JNIEnv*);
+static int findAndHotSwap(JNIEnv*, jclass);
+static int doHotSwap(JNIEnv*, jclass, jint, jbyte*);
+static void display(int, const char format[], ...);
+static void clearJavaException(JNIEnv*);
+static int enableEventsCaps();
+static int addStressEvents();
+static void getVerdict(JNIEnv*, const char *);
+/************************************************/
+
+/** callback functions **/
+void JNICALL
+Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, jmethodID method,
+ jlocation loc) {
+
+ display(1, "#### JVMTIagent: Breakpoint occurred ####\n");
+
+ getVerdict(jni_env, "Breakpoint");
+}
+
+void JNICALL
+ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jclass class_beeing_redefined,
+ jobject loader, const char* name, jobject protection_domain,
+ jint class_data_len, const unsigned char* class_data,
+ jint *new_class_data_len, unsigned char** new_class_data) {
+
+ display(1, "#### JVMTIagent: ClassFileLoadHook occurred ####\n");
+
+ getVerdict(jni_env, "ClassFileLoadHook");
+}
+
+void JNICALL
+ClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jclass klass) {
+ char *cls_sig;
+ jint clsByteCount;
+
+ display((hotswap != HOTSWAP_OFF)?0:1,
+ "#### JVMTIagent: ClassLoad occurred ####\n");
+
+ getVerdict(jni_env, "ClassLoad");
+
+ if (hotswap != HOTSWAP_OFF) {
+ /* enter into a raw monitor for exclusive work with redefined class */
+ lock(jni_env);
+ display(0, "#### JVMTIagent: ClassLoad: >>>>>>>> entered the raw monitor \"eventLock\" ####\n");
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
+ jvmti_env, klass, &cls_sig, /*&generic*/NULL)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get class signature\n");
+ else {
+ if (shortTestName != NULL) {
+ if (strstr((const char*) cls_sig, shortTestName) != NULL) {
+ display(0, "#### JVMTIagent: found test class matched with \"%s\"\n\
+<JVMTIagent>\tsignature=%s\n",
+ shortTestName, cls_sig);
+ clsByteCount = allocClsInfo(jni_env, cls_sig, klass);
+ display(0, "#### JVMTIagent: %d bytes defining the class have been successfully loaded\n",
+ clsByteCount);
+ }
+ }
+ }
+
+ /* exit from the raw monitor */
+ unlock(jni_env);
+ display(0, "#### JVMTIagent: ClassLoad: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n");
+ }
+}
+
+void JNICALL
+ClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jclass cls) {
+
+ display(1, "#### JVMTIagent: ClassPrepare occurred ####\n");
+
+ getVerdict(jni_env, "ClassPrepare");
+}
+
+void JNICALL
+CompiledMethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size,
+ const void* code_addr, jint map_length,
+ const jvmtiAddrLocationMap* map, const void* compile_info) {
+
+ display(1, "#### JVMTIagent: CompiledMethodLoad occurred ####\n");
+
+ getVerdict(NULL, "CompiledMethodLoad");
+}
+
+void JNICALL
+CompiledMethodUnload(jvmtiEnv *jvmti_env, jmethodID method,
+ const void* code_addr) {
+
+ display(1, "#### JVMTIagent: CompiledMethodUnload occurred ####\n");
+
+ getVerdict(NULL, "CompiledMethodUnload");
+}
+
+void JNICALL
+DataDumpRequest(jvmtiEnv *jvmti_env) {
+
+ display(1, "#### JVMTIagent: DataDumpRequest occurred ####\n");
+
+ getVerdict(NULL, "DataDumpRequest");
+}
+
+void JNICALL
+DynamicCodeGenerated(jvmtiEnv *jvmti_env,
+ const char* name,
+ const void* address,
+ jint length) {
+
+ display(1, "#### JVMTIagent: DynamicCodeGenerated occurred ####\n");
+
+ getVerdict(NULL, "DynamicCodeGenerated");
+}
+
+void JNICALL
+Exception(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr,
+ jmethodID method, jlocation location, jobject exception,
+ jmethodID catch_method, jlocation catch_location) {
+ jclass decl_clazz;
+
+ display((hotswap == HOTSWAP_EVERY_EXCEPTION ||
+ hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1,
+ "#### JVMTIagent: Exception occurred ####\n");
+
+ getVerdict(jni_env, "Exception");
+
+ if (hotswap == HOTSWAP_EVERY_EXCEPTION ||
+ hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
+ jvmti_env, method, &decl_clazz)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get method declaring class\n");
+
+ if (findAndHotSwap(jni_env, decl_clazz) != 0)
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to hotswap class\n");
+ }
+}
+
+void JNICALL
+FieldAccess(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jmethodID method,
+ jlocation location, jclass field_klass, jobject obj, jfieldID field) {
+
+ display(1, "#### JVMTIagent: FieldAccess occurred ####\n");
+
+ getVerdict(jni_env, "FieldAccess");
+}
+
+void JNICALL
+FieldModification(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jmethodID method, jlocation location,
+ jclass field_klass, jobject obj,
+ jfieldID field, char sig, jvalue new_value) {
+
+ display(1, "#### JVMTIagent: FieldModification occurred ####\n");
+
+ getVerdict(jni_env, "FieldModification");
+}
+
+void JNICALL
+FramePop(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jmethodID method, jboolean wasPopedByException) {
+
+ display(1, "#### JVMTIagent: FramePop occurred ####\n");
+
+ getVerdict(jni_env, "FramePop");
+}
+
+void JNICALL
+GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
+
+ display(1, "#### JVMTIagent: GarbageCollectionFinish occurred ####\n");
+
+ getVerdict(NULL, "GarbageCollectionFinish");
+}
+
+void JNICALL
+GarbageCollectionStart(jvmtiEnv *jvmti_env) {
+
+ display(1, "#### JVMTIagent: GarbageCollectionStart occurred ####\n");
+
+ getVerdict(NULL, "GarbageCollectionStart");
+}
+
+void JNICALL
+MonitorContendedEnter(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr,
+ jobject obj) {
+
+ display(1, "#### JVMTIagent: MonitorContendedEnter occurred ####\n");
+
+ getVerdict(jni_env, "MonitorContendedEnter");
+}
+
+void JNICALL
+MonitorContendedEntered(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr,
+ jobject obj) {
+
+ display(1, "#### JVMTIagent: MonitorContendedEntered occurred ####\n");
+
+ getVerdict(jni_env, "MonitorContendedEntered");
+}
+
+void JNICALL
+MonitorWait(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, jobject obj,
+ jlong tout) {
+
+ display(1, "#### JVMTIagent: MonitorWait occurred ####\n");
+
+ getVerdict(jni_env, "MonitorWait");
+}
+
+void JNICALL
+MonitorWaited(jvmtiEnv *jvmti_env, JNIEnv* jni_env,
+ jthread thr, jobject obj, jboolean timed_out) {
+
+ display(1, "#### JVMTIagent: MonitorWaited occurred ####\n");
+
+ getVerdict(jni_env, "MonitorWaited");
+}
+
+void JNICALL
+NativeMethodBind(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
+ jmethodID method, void *addr, void **new_addr) {
+
+ display(1, "#### JVMTIagent: NativeMethodBind occurred ####\n");
+
+ getVerdict(jni_env, "NativeMethodBind");
+}
+
+void JNICALL
+ObjectFree(jvmtiEnv *jvmti_env, jlong tag) {
+
+ display(1, "#### JVMTIagent: ObjectFree occurred ####\n");
+
+ getVerdict(NULL, "ObjectFree");
+}
+
+void JNICALL
+ThreadEnd(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) {
+
+ display(1, "#### JVMTIagent: ThreadEnd occurred ####\n");
+
+ getVerdict(jni_env, "ThreadEnd");
+}
+
+void JNICALL
+ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) {
+
+ display(1, "#### JVMTIagent: ThreadStart occurred ####\n");
+
+ getVerdict(jni_env, "ThreadStart");
+}
+
+void JNICALL
+VMDeath(jvmtiEnv *jvmti_env, JNIEnv *jni_env) {
+ vm_death_occured = TRUE;
+
+ display(0, "#### JVMTIagent: VMDeath occurred ####\n");
+
+ if (hotswap != HOTSWAP_OFF) {
+ deallocClsInfo(jni_env);
+ display(0, "#### JVMTIagent: allocated memory was successfully freed ####\n");
+ }
+}
+
+void JNICALL
+VMInit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr) {
+
+ display(0, "#### JVMTIagent: VMInit occurred ####\n");
+
+ getVerdict(jni_env, "VMInit");
+}
+
+void JNICALL
+VMStart(jvmtiEnv *jvmti_env, JNIEnv* jni_env) {
+
+ display(0, "#### JVMTIagent: VMStart occurred ####\n");
+
+ getVerdict(jni_env, "VMStart");
+}
+
+JNIEXPORT void JNICALL
+VMObjectAlloc(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
+ jobject object, jclass object_klass, jlong size) {
+
+ display(1, "#### JVMTIagent: VMObjectAlloc occurred ####\n");
+
+ getVerdict(jni_env, "VMObjectAlloc");
+}
+
+void JNICALL
+SingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
+ jmethodID method, jlocation location) {
+ jclass decl_clazz;
+
+ display((hotswap == HOTSWAP_EVERY_SINGLE_STEP)?0:1,
+ "#### JVMTIagent: SingleStep occurred ####\n");
+
+ getVerdict(jni_env, "SingleStep");
+
+ if (hotswap == HOTSWAP_EVERY_SINGLE_STEP) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
+ jvmti_env, method, &decl_clazz)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get method declaring class\n");
+
+ if (findAndHotSwap(jni_env, decl_clazz) != 0)
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to hotswap class\n");
+ }
+}
+
+void JNICALL
+MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jmethodID method) {
+ jclass decl_clazz;
+
+ display((hotswap == HOTSWAP_EVERY_METHOD_ENTRY ||
+ hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS)?0:1,
+ "#### JVMTIagent: MethodEntry occurred ####\n");
+
+ getVerdict(jni_env, "MethodEntry");
+
+ if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY ||
+ hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
+ jvmti_env, method, &decl_clazz)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get method declaring class\n");
+
+ if (findAndHotSwap(jni_env, decl_clazz) != 0)
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to hotswap class\n");
+ }
+}
+
+void JNICALL
+MethodExit(jvmtiEnv *jvmti_env, JNIEnv *jni_env,
+ jthread thr, jmethodID method,
+ jboolean was_poped_by_exc, jvalue return_value) {
+
+ display(1, "#### JVMTIagent: MethodExit occurred ####\n");
+
+ getVerdict(jni_env, "MethodExit");
+}
+
+void JNICALL
+ExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr,
+ jmethodID method, jlocation location, jobject exception) {
+ jclass decl_clazz;
+
+ display((hotswap == HOTSWAP_EVERY_EXCEPTION ||
+ hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1,
+ "#### JVMTIagent: ExceptionCatch occurred ####\n");
+
+ getVerdict(jni_env, "ExceptionCatch");
+
+ if (hotswap == HOTSWAP_EVERY_EXCEPTION ||
+ hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
+ jvmti_env, method, &decl_clazz)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get method declaring class\n");
+
+ if (findAndHotSwap(jni_env, decl_clazz) != 0)
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to hotswap class\n");
+ }
+}
+/************************/
+
+static void lock(JNIEnv *jni_env) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter,
+ jvmti, eventLock)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to enter a raw monitor\n");
+}
+
+static void unlock(JNIEnv *jni_env) {
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit,
+ jvmti, eventLock)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to exit a raw monitor\n");
+}
+
+JNIEXPORT jint JNICALL
+Java_nsk_share_RASagent_setHotSwapMode(JNIEnv *jni_env, jclass cls,
+ jboolean vrb, jint level, jstring shortName) {
+ jvmtiCapabilities capabil;
+ jmethodID mid = NULL;
+
+ if (jvmti == NULL) {
+ printf("ERROR(%s,%d): JVMTIagent was not properly loaded: JVMTI env = NULL\n",
+ __FILE__, __LINE__);
+ return 1;
+ }
+
+ /* get supported JVMTI capabilities */
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities,
+ jvmti, &capabil)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to get capabilities\n");
+ if (capabil.can_redefine_classes != 1) { /* ???????????? */
+ printf("ERROR: JVMTIagent: Class File Redefinition (HotSwap) is not implemented in this VM\n");
+ return 1;
+ }
+
+ if (vrb == JNI_TRUE && debug_mode == 0)
+ debug_mode = 1;
+
+ hotswap = level;
+ switch (hotswap) {
+ case HOTSWAP_OFF:
+ display(0, "#### JVMTIagent: hotswap mode off ####\n");
+ return 0;
+ case HOTSWAP_EVERY_METHOD_ENTRY:
+ stress_lev = 2;
+ display(0, "#### JVMTIagent: hotswapping class in every method entry event enabled ####\n\
+<JVMTIagent>\tHotSwap stress level: %d\n",
+ stress_lev);
+ break;
+ case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS:
+ stress_lev = 2;
+ display(0, "#### JVMTIagent: hotswapping class in every method entry event for every class enabled ####\n\
+<JVMTIagent>\tHotSwap stress level: %d\n",
+ stress_lev);
+ break;
+ case HOTSWAP_EVERY_SINGLE_STEP:
+ stress_lev = 3;
+ display(0, "#### JVMTIagent: hotswapping class in every single step event enabled ####\n\
+<JVMTIagent>\tHotSwap stress level: %d\n",
+ stress_lev);
+ break;
+ case HOTSWAP_EVERY_EXCEPTION:
+ stress_lev = 4;
+ display(0, "#### JVMTIagent: hotswapping class in every exception event enabled ####\n\
+<JVMTIagent>\tHotSwap stress level: %d\n",
+ stress_lev);
+ break;
+ case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS:
+ stress_lev = 40;
+ display(0, "#### JVMTIagent: hotswapping class in every exception event for every class enabled ####\n\
+<JVMTIagent>\tHotSwap stress level: %d\n",
+ stress_lev);
+ break;
+ default:
+ printf("ERROR(%s,%d): JVMTIagent: unknown value of HotSwap stress level: \"%d\"\n",
+ __FILE__,__LINE__,hotswap);
+ return 1;
+ }
+
+ if (!NSK_JNI_VERIFY(jni_env, (shortTestName = NSK_CPP_STUB3(GetStringUTFChars,
+ jni_env, shortName, NULL)) != NULL)) {
+ printf("ERROR: JVMTIagent: unable to get UTF-8 characters of the string\n");
+ return 1;
+ }
+ display(0, "#### JVMTIagent: short name of current test is \"%s\"\n",
+ shortTestName);
+
+ if (!NSK_JNI_VERIFY(jni_env, (rasCls = NSK_CPP_STUB2(NewGlobalRef,
+ jni_env, cls)) != NULL)) {
+ printf("ERROR JVMTIagent: unable to create a new global reference of the class \"RASagent\"\n");
+ return 1;
+ }
+
+ if (addStressEvents() != 0) {
+ printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n",
+ __FILE__,__LINE__);
+ return 1;
+ }
+
+ return 0;
+}
+
+static jint allocClsInfo(JNIEnv *jni_env, char *cls_sig, jclass clazz) {
+ class_info *_clsInfo = NULL;
+ jmethodID mid = NULL;
+ jbyteArray classBytes;
+ jboolean isCopy;
+
+ if ((_clsInfo = (class_info*)
+ malloc(sizeof(class_info))) == NULL)
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: cannot allocate memory for class_info\n");
+
+ /* fill the structure class_info */
+ _clsInfo->clazzsig = cls_sig;
+
+ if (!NSK_JNI_VERIFY(jni_env, ((*_clsInfo).cls = NSK_CPP_STUB2(NewGlobalRef,
+ jni_env, clazz)) != NULL)) {
+ printf("ERROR: JVMTIagent: unable to create a new global reference of class \"%s\"\n",
+ _clsInfo->clazzsig);
+ free(_clsInfo);
+ deallocClsInfo(jni_env);
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: unable to create a new global reference of class\n");
+ }
+
+ if (!NSK_JNI_VERIFY(jni_env, (mid =
+ NSK_CPP_STUB4(GetStaticMethodID, jni_env, rasCls,
+ "loadFromClassFile", "(Ljava/lang/String;)[B")) != NULL))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: unable to get ID of the method \"loadFromClassFile\"\n");
+
+ classBytes = (jbyteArray) NSK_CPP_STUB4(CallStaticObjectMethod,
+ jni_env, rasCls, mid, NSK_CPP_STUB2(NewStringUTF, jni_env, cls_sig));
+
+ clearJavaException(jni_env);
+
+ (*_clsInfo).bCount = NSK_CPP_STUB2(GetArrayLength, jni_env, classBytes);
+
+ (*_clsInfo).clsBytes =
+ NSK_CPP_STUB3(GetByteArrayElements, jni_env, classBytes, &isCopy);
+
+ _clsInfo->next = NULL;
+
+ if (clsInfo != NULL) {
+ clsInfo->next = (struct class_info*) _clsInfo;
+ }
+ else {
+ clsInfoFst = _clsInfo;
+ }
+ clsInfo = _clsInfo;
+
+ return (*_clsInfo).bCount;
+}
+
+static void deallocClsInfo(JNIEnv *jni_env) {
+ class_info *clsInfoCurr = clsInfoFst;
+
+ NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, rasCls));
+
+ while(clsInfoCurr != NULL) {
+ class_info *_clsInfo = clsInfoCurr;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
+ jvmti, (unsigned char*) clsInfoCurr->clazzsig)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: failed to deallocate memory for clazzsig\n");
+
+ NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, clsInfoCurr->cls));
+
+ clsInfoCurr = (class_info*) clsInfoCurr->next;
+
+ free(_clsInfo);
+ }
+ /* fix for 4756585: indicate that stucture class_info is empty now */
+ clsInfoFst = NULL;
+}
+
+static int findAndHotSwap(JNIEnv *jni_env, jclass clazz) {
+ int ret_code = 0;
+ char *clazzsig = NULL;
+ class_info *clsInfoCurr = clsInfoFst;
+
+ display(1, "\n#### JVMTIagent: findAndHotSwap: obtaining class signature of class to be hotswap ...\n");
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
+ jvmti, clazz, &clazzsig, /*&generic*/NULL)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: findAndHotSwap: failed to get class signature\n");
+ else {
+ display(1, "#### JVMTIagent: findAndHotSwap: ... class signature obtained: \"%s\"\n",
+ clazzsig);
+
+ /* enter into a raw monitor for exclusive work with redefined class */
+ lock(jni_env);
+ display(0, "#### JVMTIagent: findAndHotSwap: >>>>>>>> entered the raw monitor \"eventLock\" ####\n");
+
+ while(clsInfoCurr != NULL) {
+ if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS ||
+ hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) {
+ display(1, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" during execution of class \"%s\" ...\n",
+ clsInfoCurr->clazzsig, clazzsig);
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
+ jvmti, (unsigned char*) clazzsig)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n");
+
+ if (doHotSwap(jni_env, clsInfoCurr->cls,
+ clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) {
+ ret_code = 1;
+ break;
+ }
+ }
+ else {
+ if (strcmp(clazzsig, clsInfoCurr->clazzsig) == 0) {
+ display(0, "\n#### JVMTIagent: findAndHotSwap: tested class found \"%s\" ...\n",
+ clazzsig);
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
+ jvmti, (unsigned char*) clazzsig)))
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n");
+
+ display(0, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" ...\n",
+ clsInfoCurr->clazzsig);
+ if (doHotSwap(jni_env, clsInfoCurr->cls,
+ clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) {
+ ret_code = 1;
+ break;
+ }
+ }
+ }
+
+ clsInfoCurr = (class_info*) clsInfoCurr->next;
+ }
+
+ /* exit raw monitor */
+ unlock(jni_env);
+ display(0, "#### JVMTIagent: findAndHotSwap: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n");
+ }
+
+ return ret_code;
+}
+
+static int doHotSwap(JNIEnv *jni_env, jclass redefCls, jint bCount,
+ jbyte *classBytes) {
+ jvmtiClassDefinition classDef;
+
+ /* fill the structure jvmtiClassDefinition */
+ classDef.klass = redefCls;
+ classDef.class_byte_count = bCount;
+ classDef.class_bytes = (unsigned char*) classBytes;
+
+ display(0, "#### JVMTIagent: >>>>>>>> Invoke RedefineClasses():\n\
+<JVMTIagent>\tnew class byte count=%d\n",
+ classDef.class_byte_count);
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RedefineClasses,
+ jvmti, 1, &classDef)))
+ return 1;
+
+ display(0, "#### JVMTIagent: <<<<<<<< RedefineClasses() is successfully done ####\n");
+
+ return 0;
+}
+
+static int addStressEvents() {
+ static int stepEventSet = JNI_FALSE;
+ static int methodsEventSet = JNI_FALSE;
+ static int excCatchEventSet = JNI_FALSE;
+
+ if (stress_lev >= 3) {
+ /* SingleStep events */
+ if (stepEventSet == JNI_FALSE) { /* don't set the event twice */
+ display(0, "#### JVMTIagent: setting SingleStep events ...\n");
+
+ callbacks.SingleStep = &SingleStep;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, NULL)))
+ return JNI_ERR;
+
+ stepEventSet = JNI_TRUE;
+
+ display(0, "#### JVMTIagent: ... setting SingleStep events done\n");
+ }
+ }
+
+ if (stress_lev >= 2) {
+ /* MethodEntry/Exit events */
+ if (methodsEventSet == JNI_FALSE) { /* don't set the event twice */
+ display(0, "#### JVMTIagent: setting MethodEntry events ...\n");
+
+ callbacks.MethodEntry = &MethodEntry;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL)))
+ return JNI_ERR;
+
+ display(0, "#### JVMTIagent: ... setting MethodEntry events done\n");
+
+ /* MethodExit events */
+ display(0, "#### JVMTIagent: setting MethodExit events ...\n");
+
+ callbacks.MethodExit = &MethodExit;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL)))
+ return JNI_ERR;
+
+ display(0, "#### JVMTIagent: ... setting MethodExit events done\n");
+
+ methodsEventSet = JNI_TRUE;
+ }
+ }
+
+ if (stress_lev >= 1) {
+ /* ExceptionCatch events */
+ if (excCatchEventSet == JNI_FALSE) { /* don't set the event twice */
+ display(0, "#### JVMTIagent: setting ExceptionCatch events ...\n");
+
+ callbacks.ExceptionCatch = &ExceptionCatch;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION_CATCH, NULL)))
+ return JNI_ERR;
+
+ excCatchEventSet = JNI_TRUE;
+
+ display(0, "#### JVMTIagent: ... setting ExceptionCatch events done\n");
+ }
+ }
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks,
+ jvmti, &callbacks, sizeof(callbacks))))
+ return JNI_ERR;
+ else
+ return 0;
+}
+
+static int enableEventsCaps() {
+ jvmtiCapabilities caps;
+
+ memset(&caps, 0, sizeof(jvmtiCapabilities));
+
+ /* add all capabilities */
+ caps.can_redefine_classes = 1;
+ caps.can_generate_breakpoint_events = 1;
+ caps.can_generate_all_class_hook_events = 1;
+ caps.can_generate_single_step_events = 1;
+ caps.can_generate_method_entry_events = 1;
+ caps.can_generate_method_exit_events = 1;
+ caps.can_generate_exception_events = 1;
+ caps.can_generate_compiled_method_load_events = 1;
+ caps.can_generate_field_access_events = 1;
+ caps.can_generate_field_modification_events = 1;
+ caps.can_generate_frame_pop_events = 1;
+ caps.can_generate_garbage_collection_events = 1;
+ caps.can_generate_monitor_events = 1;
+ caps.can_generate_native_method_bind_events = 1;
+ caps.can_generate_object_free_events = 1;
+ caps.can_generate_vm_object_alloc_events = 1;
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities,
+ jvmti, &caps)))
+ return JNI_ERR;
+
+ /* Breakpoint events */
+ display(0, "#### JVMTIagent: setting Breakpoint events ...\n");
+
+ callbacks.Breakpoint = &Breakpoint;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting Breakpoint events done\n");
+
+ /* ClassFileLoadHook events */
+ display(0, "#### JVMTIagent: setting ClassFileLoadHook events ...\n");
+
+ callbacks.ClassFileLoadHook = &ClassFileLoadHook;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ClassFileLoadHook events done\n");
+
+ /* ClassLoad events */
+ display(0, "#### JVMTIagent: setting ClassLoad events ...\n");
+
+ callbacks.ClassLoad = &ClassLoad;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ClassLoad events done\n");
+
+ /* ClassPrepare events */
+ display(0, "#### JVMTIagent: setting ClassPrepare events ...\n");
+
+ callbacks.ClassPrepare = &ClassPrepare;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ClassPrepare events done\n");
+
+ /* CompiledMethodLoad events */
+ display(0, "#### JVMTIagent: setting CompiledMethodLoad events ...\n");
+
+ callbacks.CompiledMethodLoad = &CompiledMethodLoad;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting CompiledMethodLoad events done\n");
+
+ /* CompiledMethodUnload events */
+ display(0, "#### JVMTIagent: setting CompiledMethodUnload events ...\n");
+
+ callbacks.CompiledMethodUnload = &CompiledMethodUnload;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting CompiledMethodUnload events done\n");
+
+ /* DataDumpRequest events */
+ display(0, "#### JVMTIagent: setting DataDumpRequest events ...\n");
+
+ callbacks.DataDumpRequest = &DataDumpRequest;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting DataDumpRequest events done\n");
+
+ /* DynamicCodeGenerated events */
+ display(0, "#### JVMTIagent: setting DynamicCodeGenerated events ...\n");
+
+ callbacks.DynamicCodeGenerated = &DynamicCodeGenerated;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting DynamicCodeGenerated events done\n");
+
+ /* Exception events */
+ display(0, "#### JVMTIagent: setting Exception events ...\n");
+
+ callbacks.Exception = &Exception;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting Exception events done\n");
+
+ /* FieldAccess events */
+ display(0, "#### JVMTIagent: setting FieldAccess events ...\n");
+
+ callbacks.FieldAccess = &FieldAccess;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting FieldAccess events done\n");
+
+ /* FieldModification events */
+ display(0, "#### JVMTIagent: setting FieldModification events ...\n");
+
+ callbacks.FieldModification = &FieldModification;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting FieldModification events done\n");
+
+ /* FramePop events */
+ display(0, "#### JVMTIagent: setting FramePop events ...\n");
+
+ callbacks.FramePop = &FramePop;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting FramePop events done\n");
+
+ /* GarbageCollectionFinish events */
+ display(0, "#### JVMTIagent: setting GarbageCollectionFinish events ...\n");
+
+ callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting GarbageCollectionFinish events done\n");
+
+ /* GarbageCollectionStart events */
+ display(0, "#### JVMTIagent: setting GarbageCollectionStart events ...\n");
+
+ callbacks.GarbageCollectionStart = &GarbageCollectionStart;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting GarbageCollectionStart events done\n");
+
+ /* MonitorContendedEnter events */
+ display(0, "#### JVMTIagent: setting MonitorContendedEnter events ...\n");
+
+ callbacks.MonitorContendedEnter = &MonitorContendedEnter;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting MonitorContendedEnter events done\n");
+
+ /* MonitorContendedEntered events */
+ display(0, "#### JVMTIagent: setting MonitorContendedEntered events ...\n");
+
+ callbacks.MonitorContendedEntered = &MonitorContendedEntered;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting MonitorContendedEntered events done\n");
+
+ /* MonitorWait events */
+ display(0, "#### JVMTIagent: setting MonitorWait events ...\n");
+
+ callbacks.MonitorWait = &MonitorWait;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting MonitorWait events done\n");
+
+ /* MonitorWaited events */
+ display(0, "#### JVMTIagent: setting MonitorWaited events ...\n");
+
+ callbacks.MonitorWaited = &MonitorWaited;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting MonitorWaited events done\n");
+
+ /* NativeMethodBind events */
+ display(0, "#### JVMTIagent: setting NativeMethodBind events ...\n");
+
+ callbacks.NativeMethodBind = &NativeMethodBind;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting NativeMethodBind events done\n");
+
+ /* ObjectFree events */
+ display(0, "#### JVMTIagent: setting ObjectFree events ...\n");
+
+ callbacks.ObjectFree = &ObjectFree;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ObjectFree events done\n");
+
+ /* ThreadEnd events */
+ display(0, "#### JVMTIagent: setting ThreadEnd events ...\n");
+
+ callbacks.ThreadEnd = &ThreadEnd;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ThreadEnd events done\n");
+
+ /* ThreadStart events */
+ display(0, "#### JVMTIagent: setting ThreadStart events ...\n");
+
+ callbacks.ThreadStart = &ThreadStart;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting ThreadStart events done\n");
+
+ /* VMDeath events */
+ display(0, "#### JVMTIagent: setting VMDeath events ...\n");
+
+ callbacks.VMDeath = &VMDeath;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting VMDeath events done\n");
+
+ /* VMInit events */
+ display(0, "#### JVMTIagent: setting VMInit events ...\n");
+
+ callbacks.VMInit = &VMInit;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting VMInit events done\n");
+
+ /* VMStart events */
+ display(0, "#### JVMTIagent: setting VMStart events ...\n");
+
+ callbacks.VMStart = &VMStart;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting VMStart events done\n");
+
+ /* VMObjectAlloc events */
+ display(0, "#### JVMTIagent: setting VMObjectAlloc events ...\n");
+
+ callbacks.VMObjectAlloc = &VMObjectAlloc;
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
+ jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL)))
+ return JNI_ERR;
+ display(0, "#### JVMTIagent: ... setting VMObjectAlloc events done\n");
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks,
+ jvmti, &callbacks, sizeof(callbacks))))
+ return JNI_ERR;
+
+ return 0;
+}
+
+static void clearJavaException(JNIEnv* jni_env) {
+ if (NSK_CPP_STUB1(ExceptionOccurred, jni_env)) {
+
+ NSK_CPP_STUB1(ExceptionDescribe, jni_env);
+ NSK_CPP_STUB1(ExceptionClear, jni_env);
+
+ NSK_CPP_STUB2(FatalError, jni_env,
+ "JVMTIagent: exception occurred in java code, aborting\n");
+ }
+}
+
+static int get_tok(char **src, char *buf, int buflen, char sep) {
+ int i;
+ char *p = *src;
+ for (i = 0; i < buflen; i++) {
+ if (p[i] == 0 || p[i] == sep) {
+ buf[i] = 0;
+ if (p[i] == sep) {
+ i++;
+ }
+ *src += i;
+ return i;
+ }
+ buf[i] = p[i];
+ }
+ /* overflow */
+ return 0;
+}
+
+static void doSetup(char *str) {
+ if (str == 0)
+ str = "";
+
+ if ((strcmp(str, "help")) == 0) {
+ printf("#### JVMTIagent usage: -agentlib:JVMTIagent[=[help]|[=[verbose]|[verbose2],[stress0|stress1|stress2|stress3]]]\n");
+ printf("#### where: help\tprint this message\n");
+ printf("#### verbose\tturn verbose mode on\n");
+ printf("#### verbose2\tturn extended verbose mode on (including reporting JVMTI events)\n");
+ printf("#### stress0, or empty value\tturn stress level 0 on (default mode):\n");
+ printf("#### enable event generation except ExceptionCatch, MethodEntry/Exit, SingleStep\n");
+ printf("#### stress1\tturn stress level 1 on:\n");
+ printf("#### enable generation of ExceptionCatch events\n");
+ printf("#### stress2\tturn stress level 2 on:\n");
+ printf("#### enable generation of ExceptionCatch,\n");
+ printf("#### MethodEntry/Exit events\n");
+ printf("#### stress3\tturn stress level 3 on:\n");
+ printf("#### enable generation of ExceptionCatch,\n");
+ printf("#### MethodEntry/Exit,\n");
+ printf("#### SingleStep events\n");
+ exit(1);
+ }
+
+ while (*str) {
+ char buf[1000];
+
+ if (!get_tok(&str, buf, sizeof(buf), ',')) {
+ printf("ERROR: JVMTIagent: bad option: \"%s\"!\n", str);
+ exit(1);
+ }
+ if ((strcmp(buf, "verbose")) == 0) {
+ printf("#### JVMTIagent: turned verbose mode on ####\n");
+ debug_mode = 1;
+ }
+ if ((strcmp(buf, "verbose2")) == 0) {
+ printf("#### JVMTIagent: turned extended verbose mode on ####\n");
+ debug_mode = 2;
+ }
+ if ((strcmp(buf, "stress0")) == 0) {
+ if (debug_mode > 0)
+ printf("#### JVMTIagent: turned stress level 0 on ####\n");
+ stress_lev = 0;
+ }
+ if ((strcmp(buf, "stress1")) == 0) {
+ if (debug_mode > 0)
+ printf("#### JVMTIagent: turned stress level 1 on ####\n");
+ stress_lev = 1;
+ }
+ if ((strcmp(buf, "stress2")) == 0) {
+ if (debug_mode > 0)
+ printf("#### JVMTIagent: turned stress level 2 on ####\n");
+ stress_lev = 2;
+ }
+ if ((strcmp(buf, "stress3")) == 0) {
+ if (debug_mode > 0)
+ printf("#### JVMTIagent: turned stress level 3 on ####\n");
+ stress_lev = 3;
+ }
+ }
+}
+
+static void getVerdict(JNIEnv *jni_env, const char *evnt) {
+ char error_msg[80];
+
+ if (vm_death_occured == TRUE) {
+ sprintf(error_msg, "JVMTIagent: getVerdict: %s event occured after VMDeath",
+ evnt);
+
+ if (jni_env==NULL) { /* some event callbacks have no pointer to jni */
+ printf("ERROR: %s\n", error_msg);
+ exit(97);
+ }
+ else
+ NSK_CPP_STUB2(FatalError, jni_env, error_msg);
+ }
+}
+
+static void display(int level, const char format[], ...) {
+ va_list ar;
+
+ if (debug_mode > level) {
+ va_start(ar, format);
+ vprintf(format, ar);
+ va_end(ar);
+ }
+}
+
+/* agent procedure */
+static void JNICALL
+agentProc(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) {
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ /* create JVMTI environment */
+ if (!NSK_VERIFY((jvmti =
+ nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
+ return JNI_ERR;
+
+ doSetup(options);
+
+ if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor,
+ jvmti, "_event_lock", &eventLock)))
+ return JNI_ERR;
+
+ if (enableEventsCaps() == 0 && addStressEvents() == 0) {
+ display(0, "#### JVMTIagent: all events were successfully enabled and capabilities/events callbacks set ####\n\n");
+ } else {
+ printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n",
+ __FILE__,__LINE__);
+ return JNI_ERR;
+ }
+
+ /* register agent proc and arg */
+ if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
+ return JNI_ERR;
+
+ return JNI_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import nsk.share.*;
+
+import java.io.*;
+
+/**
+ * Wrapper for local process.
+ * <p>
+ * This class provides abilities to launch such process,
+ * redirect standard output streams, wait for process terminates
+ * or kill the process, and so on.
+ * <p>
+ * This object is finalized with <code>nsk.share.Finalizer</code>.
+ *
+ * @see nsk.share.FinalizableObject
+ * @see nsk.share.Finalizer
+ */
+
+public class LocalProcess extends FinalizableObject {
+
+ public final static int PROCESS_IS_ALIVE = 222;
+
+ private Process process;
+
+ protected Process getProcess() {
+ return process;
+ }
+
+ public void launch (String[] args) throws IOException {
+ System.out.println("Launching process by array of args: ");
+ for (int mm=0; mm < args.length; mm++) {
+ System.out.println(" args[" + Integer.toString(mm) + "]: >" +
+ args[mm] + "<");
+
+ }
+
+ process = Runtime.getRuntime().exec(args);
+
+ Finalizer finalizer = new Finalizer(this);
+ finalizer.activate();
+ }
+
+ public void launch (String cmdLine) throws IOException {
+ System.out.println("Launching process by command line: " + cmdLine);
+
+ process = Runtime.getRuntime().exec(cmdLine);
+
+ Finalizer finalizer = new Finalizer(this);
+ finalizer.activate();
+ }
+
+ /** Return exit status. */
+ public int getStatus () {
+ return process.exitValue();
+ }
+
+ /** Check whether the process has been terminated. */
+ public boolean terminated() {
+ try {
+ int value = process.exitValue();
+ return true;
+ } catch (IllegalThreadStateException e) {
+ return false;
+ }
+ }
+
+ /** Wait until the process shutdown or crash. */
+ public int waitFor () throws InterruptedException {
+ return process.waitFor();
+ }
+
+ /**
+ * Wait until the process shutdown or crash for given timeout in milliseconds.
+ * Returns <code>LocalProcess.PROCESS_IS_ALIVE</code> if process is not terminated
+ * after timeout.
+ */
+
+ public int waitFor (long timeMillisec) throws InterruptedException {
+ final Object waitObject = new Object();
+
+ class Watcher extends Thread {
+ int exitCode = LocalProcess.PROCESS_IS_ALIVE;
+ Process process;
+
+ Watcher (Process process) {
+ this.process = process;
+ }
+
+ public void run () {
+ try {
+ synchronized (this) {
+ exitCode = process.waitFor();
+ }
+ } catch (InterruptedException ie) {
+ }
+ synchronized (waitObject) {
+ waitObject.notifyAll();
+ }
+ }
+
+ synchronized public int getExitCode() {
+ return exitCode;
+ }
+ }
+
+ Watcher watcher;
+ // yield control to watcher for timeMillisec time.
+ synchronized (waitObject) {
+ watcher = new Watcher(process);
+ watcher.start();
+
+ waitObject.wait(timeMillisec);
+ }
+
+ if (watcher.isAlive()) {
+ watcher.interrupt();
+ }
+
+ return watcher.getExitCode();
+ }
+
+ // --------------------------------------------------- //
+
+ /** Get a pipe to write to the process' stdin stream. */
+ public OutputStream getStdin () {
+ return process.getOutputStream();
+ }
+
+ /** Get a pipe to read the process' stdout stream. */
+ public InputStream getStdout () {
+ return process.getInputStream();
+ }
+
+ /** Get a pipe to read the process stderr stream. */
+ public InputStream getStderr () {
+ return process.getErrorStream();
+ }
+
+ /** Kill the process. */
+ protected void kill() {
+ process.destroy();
+ }
+
+ /**
+ * Finalize mirror by invoking <code>close()</code>.
+ *
+ * @throws Throwable if any throwable exception is thrown during finalization
+ */
+ protected void finalize() throws Throwable {
+ kill();
+ super.finalize();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Vector;
+
+import nsk.share.test.LazyFormatString;
+
+/**
+ * This class helps to print test-execution trace messages
+ * and filter them when execution mode is not verbose.
+ * <p>
+ * Verbose mode if defined by providing <i>-verbose</i> command line
+ * option, handled by <code>ArgumentParser</code>. Use <code>verbose()</code>
+ * method to determine which mode is used.
+ * <p>
+ * <code>Log</code> provides with two main methods to print messages:
+ * <ul>
+ * <li> <code>complain(String)</code> - to print error message
+ * <li> <code>display(String)</code> - to print additional log message
+ * </ul>
+ * No other way to print messages to the log stream should be used.
+ * <p>
+ * Error messages appeares in log stream in all modes. Additional log massages,
+ * printed with <code>display()</code> method will be filtered out, if log mode
+ * is not verbose. In verbose log made messages of both types are printed.
+ * Additionally, in verbose mode a summary of all occured errors will be printed
+ * at the program exit, by automatically invoking method
+ * <code>printErrorsSummary()</code>.
+ * <p>
+ * To provide printing messages from different sources into one log
+ * with distinct prefixes use internal <code>Log.Logger</code> class.
+ *
+ * @see #verbose()
+ * @see #complain(String)
+ * @see #display(String)
+ * @see ArgumentParser
+ * @see Log.Logger
+ */
+public class Log extends FinalizableObject {
+ /**
+ * Report step-by-step activity to this stream.
+ *
+ * @deprecated Tests should not use this field directly.
+ */
+ protected PrintStream out = null;
+
+ /**
+ * Is log-mode verbose?
+ * Default value is <code>false</code>.
+ */
+ private boolean verbose = false;
+
+ /**
+ * Should log messages prefixed with timestamps?
+ * Default value is <code>false</code>.
+ */
+ private boolean timestamp = false;
+
+ /**
+ * Names for trace levels
+ */
+ public static final class TraceLevel {
+ public static final int TRACE_NONE = 0;
+ public static final int TRACE_IMPORTANT = 1;
+ public static final int TRACE_NORMAL = 2;
+ public static final int TRACE_VERBOSE = 3;
+ public static final int TRACE_DEBUG = 4;
+
+ public static final int DEFAULT = TRACE_IMPORTANT;
+
+ public static final Map<String, Integer> NAME_TO_LEVEL_MAP = new HashMap<String, Integer>();
+ static {
+ NAME_TO_LEVEL_MAP.put("none", TRACE_NONE);
+ NAME_TO_LEVEL_MAP.put("important", TRACE_IMPORTANT);
+ NAME_TO_LEVEL_MAP.put("info", TRACE_NORMAL);
+ NAME_TO_LEVEL_MAP.put("verbose", TRACE_VERBOSE);
+ NAME_TO_LEVEL_MAP.put("debug", TRACE_DEBUG);
+ NAME_TO_LEVEL_MAP.put("default", DEFAULT);
+ }
+
+ public static int nameToLevel(String value) throws IllegalArgumentException {
+ Integer level = NAME_TO_LEVEL_MAP.get(value.toLowerCase());
+ if ( level == null )
+ throw new IllegalArgumentException("Wrong trace level: " + value);
+
+ return level;
+ }
+
+ public static String getLevelsString() {
+ StringBuffer result = new StringBuffer();
+ for ( String s : NAME_TO_LEVEL_MAP.keySet() ) {
+ result.append(s).append(", ");
+ }
+ return result.substring(0, result.length() - 3);
+ }
+ }
+
+ /**
+ * Threshold value for printing trace messages for debugging purpose.
+ * Default value is <code>0</code> a.k.a. <code>TraceLevel.INFO</code>;
+ */
+ private int traceLevel = TraceLevel.DEFAULT;
+
+ /**
+ * Is printing errors summary enabled? Default value is <code>true</code>;
+ */
+ private boolean errorsSummaryEnabled = true;
+
+ /**
+ * Is printing saved verbose messages on error enabled? Default value is <code>true</code>;
+ */
+ private boolean verboseOnErrorEnabled = true;
+
+ /**
+ * This <code>errosBuffer</code> will keep all messages printed via
+ * <code>complain()</code> method for final summary output.
+ * Ensure that buffer has enough room for messages to keep,
+ * to minimize probability or OutOfMemory error while keeping
+ * an error message in stress tests.
+ */
+ private Vector<String> errorsBuffer = new Vector<String>(1000);
+
+ /**
+ * Most tests in nsk do not log exceptions, they only log an error message.
+ * This makes failure analysis harder.
+ * To solve this we will automatically generate Exceptions for error logs.
+ * To not log too many Exceptions, we try to log each unique error only once.
+ * <code>loggedExceptions</code> contains all messages that have already been logged.
+ */
+ private Set<String> loggedExceptions = new HashSet<String>();
+
+ /**
+ * This <code>logBuffer</code> will keep all messages printed via
+ * <code>display()</code> method in non-verbose mode until
+ * swithching verbose mode on or invoking <code>complain()</code>.
+ * Ensure that buffer has enough room for messages to keep,
+ * to minimize probability or OutOfMemory error while keeping
+ * an error message in stress tests.
+ */
+ private Vector<String> logBuffer = new Vector<String>(1000);
+
+ /**
+ * Did I already warned if output stream is not assigned?
+ */
+ private boolean noOutWarned = false;
+
+ /////////////////////////////////////////////////////////////////
+
+ /**
+ * Create new Log's only with <code>Log(out)</code> or with
+ * <code>Log(out,argsHandler)</code> constructors.
+ *
+ * @deprecated Extending test class with Log is obsolete.
+ */
+ protected Log() {
+ // install finalizer to print errors summary at exit
+ Finalizer finalizer = new Finalizer(this);
+ finalizer.activate();
+
+ // Don't log exceptions from this method. It would just add unnecessary logs.
+ loggedExceptions.add("nsk.share.jdi.SerialExecutionDebugger.executeTests");
+ }
+
+ /**
+ * Incarnate new Log for the given <code>stream</code> and
+ * for non-verbose mode.
+ */
+ public Log(PrintStream stream) {
+ this();
+ out = stream;
+ }
+
+ /**
+ * Incarnate new Log for the given <code>stream</code>; and
+ * either for verbose or for non-verbose mode accordingly to
+ * the given <code>verbose</code> key.
+ */
+ public Log(PrintStream stream, boolean verbose) {
+ this(stream);
+ this.verbose = verbose;
+ }
+
+ /**
+ * Incarnate new Log for the given <code>stream</code>; and
+ * either for verbose or for non-verbose mode accordingly to
+ * the given <code>argsHandler</code>.
+ */
+ public Log(PrintStream stream, ArgumentParser argsParser) {
+ this(stream, argsParser.verbose());
+ traceLevel = argsParser.getTraceLevel();
+ timestamp = argsParser.isTimestamp();
+ }
+
+ /////////////////////////////////////////////////////////////////
+
+ /**
+ * Return <i>true</i> if log mode is verbose.
+ */
+ public boolean verbose() {
+ return verbose;
+ }
+
+ /**
+ * Return <i>true</i> if printing errors summary at exit is enabled.
+ */
+ public boolean isErrorsSummaryEnabled() {
+ return errorsSummaryEnabled;
+ }
+
+ /**
+ * Enable or disable printing errors summary at exit.
+ */
+ public void enableErrorsSummary(boolean enable) {
+ errorsSummaryEnabled = enable;
+ }
+
+ /**
+ * Return <i>true</i> if printing saved verbose messages on error is enabled.
+ */
+ public boolean isVerboseOnErrorEnabled() {
+ return errorsSummaryEnabled;
+ }
+
+ /**
+ * Enable or disable printing saved verbose messages on error.
+ */
+ public void enableVerboseOnError(boolean enable) {
+ verboseOnErrorEnabled = enable;
+ }
+
+ /**
+ * Enable or disable verbose mode for printing messages.
+ */
+ public void enableVerbose(boolean enable) {
+ if (!verbose) {
+ flushLogBuffer();
+ }
+ verbose = enable;
+ }
+
+ public int getTraceLevel() {
+ return traceLevel;
+ }
+
+ /**
+ * Set threshold for printing trace messages.
+ * Warning: trace level changes may NOT be observed by other threads immediately.
+ */
+ public void setTraceLevel(int level) {
+ traceLevel = level;
+ }
+
+ /**
+ * Return output stream of this <code>Log</code> object.
+ */
+ public PrintStream getOutStream() {
+ return out;
+ }
+
+ /**
+ * Returns a string that contains prefix concatenated
+ * with Throwable.printStackTrace() output.
+ */
+ public static String printExceptionToString(Object prefix, Throwable exception) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PrintWriter pw = new PrintWriter(bos);
+ pw.println(prefix);
+ exception.printStackTrace(pw);
+ pw.close();
+ return bos.toString();
+ }
+
+ /**
+ * Print <code>message</code> to the assigned output stream.
+ *
+ * @deprecated Test ought to be quiet if log mode is non-verbose
+ * and there is no errors found by the test. Methods
+ * <code>display()</code> and <code>complain()</code>
+ * are enough for testing purposes.
+ */
+ public synchronized void println(String message) {
+ doPrint(message);
+ if (!verbose() && isVerboseOnErrorEnabled()) {
+ keepLog(composeLine(message));
+ }
+ }
+
+ /**
+ * Print <code>message</code> to the assigned output stream,
+ * if log mode is <i>non</i>-verbose.
+ *
+ * @deprecated Test ought to be quiet if log mode is non-verbose
+ * and there is no errors found by the test. Methods
+ * <code>display()</code> and <code>complain()</code>
+ * are enough for testing purposes.
+ */
+ public synchronized void comment(String message) {
+ if (!verbose()) {
+ doPrint(message);
+ }
+ }
+
+ /**
+ * Print trace <code>message</code> to the assigned output stream,
+ * only if specified <code>level</code> is less or equal for the
+ * trace level specified in command line by <code>-trace.level</code>
+ * option.
+ */
+ public void trace(int level, Object message) {
+ if (level <= traceLevel) {
+ synchronized ( this ) {
+ doPrint("### TRACE " + level + ": " + message);
+ }
+ }
+ }
+ /**
+ * Print trace <code>message</code> and <code>exception</code> to
+ * the assigned output stream,
+ * only if specified <code>level</code> is less or equal for the
+ * trace level specified in command line by <code>-trace.level</code>
+ * option.
+ */
+ public void trace(int level, Object message, Throwable exception) {
+ if (level <= traceLevel) {
+ trace(level, printExceptionToString(message, exception));
+ }
+ }
+
+ /**
+ * Print <code>message</code> to the assigned output stream,
+ * if log mode is verbose. The <code>message</code> will be lost,
+ * if execution mode is non-verbose, and there is no error messages
+ * printed.
+ */
+ public synchronized void display(Object message) {
+ if (verbose()) {
+ doPrint(message.toString());
+ } else if (isVerboseOnErrorEnabled()) {
+ keepLog(composeLine(message.toString()));
+ } else {
+ // ignore
+ }
+ }
+
+ /**
+ * Print error <code>message</code> to the assigned output stream
+ * (or to stderr if output is not specified) and keep the message
+ * into <code>errorsBuffer</code>.
+ */
+ public synchronized void complain(Object message) {
+ if (!verbose() && isVerboseOnErrorEnabled()) {
+ PrintStream stream = findOutStream();
+ stream.println("#> ");
+ stream.println("#> WARNING: switching log to verbose mode,");
+ stream.println("#> because error is complained");
+ stream.println("#> ");
+ stream.flush();
+ enableVerbose(true);
+ }
+ String msgStr = message.toString();
+ printError(msgStr);
+ if (isErrorsSummaryEnabled()) {
+ keepError(msgStr);
+ }
+
+ logExceptionForFailureAnalysis(msgStr);
+ }
+
+ /**
+ * Print error <code>message</code> and <code>exception</code>
+ * to the assigned output stream
+ * (or to stderr if output is not specified) and keep the message
+ * into <code>errorsBuffer</code>.
+ */
+ public void complain(Object message, Throwable exception) {
+ if ( exception != null )
+ complain(printExceptionToString(message, exception));
+ else
+ complain(message);
+ }
+
+ /**
+ * Create an Exception and print the stack trace for an error msg.
+ * This makes it possible to detect a failure reason for this error.
+ */
+ private void logExceptionForFailureAnalysis(String msg) {
+ // Some error messages are formatted in multiple lines and with tabs.
+ // We clean the messages to help parse the stack traces for failure analysis.
+ // We keep at most 2 lines, otherwise the error message may be too long.
+ String[] lines = msg.split("[\r\n]+");
+ msg = lines.length >= 2 ? lines[0] + " " + lines[1] : lines[0];
+ msg = msg.replaceAll("\t", " ");
+
+ // Create a dummy exception just so we can print the stack trace.
+ TestFailure e = new TestFailure(msg);
+ StackTraceElement[] elements = e.getStackTrace();
+
+ final int callerIndex = 2; // 0=this function, 1=complain(), 2=caller
+ if (elements.length <= callerIndex) {
+ return;
+ }
+
+ // Only log the first complain message from each function.
+ // The reason is that some functions splits an error message
+ // into multiple lines and call complain() many times.
+ // We do not want a RULE for each of those calls.
+ // This means that we may miss some rules, but that
+ // is better than to create far too many rules.
+ String callerClass = elements[callerIndex].getClassName();
+ String callerMethod = elements[callerIndex].getMethodName();
+ String callerKey = callerClass + "." + callerMethod;
+ boolean isAlreadyLogged = loggedExceptions.contains(msg) || loggedExceptions.contains(callerKey);
+
+ if (!isAlreadyLogged) {
+ PrintStream stream = findOutStream();
+ stream.println("The following stacktrace is for failure analysis.");
+ e.printStackTrace(stream);
+ }
+
+ loggedExceptions.add(callerKey);
+ loggedExceptions.add(msg);
+ }
+
+ /////////////////////////////////////////////////////////////////
+
+ /**
+ * Redirect log to the given <code>stream</code>, and switch
+ * log mode to verbose.
+ * Prints errors summary to current stream, cancel current stream
+ * and switches to new stream. Turns on verbose mode for new stream.
+ *
+ * @deprecated This method is obsolete.
+ */
+ protected synchronized void logTo(PrintStream stream) {
+ finalize(); // flush older log stream
+ out = stream;
+ verbose = true;
+ }
+
+ /////////////////////////////////////////////////////////////////
+
+ /**
+ * Print all messages from log buffer which were hidden because
+ * of non-verbose mode,
+ */
+ private synchronized void flushLogBuffer() {
+ if (!logBuffer.isEmpty()) {
+ PrintStream stream = findOutStream();
+ for (int i = 0; i < logBuffer.size(); i++) {
+ stream.println(logBuffer.elementAt(i));
+ }
+ stream.flush();
+ }
+ }
+
+ /**
+ * Return <code>out</code> stream if defined or <code>Sytem.err<code> otherwise;
+ * print a warning message when <code>System.err</code> is used first time.
+ */
+ private synchronized PrintStream findOutStream() {
+ PrintStream stream = out;
+ if (stream == null) {
+ stream = System.err;
+ if (!noOutWarned) {
+ noOutWarned = true;
+ stream.println("#> ");
+ stream.println("#> WARNING: switching log stream to stderr,");
+ stream.println("#> because no output stream is assigned");
+ stream.println("#> ");
+ };
+ };
+ stream.flush();
+ return stream;
+ }
+
+ /**
+ * Compose line to print possible prefixing it with timestamp.
+ */
+ private String composeLine(String message) {
+ if (timestamp) {
+ long time = System.currentTimeMillis();
+ long ms = time % 1000;
+ time /= 1000;
+ long secs = time % 60;
+ time /= 60;
+ long mins = time % 60;
+ time /= 60;
+ long hours = time % 24;
+ return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message;
+ }
+ return message;
+ }
+
+ /**
+ * Print the given <code>message</code> either to <code>out</code>
+ * stream, or to <code>System.err</code> if <code>out</code>
+ * stream is not specified.
+ */
+ private synchronized void doPrint(String message) {
+ PrintStream stream = findOutStream();
+ stream.println(composeLine(message));
+ stream.flush();
+ }
+
+ /**
+ * Print the given error <code>message</code> either to <code>out</code>
+ * stream, or to <code>System.err</code> if <code>out</code>
+ * stream is not specified.
+ */
+ private synchronized void printError(String message) {
+ // Print each line with the ERROR prefix:
+ BufferedReader br = new BufferedReader(new StringReader(message));
+ for (String line; ; ) {
+ try {
+ line = br.readLine();
+ if (line == null)
+ break;
+ doPrint("# ERROR: " + line);
+ } catch (IOException e) {
+ throw new TestBug("Exception in Log.printError(): " + e);
+ };
+ }
+ }
+
+ /**
+ * Keep the given log <code>message</code> into <code>logBuffer</code>.
+ */
+ private synchronized void keepLog(String message) {
+ logBuffer.addElement(message);
+ }
+
+ /**
+ * Keep the given error <code>message</code> into <code>errorsBuffer</code>.
+ */
+ private synchronized void keepError(String message) {
+ errorsBuffer.addElement(message);
+ }
+
+ /**
+ * Print errors messages summary from errors buffer if any;
+ * print a warning message first.
+ */
+ private synchronized void printErrorsSummary() {
+ if (errorsBuffer.size() <= 0)
+ return;
+
+ PrintStream stream = findOutStream();
+ stream.println();
+ stream.println();
+ stream.println("#> ");
+ stream.println("#> SUMMARY: Following errors occured");
+ stream.println("#> during test execution:");
+ stream.println("#> ");
+ stream.flush();
+
+ for (Enumeration e = errorsBuffer.elements(); e.hasMoreElements(); ) {
+ printError((String) e.nextElement());
+ }
+ }
+
+ /**
+ * Print errors summary if mode is verbose, flush and cancel output stream.
+ */
+ protected void finalize() {
+ if (verbose() && isErrorsSummaryEnabled()) {
+ printErrorsSummary();
+ }
+ if (out != null)
+ out.flush();
+ out = null;
+ }
+
+ /**
+ * Perform finalization at the exit.
+ */
+ public void finalizeAtExit() {
+ finalize();
+ }
+
+ /**
+ * This class can be used as a base for each class that use <code>Log</code>
+ * for print messages and errors.
+ * <code>Logger</code> provides with ability to print such messages with
+ * specified prefix to make it possible to distinct messages printed from
+ * different sources.
+ *
+ * @see Log
+ */
+ public static class Logger {
+
+ /**
+ * Default prefix for messages.
+ */
+ public static final String LOG_PREFIX = "";
+
+ /**
+ * Log to print messages to.
+ */
+ protected Log log = null;
+
+ /**
+ * Prefix for messages.
+ */
+ protected String logPrefix = LOG_PREFIX;
+
+ /**
+ * Make <code>Logger</code> object with empty <code>Log</code> and
+ * default prefix.
+ * This method may be used only in derived class, that should specify
+ * the used <code>Log</code> object further and assign it to <code>log</code>.
+ *
+ * @see #log
+ * @see #setLogPrefix
+ */
+ protected Logger() {
+ }
+
+ /**
+ * Make <code>Logger</code> object for specified <code>Log</code>
+ * with default prefix.
+ *
+ * @see #setLogPrefix
+ */
+ public Logger(Log log) {
+ this.log = log;
+ }
+
+ /**
+ * Make <code>Logger</code> object for specified <code>Log</code> with
+ * given messages prefix.
+ */
+ public Logger(Log log, String prefix) {
+ this.log = log;
+ this.logPrefix = prefix;
+ }
+
+ /**
+ * Return <code>Log</code> object.
+ */
+ public Log getLog() {
+ return log;
+ }
+
+ /**
+ * Return output stream of this <code>Log</code> object.
+ */
+ public PrintStream getOutStream() {
+ return log.getOutStream();
+ }
+
+ /**
+ * Set prefix for printed messages.
+ */
+ public void setLogPrefix(String prefix) {
+ logPrefix = prefix;
+ }
+
+ /**
+ * Make printable message by adding <code>logPrefix<code> to it.
+ */
+ public String makeLogMessage(String message) {
+ return logPrefix + message;
+ }
+
+ /**
+ * Print trace message by invoking <code>Log.trace()</code>.
+ *
+ * @see Log#trace
+ */
+ public void trace(int level, String message) {
+ log.trace(level, makeLogMessage(message));
+ }
+
+ /**
+ * Print message by invoking <code>Log.println()</code>.
+ *
+ * @see Log#println
+ */
+ public void println(String message) {
+ log.println(makeLogMessage(message));
+ }
+
+ /**
+ * Print message by invoking <code>Log.display()</code>.
+ *
+ * @see Log#display
+ */
+ public void display(String message) {
+ log.display(makeLogMessage(message));
+ }
+
+ /**
+ * Complain about an error by invoking <code>Log.complain()</code> method.
+ *
+ * @see Log#complain
+ */
+ public void complain(String message) {
+ log.complain(makeLogMessage(message));
+ }
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class NativeUtils {
+ static {
+ System.loadLibrary("native_utils");
+ }
+
+ public static native long getCurrentPID();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ObjectInstancesManager.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+import java.util.*;
+
+/*
+ * Class create/delete instances with given reference type and given referrers number
+ */
+public class ObjectInstancesManager
+{
+ public static String STRONG_REFERENCE = "STRONG";
+ public static String WEAK_REFERENCE = "WEAK";
+ public static String SOFT_REFERENCE = "SOFT";
+ public static String PHANTOM_REFERENCE = "PHANTOM";
+ public static String JNI_GLOBAL_REFERENCE = "JNI_GLOBAL";
+ public static String JNI_LOCAL_REFERENCE = "JNI_LOCAL";
+ public static String JNI_WEAK_REFERENCE = "JNI_WEAK";
+
+ // used to create references of all types
+ private static String USE_ALL_REFERENCE_TYPES = "ALL_REFERENCE_TYPES";
+
+ private Map<String, Collection<ReferringObjectSet>> instances = new TreeMap<String, Collection<ReferringObjectSet>>();
+
+ public static Set<String> primitiveArrayClassNames = new HashSet<String>();
+
+ static
+ {
+ primitiveArrayClassNames.add("boolean[]");
+ primitiveArrayClassNames.add("byte[]");
+ primitiveArrayClassNames.add("char[]");
+ primitiveArrayClassNames.add("int[]");
+ primitiveArrayClassNames.add("long[]");
+ primitiveArrayClassNames.add("float[]");
+ primitiveArrayClassNames.add("double[]");
+ }
+
+
+ public static Set<String> allReferenceTypes = new HashSet<String>();
+
+ static
+ {
+ allReferenceTypes.add(ObjectInstancesManager.STRONG_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.WEAK_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.SOFT_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE);
+ allReferenceTypes.add(ObjectInstancesManager.JNI_WEAK_REFERENCE);
+ }
+
+ public static boolean isWeak(String type) {
+ return !(type.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE)
+ || type.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE)
+ || type.equals(ObjectInstancesManager.STRONG_REFERENCE));
+
+ }
+
+ public static Log log;
+
+ public ObjectInstancesManager(Log log)
+ {
+ ObjectInstancesManager.log = log;
+ }
+
+ // delete a given number of referrers
+ public void deleteReferrers(String className, int referrersCount, Set<String> referrerTypes)
+ {
+ Collection<ReferringObjectSet> objectInstances;
+
+ objectInstances = instances.get(className);
+
+ if(objectInstances == null)
+ {
+ log.display("Error command 'deleteObjectInstances' is requsted: instances of class " + className + " was not created");
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ return;
+ }
+
+ Iterator<ReferringObjectSet> iterator = objectInstances.iterator();
+
+ while(iterator.hasNext())
+ {
+ ReferringObjectSet debugeeObjectReference = iterator.next();
+ if (referrerTypes.isEmpty() || referrerTypes.contains(debugeeObjectReference.getReferenceType())) {
+ debugeeObjectReference.delete(referrersCount);
+
+ if(debugeeObjectReference.getReferrerCount() == 0)
+ iterator.remove();
+ }
+ }
+ }
+
+ // delete all object referrers, it is equal to make object unreacheable
+ public void deleteAllReferrers(int count, String className)
+ {
+ Collection<ReferringObjectSet> objectInstances;
+
+ objectInstances = instances.get(className);
+
+ if(objectInstances == null)
+ {
+ throw new TestBug("Command 'deleteObjectInstances' is requsted: instances of class " + className + " was not created");
+ }
+
+ Iterator<ReferringObjectSet> iterator = objectInstances.iterator();
+
+ if(count == 0)
+ count = objectInstances.size();
+
+ for(int i = 0; i < count; i++)
+ {
+ ReferringObjectSet debugeeObjectReference = iterator.next();
+ debugeeObjectReference.deleteAll();
+
+ iterator.remove();
+ }
+ }
+
+ // create object instance with referrers of all possible types
+ public void createAllTypeReferences(String className, int count)
+ {
+ createReferences(count, className, 1, allReferenceTypes);
+ }
+
+ // create a given number of object instances with given number of referrers
+ public void createReferences(int count, String className, int referrerCount, Set<String> referrerTypes)
+ {
+ Collection<ReferringObjectSet> objectInstances;
+
+ Class klass = null;
+
+ if(!primitiveArrayClassNames.contains(className))
+ {
+ try
+ {
+ klass = Class.forName(className);
+ }
+ catch(ClassNotFoundException e)
+ {
+ log.display("Can't find class: " + className);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ return;
+ }
+ }
+
+ objectInstances = instances.get(className);
+
+ if(objectInstances == null)
+ {
+ objectInstances = new ArrayList<ReferringObjectSet>();
+ instances.put(className, objectInstances);
+ }
+
+ for(int i = 0; i < count; i++)
+ {
+ try
+ {
+ Object instance;
+
+ if(!primitiveArrayClassNames.contains(className))
+ {
+ instance = klass.newInstance();
+ }
+ else
+ {
+ instance = createPrimitiveTypeArray(className);
+ }
+
+ for(String type : referrerTypes) {
+ objectInstances.add(new ReferringObjectSet(instance, referrerCount, type));
+ }
+ }
+ catch(Exception e)
+ {
+ log.display("Unexpected exception: " + e);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+ }
+
+ public Object createPrimitiveTypeArray(String typeName)
+ {
+ int arraySize = 1;
+
+ if(typeName.equals("boolean[]"))
+ return new boolean[arraySize];
+ else
+ if(typeName.equals("byte[]"))
+ return new byte[arraySize];
+ else
+ if(typeName.equals("char[]"))
+ return new char[arraySize];
+ else
+ if(typeName.equals("int[]"))
+ return new int[arraySize];
+ else
+ if(typeName.equals("long[]"))
+ return new long[arraySize];
+ else
+ if(typeName.equals("float[]"))
+ return new float[arraySize];
+ else
+ if(typeName.equals("double[]"))
+ return new double[arraySize];
+ else
+ {
+ throw new TestBug("Invalid primitive type array type name: " + typeName);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Oddity.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * Oddity exception is used to simulate C/C++ style <code>assert()</code>
+ * facility. It is thrown when an internal contradiction is revealed, which
+ * may do not indicate a bug in the JDI implementation or in the test.
+ */
+public class Oddity extends Failure {
+ /** Explain particular oddity. */
+ public Oddity (String message) {
+ super(message);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Pair.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class Pair<A, B> {
+ final public A first;
+ final public B second;
+
+ private Pair(A first, B second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public static <A, B> Pair<A, B> of(A first, B second) {
+ return new Pair<A, B>(first, second);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + first + ", " + second + ")";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Paragrep.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * Weak emulator of perl's grep function with very small functionality.
+ * This class does not use java.util.regexp classes which appear in
+ * JDK1.4 API.
+ *
+ * @see Grep
+ */
+
+public class Paragrep {
+
+ String[] stringArray;
+ /**
+ * Takes String array as character sequence for matching the pattern.
+ */
+ public Paragrep (String[] stringArray) {
+ this.stringArray = stringArray;
+ }
+
+ /**
+ * Returns number of non-interleaved occurences of the pattern string.
+ */
+ public int find (String pattern) {
+ if (pattern.length() == 0) {
+ throw new Failure("Empty string as input parameter for Grep.find(pattern) method");
+ }
+ int counter = 0;
+ for (int i = 0; i < stringArray.length; i++) {
+
+ String string = stringArray[i];
+ if (string != null) {
+ // Find all non-interleaved occurences of pattern in this string
+ for (int ind = 0; ind < string.length(); ) {
+ int k = 0;
+ if ((k = string.indexOf(pattern, ind)) >= 0) {
+ counter++;
+ ind = k + pattern.length();
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return counter;
+ }
+
+ /**
+ * Returns all string in <code>stringArray</code> which have
+ * occurences of the pattern string.
+ */
+ public String[] findStrings (String pattern) {
+ if (pattern.length() == 0) {
+ throw new Failure("Empty string as input parameter for Grep.find(pattern) method");
+ }
+ Vector<String> v = new Vector<String>();
+ for (int i = 0; i < stringArray.length; i++) {
+ String string = stringArray[i];
+ if (string != null && string.indexOf(pattern) >= 0) {
+ v.add(string);
+ }
+ }
+ String[] result = new String[v.size()];
+ v.toArray(result);
+ return result;
+ }
+
+ /**
+ * Returns first string of stringArray which contains
+ * the pattern string or empty string othrewise.
+ */
+ public String findFirst (String pattern) {
+ if (pattern.length() == 0) {
+ throw new Failure("Empty string as input parameter for Paragrep.findFirst(pattern) method");
+ }
+ String result = "";
+ for (int i = 0; i < stringArray.length; i++) {
+ String string = stringArray[i];
+ if (string != null) {
+ if (string.indexOf(pattern) >= 0) {
+ result = string;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns first string of stringArray which contains
+ * all of the pattern strings or empty string otherwise.
+ */
+ public String findFirst (Vector<String> patternVector) {
+ if (patternVector.isEmpty()) {
+ throw new Failure("Empty vector as input parameter for Paragrep.findFirst(patternVector) method");
+ }
+ String[] patterns = new String[patternVector.size()];
+ patternVector.toArray(patterns);
+ String result = "";
+ for (int i = 0; i < stringArray.length; i++) {
+ String string = stringArray[i];
+ if (string != null && string.length() > 0) {
+ for (int j = 0; j < patterns.length; j++) {
+ String pattern = patterns[j];
+ if (string.indexOf(pattern) >= 0) {
+ if (j + 1 == patterns.length) {
+ // found all patterns in the current string
+ result = string;
+ i = stringArray.length;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns count of strings in stringArray which contain
+ * all of the pattern strings.
+ */
+ public int find (Vector<String> patternVector) {
+ if (patternVector.isEmpty()) {
+ throw new Failure("Empty vector as input parameter for Paragrep.find(patternVector) method");
+ }
+ String[] patterns = new String[patternVector.size()];
+ patternVector.toArray(patterns);
+ int counter = 0;
+
+ for (int i = 0; i < stringArray.length; i++) {
+ String string = stringArray[i];
+ if (string != null && string.length() > 0) {
+ for (int j = 0; j < patterns.length; j++) {
+ String pattern = patterns[j];
+ if (string.indexOf(pattern) >= 0) {
+ if (j + 1 == patterns.length) {
+ // found all patterns in the current string
+ counter++;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return counter;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/PrintProperties.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.Properties;
+
+/**
+ * This program prints system properties.
+ */
+public class PrintProperties {
+ public static void main(String[] args) {
+ Properties pr = System.getProperties();
+ switch (args.length) {
+ case 0:
+ pr.list(System.out);
+ System.exit(0);
+ case 1:
+ String value = pr.getProperty(args[0]);
+ if (value == null) {
+ System.err.println("Not found");
+ System.exit(1);
+ } else {
+ System.out.println(value);
+ System.exit(0);
+ }
+ default:
+ System.out.println("Usage:");
+ System.out.println(" PrintProperties");
+ System.out.println(" PrintProperties <property name>");
+ System.exit(255);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/RASagent.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * Class used as an agent for Java serviceability reliability testing (RAS).
+ * It sets different RAS options and/or modes for a special agent which
+ * actually performs the specified RAS testing.<br>
+ * The agent recognizes arguments, started with ''<code>-ras.</code>''. They
+ * may be as follows:<p>
+ * <li><code>-ras.help</code> - print usage message and exit
+ * <li><code>-ras.verbose</code> - verbose mode
+ * <li><code>-ras.invoke_run</code> - invoke the method <i>run(String[],PrintStream)</i>
+ * of the test instead of <i>main(String[])</i> which is invoked by default.
+ * <li><code>-ras.hotswap=<stress_level></code> - enable JVMTI hotswap of
+ * the currently running test classes. Here are the possible HotSwap stress
+ * levels:<br>
+ * 0 - HotSwap off<br>
+ * 2 - HotSwap tested class in every JVMTI method entry event of running test
+ * (default mode)<br>
+ * 20 - HotSwap tested class in every JVMTI method entry event of every class<br>
+ * 3 - HotSwap tested class in every JVMTI single step event of running test<br>
+ * 4 - HotSwap tested class in every JVMTI exception event of running test<br>
+ * 40 - HotSwap tested class in every JVMTI exception event of every class<p>
+ */
+public class RASagent {
+ static final int HOTSWAP_OFF = 0;
+ static final int HOTSWAP_EVERY_METHOD_ENTRY = 2;
+ static final int HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS = 20;
+ static final int HOTSWAP_EVERY_SINGLE_STEP = 3;
+ static final int HOTSWAP_EVERY_EXCEPTION = 4;
+ static final int HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS = 40;
+
+ // path to the directory with class files of the invoked test
+ static String clfBasePath = null;
+
+ private static boolean verbose = false;
+
+ private static PrintStream out;
+
+ native static int setHotSwapMode(boolean vrb, int stress_lev,
+ String shortName);
+
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new RASagent().runThis(argv, out);
+ }
+
+ private int runThis(String argv[], PrintStream out) {
+ int skipArgs = 1; // number of arguments which must be skipped
+ // for the invoked test
+ boolean invokeRun = false; // invoke the method "main" by default
+ int hotSwapMode = HOTSWAP_EVERY_METHOD_ENTRY; // HotSwap default stress level
+ int res;
+ String hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY";
+
+ RASagent.out = out;
+
+ if (argv.length != 0) {
+ // parse arguments for the RASagent and then skip them
+ while(argv[skipArgs-1].startsWith("-ras.")) {
+ if (argv[skipArgs-1].equals("-ras.verbose")) {
+ verbose = true;
+ } else if (argv[skipArgs-1].equals("-ras.help")) {
+ printHelp();
+ return Consts.TEST_FAILED;
+ } else if (argv[skipArgs-1].equals("-ras.invoke_run")) {
+ invokeRun = true;
+ } else if (argv[skipArgs-1].startsWith("-ras.hotswap=")) {
+ try {
+ hotSwapMode = Integer.parseInt(
+ argv[skipArgs-1].substring(argv[skipArgs-1].lastIndexOf("=")+1));
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ out.println("\nERROR: RASagent: specified HotSwap mode \""
+ + hotSwapMode + "\" is not an integer");
+ printHelp();
+ return Consts.TEST_FAILED;
+ }
+ switch(hotSwapMode) {
+ case HOTSWAP_EVERY_METHOD_ENTRY:
+ hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY";
+ break;
+ case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS:
+ hotSwapModeName = "HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS";
+ break;
+ case HOTSWAP_EVERY_SINGLE_STEP:
+ hotSwapModeName = "HOTSWAP_EVERY_SINGLE_STEP";
+ break;
+ case HOTSWAP_EVERY_EXCEPTION:
+ hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION";
+ break;
+ case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS:
+ hotSwapModeName = "HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS";
+ break;
+ default:
+ out.println("\nERROR: RASagent: specified HotSwap mode \""
+ + hotSwapMode + "\" is unrecognized");
+ printHelp();
+ return Consts.TEST_FAILED;
+ }
+ }
+ skipArgs++;
+ }
+
+ String shortTestName = getTestNameAndPath(argv[skipArgs-1]);
+
+ display("\n#### RASagent: setting hotswap mode \""
+ + hotSwapModeName + "\" for class \""
+ + shortTestName + "\" ...");
+ if ((res = setHotSwapMode(verbose, hotSwapMode, shortTestName)) != 0) {
+ out.println("\nERROR: RASagent: unable to set HotSwap stress level for \""
+ + shortTestName + "\", exiting");
+ return Consts.TEST_FAILED;
+ }
+ display("\n#### RASagent: ... setting hotswap mode done");
+
+ try {
+ Class testCls = Class.forName(argv[skipArgs-1]);
+ display("\n#### RASagent: main class \""
+ + testCls.toString() + "\" loaded");
+
+ // copy arguments for the invoked test
+ String args[] = new String[argv.length-skipArgs];
+ System.arraycopy(argv, skipArgs, args, 0, args.length);
+
+ // invoke the test
+ if (invokeRun)
+ return invokeRunMethod(testCls, args);
+ else
+ return invokeMainMethod(testCls, args);
+ } catch(ClassNotFoundException e) {
+ // just pass: the invoked test is already a RAS specific one
+ out.println("\nWARNING: the test was not really run due to the following error:"
+ + "\n\tunable to get the Class object for \""
+ + argv[skipArgs-1] + "\"\n\tcaught: " + e);
+ return Consts.TEST_PASSED;
+ }
+
+ } else {
+ out.println("\nERROR: RASagent: required test name is absent in parameters list");
+ return Consts.TEST_FAILED;
+ }
+ }
+
+ /**
+ * Verify that test's class file exists with a path given as a parameter
+ * and, if so, store that path in the static field "clfBasePath".
+ */
+ private boolean pathValid(String pathToCheck, String testName) {
+ String fullPath = pathToCheck + File.separator
+ + testName.replace('.', File.separatorChar) + ".class";
+ File classFile = null;
+
+ display("\n#### RASagent: verifying class path\n<RASagent>\t"
+ + pathToCheck + " ...");
+ try {
+ classFile = new File(fullPath);
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ out.println("\nERROR: RASagent: verification of class file "
+ + fullPath + " failed: caught " + e);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ if (classFile.exists()) {
+ clfBasePath = pathToCheck;
+ display("<RASagent>\tthe class file exists:\n<RASagent>\t\t"
+ + fullPath + "\n<RASagent>\tclass file base directory found:\n"
+ + "<RASagent>\t\t" + clfBasePath
+ + "\n#### RASagent: ... class path verification done\n");
+ return true;
+ }
+ else {
+ display("<RASagent>\tno class file at location :\n\t\t"
+ + fullPath
+ + "\n#### RASagent: ... class path verification done\n");
+ return false;
+ }
+ }
+
+ /**
+ * Get short name of an invoked test (i.e. without package name) and
+ * store path to the directory with the test's class files.
+ */
+ private String getTestNameAndPath(String testName) {
+ String shortTestName = testName;
+ String packageName = "";
+
+ // if '.' occurs, it means that current test is inside a package
+ if (testName.lastIndexOf(".") != -1) {
+ shortTestName = testName.substring(testName.lastIndexOf(".")+1);
+ packageName = testName.substring(0, testName.lastIndexOf("."));
+ }
+
+ StringTokenizer clPathes = new StringTokenizer(
+ System.getProperty("java.class.path"), File.pathSeparator);
+
+ while(clPathes.hasMoreTokens()) {
+ String clPath = clPathes.nextToken();
+
+ // trying to load a class file defining the current test from
+ // this entry of "java.class.path": the class file may locate
+ // at the test's work directory or if it's already compiled,
+ // at any directory in classpath
+ if (pathValid(clPath, testName))
+ return shortTestName;
+ }
+
+ // directory with the test's class files was not found.
+ // Actually, it means that the invoked test has own Java
+ // options such as, for example, "-verify"
+ out.println("\nWARNING: the test was not really run due to the following reason:"
+ + "\n\tthe invoked test has the own Java option: "
+ + testName);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);
+
+ return null; // fake return for too smart javac
+ }
+
+ /**
+ * Invoke the method <i>main(String[])</i> of the test.
+ */
+ private int invokeMainMethod(Class testCls, String args[]) {
+ Class[] methType = { String[].class };
+ Object[] methArgs = { args };
+
+ return invokeMethod(testCls, "main", methType, methArgs);
+ }
+
+ /**
+ * Invoke the method <i>run(String[], PrintStream)</i> of the test.
+ */
+ private int invokeRunMethod(Class testCls, String args[]) {
+ Class[] methType = { String[].class, PrintStream.class };
+ Object[] methArgs = { args, out };
+
+ return invokeMethod(testCls, "run", methType, methArgs);
+ }
+
+ /**
+ * Low level invocation of the test.
+ */
+ private int invokeMethod(Class<?> testCls, String methodName,
+ Class methType[], Object methArgs[]) {
+
+ try {
+ Method testMeth = testCls.getMethod(methodName, methType);
+ display("\n#### RASagent: invoking method \""
+ + testMeth.toString() + "\" ...");
+
+ Object result = testMeth.invoke(null, methArgs);
+
+ display("\n#### RASagent: ... invocation of \""
+ + testMeth.toString() + "\" done");
+ if (result instanceof Integer) {
+ Integer retCode = (Integer) result;
+ return retCode.intValue();
+ }
+ } catch(NoSuchMethodException e) {
+ e.printStackTrace();
+ out.println("\nFAILURE: RASagent: unable to get method \""
+ + methodName + "\" in class "
+ + testCls + "\n\tcaught " + e);
+ return Consts.TEST_FAILED;
+ } catch(Exception e) {
+ e.printStackTrace();
+ out.println("\nFAILURE: RASagent: caught during invokation of the test class "
+ + testCls + " " + e);
+ return Consts.TEST_FAILED;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Load class bytes for HotSwap.
+ */
+ static byte[] loadFromClassFile(String signature) {
+ String testPath = clfBasePath + File.separator + signature.substring(
+ 1, signature.length()-1).replace('/', File.separatorChar) + ".class";
+ File classFile = null;
+
+ display("\n#### RASagent: looking for class file\n<RASagent>\t"
+ + testPath + " ...");
+
+ try {
+ classFile = new File(testPath);
+ } catch (NullPointerException e) {
+ out.println("\nFAILURE: RASagent: path name to the redefining class file is null");
+ }
+
+ display("\n#### RASagent: loading " + classFile.length()
+ + " bytes from class file "+ testPath + " ...");
+ byte[] buf = new byte[(int) classFile.length()];
+ try {
+ InputStream in = new FileInputStream(classFile);
+ in.read(buf);
+ in.close();
+ } catch(FileNotFoundException e) {
+ e.printStackTrace();
+ out.println("\nFAILURE: RASagent: loadFromClassFile: file " +
+ classFile.getName() + " not found");
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ } catch (Exception e) {
+ e.printStackTrace();
+ out.println("\nFAILURE: RASagent: unable to load bytes from the file:\n");
+ out.println("\t" + testPath + ": caught " + e);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ display("\n#### RASagent: ... " + classFile.length() + " bytes loaded");
+
+ return buf;
+ }
+
+ /**
+ * This method is used in verbose mode. It prints paramter string only
+ * in case of verbose mode.
+ */
+ private static void display(String msg) {
+ if (verbose)
+ out.println(msg);
+ }
+
+ /**
+ * This method prints out RASagent usage message.
+ */
+ private static void printHelp() {
+ out.println("\nRASagent usage: RASagent [option, ...] test" +
+ "\n\t-ras.help print this message and exit" +
+ "\n\t-ras.verbose verbose mode (off by default)" +
+ "\n\t-ras.hotswap=mode enable HotSwap of the running test classes" +
+ "\n\t\twhere mode is:" +
+ "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY
+ + " - hotswap tested class in its every method entry event" +
+ "\n\t\t\t" + HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS
+ + " - hotswap tested class in every method entry event for every class" +
+ "\n\t\t\t" + HOTSWAP_EVERY_SINGLE_STEP
+ + " - hotswap tested class in its every single step event" +
+ "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION
+ + " - hotswap tested class in its every exception event" +
+ "\n\t\t\t" + HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS
+ + " - hotswap tested class in every exception event for every class\n" +
+ "\n\t-ras.invoke_run invoke the method run() of the test" +
+ "\n\t\tinstead of main() by default");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/README Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,128 @@
+Copyright (c) 2003, 2018, 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.
+
+---------------------------------------------------------------------------------
+
+This directory contains source files of NSK tests framework
+shared between all NSK tests.
+
+Files located directly in this directory provide general support
+for all tests.
+
+Files in the subdirectories provide specific support for tests of
+particular subsuites.
+
+---------------------------------------------------------------------------------
+
+Short description of files:
+
+ common exceptions:
+ Failure,java, TestBug.java, Oddity.java
+ common constants:
+ Consts.java
+ parsing command line arguments:
+ ArgumentPareser.java
+ output of errors and messages:
+ Log.java
+ process running:
+ LocalProcess.java, IORedirector.java
+ class loading/unloading:
+ DummyClassLoader.java, ZipClassLoader.java,
+ CustomClassLoader.java, ClassUnloder.java
+ objects finalization:
+ Finalizable.java, FinalizableObject.java, Finalizer.java
+ threads synchronization:
+ Wicket.java
+ text processing:
+ Grep.java, Paragrep.java
+ timeouts handling:
+ Harakiri.java, TimeoutHandler.java
+ tree structures support:
+ Denotation.java, TreeNodesDenotation.java
+ RAS mode support:
+ RASagent.java, JVMTIagent.c
+ JVMDI tests support:
+ JVMDITools.h, JVMDITools.c
+
+Short description of subdirectories:
+
+ Alien - support for accessing external tests (JCK)
+ native - support for native part of NSK tests
+ jni - support for JNI tests and accessing JNI API
+ jvmti - support for JVMTI tests and accessing JVMTI API
+ jpda - support for two-VMs JPDA tests
+ jdwp - support for JDWP tests and accessing JDWP API
+ jdi - support for JDI tests and accesing JDI API
+ jdb - support for JDB tests and accessing JDB tool
+ monitoring - support for monitoring tests and accessing Java Monitoring&Management API
+ sysdict - support for System Dictionary tests
+ gc - support for GC tests
+ regression - support for regression tests for known bugs
+ split_verifier - support for Split Verifier tests
+
+For more detailed description see README files in subdirectories.
+
+---------------------------------------------------------------------------------
+
+Naming conventions
+
+Classes:
+
+ All shared classes are groupped into packages to prevent
+ name collision.
+
+ All classes exported directly from this directory are
+ of package:
+
+ nsk.share
+
+ All classes exported from subdirectories are of particular
+ subpackage, e.g.:
+
+ nsk.share.jpda
+ nsk.share.jdwp
+ nsk.share.jdi
+ nsk.share.jdb
+ nsk.share.monitoring
+ nsk.share.sysdict
+
+Native functions and macroses:
+
+ Most native functions have special prefix to prevent linking collisions.
+ Most macroses also have special prefix and are wrote in upper register.
+
+ Here is typical naming scheme used for native functions and macroses:
+
+ share/native
+ functions: nsk_*
+ macroses: NSK_*
+
+ share/jni
+ functions: nsk_jni_*
+ macroses: NSK_JNI_*
+
+ share/jvmti
+ functions: nsk_jvmti_*
+ macroses: NSK_JVMTI_*
+
+ However, some native functions and macroses do not follow this scheme,
+ in order to preserve compatibility with old tests.
+
+---------------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+
+/*
+ * This class create/delete reference with given type.
+ *
+ * Supported reference types are:
+ * - strong
+ * - soft
+ * - weak
+ * - phantom
+ * - jni local
+ * - jni global
+ * - jni weak
+ */
+public class ReferringObject
+{
+ static
+ {
+ System.loadLibrary("JNIreferences");
+ }
+
+ public final static int maxJNIGlobalReferences = 1000;
+ public final static int maxJNIWeakReferences = 1000;
+
+ private Object reference;
+
+ private String referenceType;
+
+ //used for storing jni global and jni weak references
+ private int referenceIndex;
+
+ public ReferringObject(Object object, String referenceType)
+ {
+ this.referenceType = referenceType;
+
+ if(referenceType.equals(ObjectInstancesManager.STRONG_REFERENCE))
+ {
+ createStrongReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.SOFT_REFERENCE))
+ {
+ createSoftReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.WEAK_REFERENCE))
+ {
+ createWeakReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.PHANTOM_REFERENCE))
+ {
+ createPhantomReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE))
+ {
+ createJNIGlobalReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE))
+ {
+ createJNILocalReference(object);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_WEAK_REFERENCE))
+ {
+ createJNIWeakReference(object);
+ }
+ else
+ throw new IllegalArgumentException("Invalid reference type: " + referenceType);
+ }
+
+ public void delete()
+ {
+ if(referenceType == null)
+ {
+ throw new TestBug("Reference type is null");
+ }
+
+ if(referenceType.equals(ObjectInstancesManager.SOFT_REFERENCE))
+ {
+ if(reference == null)
+ {
+ throw new TestBug("Reference is null for SoftReference");
+ }
+
+ if(((SoftReference)reference).get() == null)
+ {
+ // throw new TestBug("Test execution error: SoftReference was collected");
+ }
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.WEAK_REFERENCE))
+ {
+ if(reference == null)
+ {
+ throw new TestBug("Reference is null for WeakReference");
+ }
+
+ if(((WeakReference)reference).get() == null)
+ {
+ // throw new TestBug("Test execution error: WeakReference was collected");
+ }
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.PHANTOM_REFERENCE))
+ {
+ if(reference == null)
+ {
+ throw new TestBug("Reference is null for PhantomReference");
+ }
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_GLOBAL_REFERENCE))
+ {
+ deleteJNIGlobalReferenceNative(referenceIndex);
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_LOCAL_REFERENCE))
+ {
+ deleteJNILocalReference();
+ }
+ else
+ if(referenceType.equals(ObjectInstancesManager.JNI_WEAK_REFERENCE))
+ {
+ try {
+ deleteJNIWeakReferenceNative(referenceIndex);
+ } catch (Throwable t)
+ {
+
+ }
+ }
+
+ reference = null;
+ }
+
+ private void createStrongReference(Object object)
+ {
+ reference = object;
+ }
+
+ private void createSoftReference(Object object)
+ {
+ reference = new SoftReference<Object>(object);
+ }
+
+ private void createWeakReference(Object object)
+ {
+ reference = new WeakReference<Object>(object);
+ }
+
+ private void createPhantomReference(Object object)
+ {
+ reference = new PhantomReference<Object>(object, new ReferenceQueue<Object>());
+ }
+
+ private void createJNIGlobalReference(Object object)
+ {
+ referenceIndex = createJNIGlobalReferenceNative(object, maxJNIGlobalReferences);
+
+ if(referenceIndex < 0)
+ {
+ throw new TestBug("Error on creation of JNI_Global reference, Possible number of JNI_Global references exceeded max available value!");
+ }
+ }
+
+ /*
+ * Since jni local reference valid only for duration of native method call, to create jni local reference
+ * special thread is created which enter in native method, create jni local reference and wait
+ */
+ private void createJNILocalReference(Object object)
+ {
+ this.reference = object;
+
+ jniLocalReferenceThread = new JNILocalReferenceThread();
+ jniLocalReferenceThread.start();
+
+ // wait till JNI local reference will be created
+ jniLocalReferenceThread.createWhicket.waitFor();
+
+ reference = null;
+ }
+
+ private void deleteJNILocalReference()
+ {
+ // notify JNI method that JNI local reference is not needed any more and could be released
+ jniLocalReferenceThread.deleteWhicket.unlock();
+
+ try
+ {
+ jniLocalReferenceThread.join(1000 * 60 * 2);
+
+ if(jniLocalReferenceThread.isAlive())
+ {
+ throw new TestBug("JNI_Local_Reference thread can't finish execution");
+ }
+ }
+ catch(InterruptedException e)
+ {
+ throw new TestBug("deleteJNILocalReference was interrupted");
+ }
+ }
+
+ private void createJNIWeakReference(Object object)
+ {
+ referenceIndex = createJNIWeakReferenceNative(object, maxJNIWeakReferences);
+
+ if(referenceIndex < 0)
+ {
+ throw new TestBug("Error on creation of JNI_Weak reference. Possible number of JNI_Weak references exceeded max available value!");
+ }
+ }
+
+ class JNILocalReferenceThread
+ extends Thread
+ {
+ Wicket createWhicket = new Wicket();
+ Wicket deleteWhicket = new Wicket();
+
+ public void run()
+ {
+ createJNILocalReferenceNative(reference, createWhicket, deleteWhicket);
+ }
+ }
+
+ private JNILocalReferenceThread jniLocalReferenceThread;
+
+ private native int createJNIGlobalReferenceNative(Object object, int maxJNIGlobalReferences);
+
+ private native void deleteJNIGlobalReferenceNative(int index);
+
+ private native void createJNILocalReferenceNative(Object object, Wicket createWhicket, Wicket deleteWhicket);
+
+ private native int createJNIWeakReferenceNative(Object object, int maxJNIWeakReferences);
+
+ private native void deleteJNIWeakReferenceNative(int index);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ReferringObjectSet.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/*
+ * Class create a number of referrers to given object
+ */
+public class ReferringObjectSet
+{
+ private Collection<ReferringObject> referringObjects;
+ private String referenceType;
+
+ public ReferringObjectSet(Object object, int referringCount, String referenceType)
+ {
+ this.referenceType = referenceType;
+ referringObjects = new ArrayList<ReferringObject>(referringCount);
+
+ for(int i = 0; i < referringCount; i++)
+ referringObjects.add(new ReferringObject(object, referenceType));
+ }
+
+ public void delete(int count)
+ {
+ if((count < 0) || (count > referringObjects.size()))
+ {
+ throw new TestBug("Invalid 'count' value: " + count + ", size=" + referringObjects.size());
+ }
+
+ Iterator<ReferringObject> iterator = referringObjects.iterator();
+
+ for(int i = 0; i < count; i++)
+ {
+ ReferringObject referringObject = iterator.next();
+ referringObject.delete();
+
+ iterator.remove();
+ }
+ }
+
+ public void deleteAll()
+ {
+ delete(referringObjects.size());
+ }
+
+ public String getReferenceType() {
+ return referenceType;
+ }
+
+ public int getReferrerCount()
+ {
+ return referringObjects.size();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/StringGoldChecker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class StringGoldChecker extends AbstractGoldChecker {
+
+ private final String goldenString;
+
+ public StringGoldChecker(String goldenString) {
+ this.goldenString = goldenString;
+ }
+
+ @Override
+ protected String getGoldenString() {
+ return goldenString;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestBug.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+/**
+ * Thrown when it becomes obvious that the test algorithm
+ * works incorrectly (for example - tries to write to debugee's
+ * stdin after it is already redirected, or something of the
+ * kind).
+ */
+public class TestBug extends Failure {
+ /** Explain particular failure. */
+ public TestBug(String message) {
+ super(message);
+ }
+
+ /** Enwrap another throwable. */
+ public TestBug(Throwable throwable) {
+ super(throwable);
+ }
+
+ public TestBug(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestFailure.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class TestFailure extends RuntimeException {
+ public TestFailure() {
+ super();
+ }
+
+ public TestFailure(String message) {
+ super(message);
+ }
+
+ public TestFailure(String message, Throwable e) {
+ super(message, e);
+ }
+
+ public TestFailure(Throwable e) {
+ super(e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TestJNIError.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share;
+
+public class TestJNIError
+ extends Error
+{
+ public TestJNIError(String message)
+ {
+ super(message);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TimeoutHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.*;
+
+/**
+ * This class can be used to set timeout for test execution.
+ */
+public class TimeoutHandler {
+
+ /**
+ * Test execution timeout in minutes.
+ */
+ private int waitTime;
+
+ /**
+ * Make new <code>TimeoutHandler</code> object for timeout value
+ * specified in command line arguments.
+ */
+ public TimeoutHandler(ArgumentParser argumentHandler) {
+ this.waitTime = argumentHandler.getWaitTime();
+ }
+
+ /**
+ * Perform test execution in separate thread and wait for
+ * thread finishes or timeout exceeds.
+ */
+ public void runTest(Thread testThread) {
+ long millisec = waitTime * 60 * 1000;
+ testThread.start();
+ try {
+ testThread.join(millisec);
+ } catch (InterruptedException ex) {
+ throw new Failure(ex);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/TreeNodesDenotation.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.util.*;
+
+/**
+ * This denotation provides naming and indexing for nodes
+ * of a binary, or ternary, or <tt>n</tt>-ary tree.
+ *
+ * <p>Here, <tt>n</tt> would be the length of a symbols
+ * string used as an alphabeth for nodes naming. For a
+ * binary tree, <tt>n=2</tt>, and an aplhabeth could be
+ * the <tt>"LR"</tt> string. This implies the following
+ * naming for tree nodes:
+ * <pre>
+ * (empty)
+ * / \
+ * L R
+ * / \ / \
+ * LL LR RL RR
+ * / \ / \ / \ / \
+ * </pre>
+ *
+ * <p>Anyway, the tree root node is named with the empty
+ * string <tt>""</tt> and is indexed with 2-zeroes array
+ * <tt>{0,0}</tt>.
+ *
+ * <p>Index for a tree node is 2-elements <tt>int[]</tt>
+ * array. The 1st element is the node's level in a tree.
+ * The 2nd element is the item's number among all nodes of
+ * that level; provided that node items are enumerated from
+ * <tt>0</tt> to <tt>n</tt><sup>level</sup><tt>-1</tt>.
+ * Given a level, lexicographic order is assumed for the
+ * nodes of the same level.
+ *
+ * <p>For example: given the above sample tree, the node
+ * <tt>"L"</tt> has the index <tt>{1,0}</tt>, while the
+ * node <tt>"RL"</tt> has the index <tt>{2,2}</tt>.
+ *
+ * <p>In general case, ordering of characters used for nodes
+ * naming is implied by the given alphabeth. This may differ
+ * from the ``natural'' ordering. For example, if alphabeth
+ * is <tt>"ZYX...CBA"</tt>, then ordering for nodes would be
+ * opposite to ``natural''.
+ */
+public class TreeNodesDenotation extends Denotation {
+ /**
+ * Symbols to denote tree nodes.
+ *
+ * @see #TreeNodeDenotation(String)
+ */
+ private String alphabeth;
+
+ /**
+ * Standard denotation for a binary tree; alphabeth
+ * is <tt>"LR"</tt>.
+ *
+ * @see #TreeNodesDenotation(String)
+ */
+ public TreeNodesDenotation() {
+ this("LR");
+ }
+
+ /**
+ * Denotation for nodes of a tree.
+ *
+ * <p>Each tree node is marked with a string of symbols
+ * from the given <tt>alphabeth</tt>. A string length
+ * equals to the node's level. The root node is always
+ * denoted with the empty string.
+ *
+ * <p>For example, an <tt>alphabeth</tt> for a binary
+ * tree could be <tt>"LR"</tt>, or <tt>"01"</tt>, or
+ * any 2-symbols string. However, <tt>"lL"</tt> or
+ * <tt>"rR"</tt> would be illegal because of collision
+ * between upper- and lower- case letters.
+ *
+ * <p>In general case, it is illegal for <tt>alphabeth</tt>
+ * to contain two or several copies of the same symbol.
+ * This constructor deems lower- and upper-case variants
+ * of the same letter are the same symbol.
+ *
+ * @throws IllegalArgumentException If the <tt>alphabeth</tt>
+ * looks illegal.
+ */
+ public TreeNodesDenotation(String alphabeth) {
+ if (alphabeth.length() == 0)
+ throw new IllegalArgumentException("empty alphabeth");
+ // Check for lower- to upper- case collision:
+ this.alphabeth = alphabeth.toUpperCase();
+ int length = this.alphabeth.length();
+ Set<Character> pool = new HashSet<Character>(); // still empty
+ for (int i=0; i<length; i++)
+ pool.add(new Character(this.alphabeth.charAt(i)));
+ if (pool.size() != length)
+ throw new IllegalArgumentException("collision: " + alphabeth);
+ }
+
+ /**
+ * Check if the <tt>name</tt> is legal, and return the
+ * numeric index for the tree node denoted by the given
+ * <tt>name</tt>.
+ *
+ * @throws IllegalArgumentException If the <tt>name</tt>
+ * is illegal.
+ */
+ public int[] indexFor(String name) {
+ int level = name.length();
+ int factor = alphabeth.length();
+ long item = 0;
+ for (int i=0; i<level; i++) {
+ char symbol = Character.toUpperCase(name.charAt(i));
+ int position = alphabeth.indexOf(symbol);
+ if (position < 0)
+ throw new IllegalArgumentException("unknown symbol: " + name);
+ item = item*factor + position;
+ if (item < 0 || item > Integer.MAX_VALUE)
+ throw new IllegalArgumentException("too long name: " + name);
+ };
+ int[] index = new int [] { level, (int)item };
+ return index;
+ }
+
+ /**
+ * Check if the <tt>index[]</tt> is legal, and return
+ * a symbolic name for the tree node denoted by the
+ * given <tt>index[]</tt>.
+ *
+ * @throws IllegalArgumentException If the <tt>index[]</tt>
+ * is illegal.
+ */
+ public String nameFor(int[] index) {
+ if (index.length != 2)
+ throw new IllegalArgumentException(
+ "index dimention: " + index.length);
+ StringBuffer name = new StringBuffer(); // still empty
+ int level = index[0];
+ int item = index[1];
+ if (level < 0 || item < 0)
+ throw new IllegalArgumentException(
+ "negative index: " + level + ", " + item);
+ int factor = alphabeth.length();
+ for (int i=0; i<level; i++) {
+ int k = item % factor;
+ name.append(alphabeth.charAt(k));
+ item = item / factor;
+ };
+ if (item != 0)
+ throw new IllegalArgumentException(
+ "out of range: {"+ index[0] + "," + index[1] + "}");
+ return new String(name.reverse());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Wicket.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share;
+
+import java.io.PrintStream;
+
+/**
+ * Wicket provides a means for one or more threads to suspend execution
+ * (to wait) until notified by one or more other threads that some set
+ * of locks is now open.
+ *
+ * <p>Wicket instances are intended to be used generally in the following
+ * scenarios:
+ *
+ * <ul><li>One thread starts one or more child threads and waits until the
+ * child threads to be started.
+ *
+ * <li>One thread starts one or more child threads and waits until at least
+ * one of the child threads to be started.
+ *
+ * <li>One or more child threads wait until a main thread lets them
+ * to finish.
+ *
+ * <li>Disable the current thread for thread scheduling purposes, for up to
+ * the specified waiting time.</ul>
+ */
+
+public class Wicket {
+
+ /** Number of closed locks, can be greater or equal to zero */
+ private int count;
+
+ /** Number of waiters **/
+ private int waiters = 0;
+
+ /** Enable debug output */
+ private PrintStream debugOutput = null;
+
+ /** Wicket's string identifier */
+ private String name = "";
+
+ /**
+ * Construct a Wicket with only one closed lock.
+ */
+ public Wicket() {
+ this(1);
+ }
+
+ /**
+ * Construct a Wicket with the given number of closed locks.
+ *
+ * @param _name Wicket's identifier
+ * @param _count the initial number of closed locks
+ * @param _debugOutput whether to print debug info or not
+ * @throws IllegalArgumentException if count is less than 1
+ */
+ public Wicket(String _name, int _count, PrintStream _debugOutput) {
+ this(_count);
+ name = _name;
+ debugOutput = _debugOutput;
+ }
+
+ /**
+ * Construct a Wicket with the given number of closed locks.
+ *
+ * @param count the initial number of closed locks
+ * @throws IllegalArgumentException if count is less than 1
+ */
+ public Wicket(int count) {
+ if (count < 1)
+ throw new IllegalArgumentException(
+ "count is less than one: " + count);
+ this.count = count;
+ }
+
+ /**
+ * Wait for all locks of this Wicket to be open.
+ *
+ * <p>If all locks are already open then returns immediately.
+ *
+ * <p>If at least one lock is still closed then the current thread becomes
+ * disabled for thread scheduling purposes and lies dormant until all
+ * the locks will be open by some other threads. One lock can be open
+ * by invoking the unlock method for this Wicket.
+ *
+ * <p>Please note, that the method would ignore Thread.interrupt() requests.
+ */
+ public synchronized void waitFor() {
+ ++waiters;
+ if (debugOutput != null) {
+ debugOutput.printf("Wicket %s: waitFor()\n", name);
+ }
+
+ while (count > 0) {
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ }
+ --waiters;
+ }
+
+ /**
+ * Wait for all locks of this Wicket to be open within the given
+ * period of time.
+ *
+ * <p>If all locks are already open then returns immediately with zero.
+ *
+ * <p>If the time is equal to zero, the method will not
+ * wait and returns a number of closed locks,
+ * if all locks are open, the return value is zero.
+ *
+ * <p>If at least one lock is still closed then the current thread becomes
+ * disabled for thread scheduling purposes and lies dormant until
+ * of the two things happens:
+ *
+ * <ul><li>Some other threads invoke the unlock method for this Wicket
+ * to open all the closed locks; or
+ *
+ * <li>The specified waiting time elapses.</ul>
+ *
+ * <p>If all locks are open then the return value is 0.
+ *
+ * <p>If the specified waiting time elapses and some locks are still closed
+ * then the return value is equal to number of closed locks.
+ *
+ * <p>Please note, that the method would ignore Thread.interrupt() requests.
+ *
+ * @param timeout the maximum time to wait in milliseconds
+ * @return the number of closed locks
+ * @throws IllegalArgumentException if timeout is less than 0
+ */
+ public synchronized int waitFor(long timeout) {
+ if (debugOutput != null) {
+ debugOutput.printf("Wicket %s: waitFor(%d)\n", name, timeout);
+ }
+
+ if (timeout < 0)
+ throw new IllegalArgumentException(
+ "timeout value is negative: " + timeout);
+ ++waiters;
+ long waitTime = timeout;
+ long startTime = System.currentTimeMillis();
+ while (count > 0 && waitTime > 0) {
+ try {
+ wait(waitTime);
+ } catch (InterruptedException e) {}
+ waitTime = timeout - (System.currentTimeMillis() - startTime);
+ }
+ --waiters;
+ return (count);
+ }
+
+ /**
+ * Unlock one closed lock.
+ *
+ * <p>Open a lock, reducing the number of closed locks by one.
+ *
+ * <p>If last closed lock is opened then all of the threads waiting
+ * by invoking the waitFor method for this Wicket will be released
+ * and re-enabled for thread scheduling purposes.
+ *
+ * @throws IllegalStateException if there is no one closed lock
+ */
+ public synchronized void unlock() {
+ if (debugOutput != null) {
+ debugOutput.printf("Wicket %s: unlock()\n", name);
+ }
+
+ if (count == 0)
+ throw new IllegalStateException("locks are already open");
+
+ --count;
+ if (count == 0) {
+ notifyAll();
+ }
+ }
+
+ /**
+ * Unlock all closed locks.
+ *
+ * <p>Open all closed locks, setting the number of closed locks to zero.
+ *
+ * <p>If any threads are waiting by invoking the waitFor method for
+ * this Wicket then they will be released and re-enabled for thread
+ * scheduling purposes.
+ */
+ public synchronized void unlockAll() {
+ if (debugOutput != null) {
+ debugOutput.printf("Wicket %s: unlockAll()\n", name);
+ }
+
+ count = 0;
+ notifyAll();
+ }
+
+ /**
+ * Return current number of waiters - threads that are currently
+ * waiting using one of waitFor methods.
+ *
+ * @return number of waiters
+ */
+ public synchronized int getWaiters() {
+ if (debugOutput != null) {
+ debugOutput.printf("Wicket %s: getWaiters()\n", name);
+ }
+ return waiters;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODRunnerArgParser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import nsk.share.*;
+import java.util.*;
+
+public class AODRunnerArgParser extends ArgumentParser {
+
+ public static final String jarAgentParam = "ja";
+
+ public static final String nativeAgentParam = "na";
+
+ public static final String targetAppParam = "target";
+
+ public static final String javaOptsParam = "javaOpts";
+
+ public static final String testedJdkParam = "jdk";
+
+ private static List<String> supportedOptions;
+
+ static {
+ supportedOptions = new ArrayList<String>();
+ supportedOptions.add(jarAgentParam);
+ supportedOptions.add(nativeAgentParam);
+ supportedOptions.add(targetAppParam);
+ supportedOptions.add(javaOptsParam);
+ supportedOptions.add(testedJdkParam);
+ }
+
+ private List<AgentInformation> agents;
+
+ public AODRunnerArgParser(String[] args) {
+ super(args);
+ }
+
+ protected boolean checkOption(String option, String value) {
+ if (super.checkOption(option, value))
+ return true;
+
+ if (!supportedOptions.contains(option))
+ return false;
+
+ if (option.equals(jarAgentParam)) {
+ addAgentInfo(true, value);
+ }
+
+ if (option.equals(nativeAgentParam)) {
+ addAgentInfo(false, value);
+ }
+
+ return true;
+ }
+
+ protected void checkOptions() {
+ if (agents == null) {
+ agents = new ArrayList<AgentInformation>();
+ }
+ }
+
+ private void addAgentInfo(boolean jarAgent, String unsplittedAgentsString) {
+ if (agents == null) {
+ agents = new ArrayList<AgentInformation>();
+ }
+
+ String agentStrings[];
+
+ if (unsplittedAgentsString.contains(","))
+ agentStrings = unsplittedAgentsString.split(",");
+ else
+ agentStrings = new String[]{unsplittedAgentsString};
+
+ for (String agentString : agentStrings) {
+ int index = agentString.indexOf('=');
+
+ if (index > 0) {
+ String pathToAgent = agentString.substring(0, index);
+ String options = agentString.substring(index + 1);
+ agents.add(new AgentInformation(jarAgent, pathToAgent, options));
+ } else {
+ agents.add(new AgentInformation(jarAgent, agentString, null));
+ }
+ }
+ }
+
+ public String getTargetApp() {
+ if (!options.containsKey(targetAppParam))
+ throw new TestBug("Target application isn't specified");
+
+ return options.getProperty(targetAppParam);
+ }
+
+ public String getTestedJDK() {
+ if (!options.containsKey(testedJdkParam))
+ throw new TestBug("Tested JDK isn't specified");
+
+ return options.getProperty(testedJdkParam);
+ }
+
+ public String getJavaOpts() {
+ return options.getProperty(javaOptsParam, "");
+ }
+
+ public List<AgentInformation> getAgents() {
+ return agents;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTargetArgParser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import nsk.share.*;
+import java.util.*;
+
+public class AODTargetArgParser extends ArgumentParser {
+
+ public static final String agentsNumberParam = "agentsNumber";
+
+ public static final String socketPortParam = "port";
+
+ private int expectedAgentsNumber;
+
+ private int port;
+
+ private static List<String> supportedOptions;
+
+ static {
+ supportedOptions = new ArrayList<String>();
+ supportedOptions.add(agentsNumberParam);
+ supportedOptions.add(socketPortParam);
+ }
+
+ public AODTargetArgParser(String[] args) {
+ super(args);
+ }
+
+ protected boolean checkOption(String option, String value) {
+ if (super.checkOption(option, value))
+ return true;
+
+ if (!supportedOptions.contains(option))
+ return false;
+
+ if (option.equals(agentsNumberParam)) {
+ expectedAgentsNumber = Integer.parseInt(value);
+ if (expectedAgentsNumber < 0)
+ throw new TestBug("Invalid value of '" + option + "'");
+ } else if (option.equals(socketPortParam)) {
+ port = Integer.parseInt(value);
+ if (port <= 0 || port > 65535)
+ throw new TestBug("Invalid value of '" + option + "':" + port +" (it is expected to be in the range [1..65535]");
+ }
+
+ return true;
+ }
+
+ public int getExpectedAgentsNumber() {
+ if (!options.containsKey(agentsNumberParam))
+ throw new TestBug("Number of expected agents isn't specified");
+
+ return expectedAgentsNumber;
+ }
+
+ public int getPort() {
+ if (!options.containsKey(socketPortParam))
+ return -1;
+
+ return port;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import java.io.*;
+import nsk.share.*;
+import nsk.share.jpda.SocketIOPipe;
+
+/*
+ Class AODTestRunner is part of the framework used in the AttachOnDemand tests
+ (tests against Attach API, API from package com.sun.tools.attach).
+
+ AODTestRunner is used as main class in AttachOnDemand tests, it performs following
+ actions:
+ - starts target application
+
+ - finds VM id for target VM (this id is needed for dynamic attach)
+
+ - by default AODTestRunner tries to attach specified via command line agents to target VM
+ (subclasses can override this default behavior)
+
+ - waits for target application completion
+
+Target application class, agents that should be attached, JDK used to run target application and
+VM options passed to target VM should be specified via command line.
+ */
+public class AODTestRunner {
+
+ public static final String targetAppIdProperty = "vmsqe.aod.targetAppId";
+ public static final String appIdProperty = "vmsqe.aod.AppId";
+
+ public static final long TARGET_APP_CONNECT_TIMEOUT = 5 * 60 * 1000; // 5 min
+
+ public static final long TARGET_APP_WORK_TIMEOUT = 30 * 60 * 1000; // 30 min (standard VM testbase test timeout)
+
+ protected Log log;
+
+ protected SocketIOPipe pipe;
+
+ protected ProcessExecutor targetAppExecutor;
+
+ // target application ready for attach
+ public static final String SIGNAL_READY_FOR_ATTACH = "ready";
+
+ // target application may finish execution
+ public static final String SIGNAL_FINISH = "finish";
+
+ protected AODRunnerArgParser argParser;
+
+ protected AODTestRunner(String[] args) {
+ log = new Log(System.out, true);
+
+ argParser = createArgParser(args);
+ }
+
+ /*
+ * This method is introduced to let subclasses to create its own parsers
+ */
+ protected AODRunnerArgParser createArgParser(String[] args) {
+ return new AODRunnerArgParser(args);
+ }
+
+ protected void doTestActions(String targetVMId) throws Throwable {
+ AgentsAttacher attacher = new AgentsAttacher(targetVMId, argParser.getAgents(), log);
+ attacher.attachAgents();
+ }
+
+ protected String getCurrentVMId() {
+ String currentVMId = "" + ProcessHandle.current().pid();
+ log.display("Current VM id was identified: " + currentVMId);
+
+ return currentVMId;
+ }
+
+ protected void runTest() {
+
+ try {
+ String targetAppId = System.getProperty(targetAppIdProperty);
+ if(targetAppId == null || targetAppId.isEmpty()) {
+ // use PID as default appID
+ targetAppId = "" + ProcessHandle.current().pid();
+ }
+ /*
+ * Create target application id required by the Utils.findVMIdUsingJPS
+ */
+ String targetAppCmd =
+ // path to java
+ argParser.getTestedJDK() + File.separator + "bin" + File.separator + "java " +
+ // VM property to identify VM running target application
+ "-D" + appIdProperty + "=" + targetAppId + " " +
+ // VM opts
+ argParser.getJavaOpts() + " -XX:+EnableDynamicAgentLoading " +
+ // target application class
+ argParser.getTargetApp() + " " +
+ // additional target application parameter - number of
+ // agents that will be attached
+ "-" + AODTargetArgParser.agentsNumberParam + " " + argParser.getAgents().size();
+
+ pipe = SocketIOPipe.createServerIOPipe(log, 0, TARGET_APP_CONNECT_TIMEOUT);
+ targetAppCmd += " -" + AODTargetArgParser.socketPortParam + " " + pipe.getPort();
+
+ log.display("Starting target application: " + targetAppCmd);
+ targetAppExecutor = new ProcessExecutor(targetAppCmd, TARGET_APP_WORK_TIMEOUT, "TargetApp");
+ targetAppExecutor.startProcess();
+
+ /*
+ * Don't try to attach agents until target application isn't initialized
+ */
+ String signal = pipe.readln();
+ log.display("Signal received: '" + signal + "'");
+ if ((signal == null) || !signal.equals(SIGNAL_READY_FOR_ATTACH))
+ throw new TestBug("Unexpected TargetApplication signal: '" + signal + "'");
+
+ String targetVMId = Long.toString(targetAppExecutor.pid());
+ log.display("Target VM id was identified: " + targetVMId);
+
+ doTestActions(targetVMId);
+
+ /*
+ * When test actions finished let target application finish execution
+ */
+ log.display("Sending signal: '" + SIGNAL_FINISH + "'");
+ pipe.println(SIGNAL_FINISH);
+
+ targetAppExecutor.waitForProcess();
+
+ File file = new File(targetAppId);
+ if (file.exists()) {
+ file.deleteOnExit();
+ }
+
+ if (targetAppExecutor.getExitCode() != 0) {
+ throw new Failure("Target application finished with non-zero code " + targetAppExecutor.getExitCode());
+ }
+
+ postTargetExitHook();
+
+ } catch (Failure f) {
+ throw f;
+ } catch (Throwable t) {
+ throw new Failure("Unexpected exception during test execution: " + t, t);
+ } finally {
+ if (pipe != null) {
+ pipe.close();
+ }
+ if (targetAppExecutor != null) {
+ targetAppExecutor.destroyProcess();
+ }
+ }
+ }
+
+ /*
+ * Allow users of this class to specify actions to be taken after the target exits
+ */
+ protected void postTargetExitHook() {
+ // do nothing by default
+ }
+
+ public static String createApplicationId() {
+ return new Long(System.currentTimeMillis()).toString();
+ }
+
+ public static void main(String[] args) {
+ new AODTestRunner(args).runTest();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import java.lang.instrument.*;
+import java.io.*;
+import nsk.share.*;
+
+/*
+
+AbstractJarAgent is base class for java agents used in AttachOnDemand tests
+(tests against Attach API, API from package com.sun.tools.attach).
+
+In all AttachOnDemand tests the same algorithm is used:
+ - java application where agent is loaded to (target application) based on
+ class nsk.share.aod.TargetApplicationWaitingAgents starts and waits when
+ test agents will be loaded
+
+ - special application (nsk.share.jvmti.aod.AgentsAttacher) loads test agents
+ in the target application using Attach API
+
+ - when agent is loaded it notifies target application about that and executes
+ test-specific actions. When agent execution is completed it also notifies
+ target application about that
+
+ - when all test agents finish execution target application checks its status
+ (passed or failed) and also finishes
+
+Each java agent should have method 'agentmain' where only agent initialization should be done,
+main agent's actions should be executed in special thread started from 'agentmain'.
+Class AbstractJarAgent incapsulates actions common for all java agents: agent initialization,
+starting thread executing agent's actions and communication with target application.
+
+In most cases test agents should override only method 'agentActions' and its 'agentmain'
+should contain only call of the method 'AbstractJarAgent.runJarAgent'.
+
+Typical agent class looks like this:
+
+public class agentExample extends AbstractJarAgent {
+
+ protected void init(String[] args) {
+ // parse agent's options and do test-specific initialization
+ }
+
+ protected void agentActions() {
+ // do test specific actions
+ }
+
+ public static void agentmain(final String options, Instrumentation inst) {
+ new agentExample().runJarAgent(options, inst);
+ }
+}
+ */
+abstract public class AbstractJarAgent {
+
+ private boolean finishedSuccessfully = true;
+
+ private Log log;
+
+ protected void display(String message) {
+ log.display(outputPrefix + message);
+ }
+
+ protected void complain(String message) {
+ log.complain(outputPrefix + message);
+ }
+
+ protected void logThrowable(Throwable t) {
+ t.printStackTrace(log.getOutStream());
+ }
+
+ /*
+ * Instrumentation object passed to the 'agentmain' method
+ */
+ protected Instrumentation inst;
+
+ private String name;
+
+ private String outputPrefix;
+
+ private String pathToNewByteCode;
+
+ protected String pathToNewByteCode() {
+ return pathToNewByteCode;
+ }
+
+ /*
+ * Subclasses should report about test failures using this method
+ */
+ protected void setStatusFailed(String errorMessage) {
+ finishedSuccessfully = false;
+ complain("ERROR: " + errorMessage);
+ }
+
+ /*
+ * Initialization method, called from agentmain before method agentActions is called
+ * (it introduced for overriding in subclasses)
+ */
+ protected void init(String[] args) {
+ }
+
+ protected static class AgentOption {
+ public String name;
+ public String value;
+ public AgentOption(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
+
+ protected AgentOption parseAgentArgument(String arg) {
+ int index = arg.indexOf('=');
+ if (index <= 0) {
+ throw new TestBug("Invalid agent parameters format");
+ }
+ return new AgentOption(arg.substring(0, index), arg.substring(index + 1));
+ }
+
+ static protected final String agentNameOption = "-agentName";
+
+ static protected final String pathToNewByteCodeOption = "-pathToNewByteCode";
+
+ /*
+ * Parse agent's options, initialize common parameters
+ */
+ private void defaultInit(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ AgentOption option = parseAgentArgument(args[i]);
+ if (option.name.equals(agentNameOption)) {
+ name = option.value;
+ outputPrefix = name + ": ";
+ } else if (option.name.equals(pathToNewByteCodeOption)) {
+ pathToNewByteCode = option.value;
+ }
+ }
+
+ if (name == null)
+ throw new TestBug("Agent name wasn't specified");
+
+ log = new Log(System.out, true);
+ }
+
+ /*
+ * Special thread which is started from agentmain method and executing main
+ * agent's actions. When agent completes execution AgentThread notifies
+ * target application about that.
+ */
+ class AgentThread extends Thread {
+
+ AgentThread() {
+ super("Jar agent thread (agent: " + name + ")");
+ }
+
+ public void run() {
+ try {
+ agentActions();
+ } catch (Throwable t) {
+ setStatusFailed("Unexpected exception in the JarAgent: " + t);
+ logThrowable(t);
+ } finally {
+ TargetApplicationWaitingAgents.agentFinished(name, finishedSuccessfully);
+ }
+ }
+ }
+
+ /*
+ * This methods parses agent's options, initializes agent, notifies target application
+ * that agent is started and starts thread executing main agent's actions.
+ * Agents used in AttachOnDemand tests should call this method from its agentmain methods.
+ */
+ public final void runJarAgent(String options, Instrumentation inst) {
+ if (options == null)
+ throw new TestBug("Agent options weren't specified");
+
+ this.inst = inst;
+
+ String[] args = options.split(" ");
+
+ // initialize common parameters
+ defaultInit(args);
+
+ // test-specific initialization
+ init(args);
+
+ // notify target application that agent was loaded and initialized
+ TargetApplicationWaitingAgents.agentLoaded(name);
+
+ // start special thread executing test-specific actions
+ new AgentThread().start();
+ }
+
+ /*
+ * Actions specific for test should be realized in this method.
+ * This method is called from special thread started from agentmain method
+ * after agent initialization
+ */
+ abstract protected void agentActions() throws Throwable;
+
+
+ /*
+ * Create ClassDefinition object for given class, path to the new class file
+ * is specified in the parameter 'pathToByteCode'
+ */
+ protected static ClassDefinition createClassDefinition(Class<?> klass,
+ String pathToByteCode) throws IOException {
+ File classFile = new File(pathToByteCode + File.separator +
+ klass.getName().replace(".", File.separator) +
+ ".class");
+
+ if (classFile.length() > Integer.MAX_VALUE)
+ throw new Failure("Class file '" + classFile.getName() + " 'too large");
+
+ byte data[] = new byte[(int)classFile.length()];
+
+ DataInputStream in = null;
+ try {
+ in = new DataInputStream(new FileInputStream(classFile));
+ in.readFully(data);
+ } finally {
+ if (in != null)
+ in.close();
+ }
+
+ return new ClassDefinition(klass, data);
+ }
+
+ /*
+ * Redefine given class using path to byte code specified with options -pathToNewByteCode
+ */
+ protected void redefineClass(Class<?> klass) throws Throwable {
+ if (pathToNewByteCode() == null)
+ throw new TestBug("Path to new class files wasn't specified");
+
+ ClassDefinition newClassDef = createClassDefinition(klass, pathToNewByteCode());
+ inst.redefineClasses(newClassDef);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentInformation.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+/*
+ * Class contains information about dynamically attached agent
+ */
+public class AgentInformation {
+
+ // counters used for unique agent names generation
+
+ private static int jarAgentsCounter;
+
+ private static int nativeAgentsCounter;
+
+ public boolean jarAgent;
+
+ public String pathToAgent;
+
+ public String agentOptions;
+
+ public AgentInformation(boolean jarAgent, String pathToAgent, String options, boolean addAgentNameOption) {
+ this.jarAgent = jarAgent;
+ this.pathToAgent = pathToAgent;
+ this.agentOptions = options;
+
+ // add to agent options additional parameter - agent name (it used by nsk.share.aod framework)
+
+ String name;
+
+ if (jarAgent)
+ name = "JarAgent-" + jarAgentsCounter++;
+ else
+ name = "NativeAgent-" + nativeAgentsCounter++;
+
+ if (addAgentNameOption) {
+ if (this.agentOptions == null) {
+ this.agentOptions = "-agentName=" + name;
+ } else {
+ this.agentOptions += " -agentName=" + name;
+ }
+ }
+ }
+
+ public AgentInformation(boolean jarAgent, String pathToAgent, String options) {
+ this(jarAgent, pathToAgent, options, true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AgentsAttacher.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import nsk.share.*;
+import java.io.IOException;
+import java.util.*;
+import com.sun.tools.attach.*;
+
+/*
+ * This class loads java and native agents in the running VM using Attach API
+ * (API from package com.sun.tools.attach).
+ */
+public class AgentsAttacher {
+
+ protected String targetVMId;
+
+ protected List<AgentInformation> agents;
+
+ protected Log log;
+
+ public AgentsAttacher(String targetVMId, List<AgentInformation> agents, Log log) {
+ this.targetVMId = targetVMId;
+ this.agents = agents;
+ this.log = log;
+ }
+
+ public void attachAgents() {
+ VirtualMachine vm = null;
+
+ try {
+ log.display("Trying to get VirtualMachine object");
+ vm = VirtualMachine.attach(targetVMId);
+ } catch (AttachNotSupportedException e) {
+ log.complain("Unexpected AttachNotSupportedException during VirtualMachine.attach: " + e);
+ e.printStackTrace(log.getOutStream());
+ } catch (IOException e) {
+ log.complain("Unexpected IOException during VirtualMachine.attach: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ if (vm == null) {
+ failed("Unable to create VirtualMachine object");
+ }
+
+ log.display("VirtualMachine was created: " + vm);
+
+ try {
+ for (AgentInformation agentInfo : agents) {
+ tryToLoadAgent(vm, agentInfo.pathToAgent, agentInfo.agentOptions, agentInfo.jarAgent);
+ }
+ } finally {
+ try {
+ log.display("Detaching from the VM '" + vm + "'");
+ vm.detach();
+ } catch (IOException e) {
+ failed("Unexpected IOException during detaching: " + e, e);
+ }
+ }
+ }
+
+ protected void tryToLoadAgent(VirtualMachine vm, String agent, String agentOptions, boolean jarAgent) {
+ boolean agentLoaded = false;
+
+ Throwable failureCause = null;
+
+ try {
+ if (jarAgent) {
+ log.display("Trying to load jar agent: '" + agent + "' (agent options: '" + agentOptions + "')");
+ vm.loadAgent(agent, agentOptions);
+ } else {
+ log.display("Trying to load native agent: '" + agent + "' (agent options: '" + agentOptions + "')");
+ vm.loadAgentLibrary(agent, agentOptions);
+ }
+ log.display("Agent was loaded");
+ agentLoaded = true;
+ } catch (AgentLoadException e) {
+ failureCause = e;
+ log.complain("Unexpected AgentLoadException during agent loading: " + e);
+ if (jarAgent) {
+ log.complain("(probably the agent does not exist, or cannot be started in the manner specified in "
+ + "the java.lang.instrument specification)");
+ } else {
+ log.complain("(probably agent library does not exist, or cannot be loaded for another reason)");
+ }
+ e.printStackTrace(log.getOutStream());
+ } catch (AgentInitializationException e) {
+ failureCause = e;
+ log.complain("Unexpected AgentInitializationException during agent loading: " + e);
+ if (jarAgent) {
+ log.complain("(agentmain have thrown an exception)");
+ } else {
+ log.complain("Agent_OnAttach function returned an error: " + e.returnValue());
+ }
+ e.printStackTrace(log.getOutStream());
+ } catch (IOException e) {
+ failureCause = e;
+ log.complain("Unexpected IOException during agent loading: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ if (!agentLoaded) {
+ if (failureCause != null)
+ failed("Couldn't attach agent to the target application", failureCause);
+ else
+ failed("Couldn't attach agent to the target application");
+ }
+ }
+
+ private void failed(String errorMessage) {
+ throw new Failure(errorMessage);
+ }
+
+ private void failed(String errorMessage, Throwable t) {
+ throw new Failure(errorMessage, t);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import nsk.share.*;
+import nsk.share.jpda.SocketIOPipe;
+
+/*
+Class TargetApplication is part of the framework used in the AttachOnDemand tests
+(tests against Attach API, API from package com.sun.tools.attach).
+
+This class is used in tests where main test application uses Attach API, but doesn't load agents to the another VM.
+In these test there are 2 java applications: main application using Attach API and another
+'dummy' application which should be alive while main application is working.
+
+To synchronize main and dummy application SocketIOPipe is used: when DummyTargetApplication starts
+it sends signal that it is ready for test and waits for signal permitting finish execution
+(socket number used for connection establishing should be passed via command line).
+ */
+public class DummyTargetApplication {
+
+ protected Log log = new Log(System.out, true);
+
+ protected AODTargetArgParser argParser;
+
+ protected SocketIOPipe pipe;
+
+ public DummyTargetApplication(String[] args) {
+ argParser = new AODTargetArgParser(args);
+ }
+
+ protected void targetApplicationActions() {
+ // do nothing by default
+ }
+
+ public void runTargetApplication() {
+ pipe = SocketIOPipe.createClientIOPipe(log, "localhost", argParser.getPort(), 0);
+ log.display("Sending signal '" + AODTestRunner.SIGNAL_READY_FOR_ATTACH + "'");
+ pipe.println(AODTestRunner.SIGNAL_READY_FOR_ATTACH);
+
+ targetApplicationActions();
+
+ String signal = pipe.readln();
+ log.display("Signal received: '" + signal + "'");
+
+ if ((signal == null) || !signal.equals(AODTestRunner.SIGNAL_FINISH))
+ throw new TestBug("Unexpected signal: '" + signal + "'");
+ }
+
+ public static void main(String[] args) {
+ new DummyTargetApplication(args).runTargetApplication();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/ProcessExecutor.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.*;
+
+public class ProcessExecutor {
+
+ private String[] cmdLine;
+
+ private long timeout;
+
+ private boolean printProcessOutput;
+
+ private String processOutputPrefix;
+
+ private InputStreamReaderThread outReader;
+
+ private InputStreamReaderThread errReader;
+
+ private Process startedProcess;
+
+ private ProcessWaiterThread processWaiter;
+
+ private long expectedFinishTime;
+
+ private volatile boolean executionCompleted;
+
+ private int exitCode;
+
+ private class InputStreamReaderThread extends Thread {
+ private BufferedReader in;
+
+ private String outputPrefix;
+
+ private List<String> output = new ArrayList<String>();
+
+ private volatile boolean streamWasAbruptlyClosed;
+
+ private Throwable unexpectedException;
+
+ public InputStreamReaderThread(InputStream in, String prefix) {
+ this.in = new BufferedReader(new InputStreamReader(in));
+ this.outputPrefix = prefix;
+ setDaemon(true);
+ }
+
+ public void streamWasAbruptlyClosed(boolean newValue) {
+ streamWasAbruptlyClosed = newValue;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ String line = in.readLine();
+ if (line == null)
+ return;
+
+ output.add(line);
+
+ if (printProcessOutput)
+ System.out.println(outputPrefix + line);
+ }
+ } catch (IOException e) {
+ if (!streamWasAbruptlyClosed) {
+ unexpectedException = e;
+ e.printStackTrace( );
+ }
+ } catch (Throwable t) {
+ unexpectedException = t;
+ t.printStackTrace( );
+ }
+ }
+
+ void checkStatus() {
+ if (unexpectedException != null)
+ throw new Failure("Exception was thrown during InputStreamReaderThread work: " + unexpectedException,
+ unexpectedException);
+ }
+ }
+
+ private class ProcessWaiterThread extends Thread {
+
+ private Throwable unexpectedException;
+
+ private Process process;
+
+ private InputStreamReaderThread outReader;
+
+ private InputStreamReaderThread errReader;
+
+ ProcessWaiterThread(Process process, InputStreamReaderThread outReader, InputStreamReaderThread errReader) {
+ this.process = process;
+ this.outReader = outReader;
+ this.errReader = errReader;
+
+ setDaemon(true);
+ }
+
+ public void run() {
+ try {
+ exitCode = process.waitFor();
+ outReader.join();
+ errReader.join();
+
+ synchronized (ProcessWaiterThread.this) {
+ executionCompleted = true;
+ ProcessWaiterThread.this.notify();
+ }
+ } catch (InterruptedException e) {
+ /*
+ * ProcessWaiterThread is interrupted if started process
+ * didn't finish in expected time
+ */
+ } catch (Throwable t) {
+ unexpectedException = t;
+ t.printStackTrace();
+ }
+ }
+
+ void checkStatus() {
+ if (unexpectedException != null)
+ throw new Failure("Exception was thrown during ProcessWaiterThread work: "
+ + unexpectedException, unexpectedException);
+ }
+ }
+
+ public ProcessExecutor(String cmdLine, long timeout) {
+ this.cmdLine = new String[]{cmdLine};
+ this.timeout = timeout;
+ }
+
+ public ProcessExecutor(String cmdLine, long timeout, String outputPrefix) {
+ this(cmdLine, timeout);
+ this.printProcessOutput = true;
+ this.processOutputPrefix = outputPrefix;
+ }
+
+ public void startProcess() throws IOException {
+ if (cmdLine.length == 1)
+ startedProcess = Runtime.getRuntime().exec(cmdLine[0]);
+ else
+ startedProcess = Runtime.getRuntime().exec(cmdLine);
+
+ expectedFinishTime = System.currentTimeMillis() + timeout;
+
+ outReader = new InputStreamReaderThread(startedProcess.getInputStream(),
+ processOutputPrefix == null ? "" : processOutputPrefix + " (stdout): ");
+ errReader = new InputStreamReaderThread(startedProcess.getErrorStream(),
+ processOutputPrefix == null ? "" : processOutputPrefix + " (stderr): ");
+
+ outReader.start();
+ errReader.start();
+
+ processWaiter = new ProcessWaiterThread(startedProcess, outReader, errReader);
+ processWaiter.start();
+ }
+
+
+ public void waitForProcess() throws InterruptedException {
+ synchronized (processWaiter) {
+ while ((System.currentTimeMillis() < expectedFinishTime) && !executionCompleted) {
+ processWaiter.wait(expectedFinishTime - System.currentTimeMillis());
+ }
+ }
+
+ if (!executionCompleted) {
+ destroyProcessAndWaitThreads();
+
+ executionCompleted = true;
+
+ throw new Failure("Execution timed out (timeout: " + timeout + "ms)");
+ }
+ }
+
+ private void destroyProcessAndWaitThreads() {
+ outReader.streamWasAbruptlyClosed(true);
+ errReader.streamWasAbruptlyClosed(true);
+
+ processWaiter.interrupt();
+ startedProcess.destroy();
+
+ try {
+ outReader.join();
+ errReader.join();
+ processWaiter.join();
+
+ outReader.checkStatus();
+ errReader.checkStatus();
+ processWaiter.checkStatus();
+ } catch (InterruptedException e) {
+ throw new Failure("Unexpected InterruptedException", e);
+ }
+ }
+
+ private void checkProcessState() {
+ if (!executionCompleted)
+ throw new IllegalStateException("Process didn't finish execution");
+ }
+
+ public void destroyProcess() {
+ if (executionCompleted)
+ return;
+
+ destroyProcessAndWaitThreads();
+ }
+
+ public long pid() {
+ return startedProcess.pid();
+ }
+
+ public int getExitCode() {
+ checkProcessState();
+
+ return exitCode;
+ }
+
+ public List<String> getProcessOut() {
+ checkProcessState();
+
+ return outReader.output;
+ }
+
+ public List<String> getProcessErr() {
+ checkProcessState();
+
+ return errReader.output;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import nsk.share.*;
+import nsk.share.jpda.SocketIOPipe;
+
+import java.util.*;
+
+/*
+Class TargetApplicationWaitingAgents is part of the framework used in the AttachOnDemand tests
+(tests against Attach API, API from package com.sun.tools.attach).
+
+Attach API allows to load so called 'agents' in the running VM. In terms of this framework
+application running in the VM where agent is loaded to is called 'target application'.
+
+TargetApplicationWaitingAgents is base class for target applications used in the AttachOnDemand tests
+(also TargetApplicationWaitingAgents can be used without modifications in tests where target
+application shouldn't execute some test-specific actions).
+
+AttachOnDemand tests requires synchronization between test agents and target application:
+ - before target application can start to execute test-specific actions it
+ should wait when all tests agents will be loaded
+
+ - target application shouldn't finish until all agents finish their work
+
+TargetApplicationWaitingAgents incapsulates actions common for all target applications. TargetApplicationWaitingAgents
+provides 2 methods: 'agentLoaded' and 'agentFinished', test agents use these methods to notify
+target application about its status. When target application based on the TargetApplicationWaitingAgents
+starts it first waits when all test agents will be loaded (number of expected test agents is
+passed via parameter -agentsNumber). After this target application executes test-specific actions,
+waits when all test agents will finish, checks agent's status (passed of failed) and
+finishes.
+
+In most cases test target applications should override only method 'targetApplicationActions' and
+its 'main' method should contain only call of the method 'TargetApplicationWaitingAgents.runTargetApplication'.
+
+Typical target application class looks like this:
+
+public class targetExample extends TargetApplicationWaitingAgents {
+
+ protected void targetApplicationActions() {
+ // do test-specific actions
+ }
+
+ public static void main(String[] args) {
+ new targetExample().runTargetApplication(args);
+ }
+}
+*/
+public class TargetApplicationWaitingAgents {
+
+ private volatile static boolean testFailed = false;
+
+ private static long AGENTS_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 min
+
+ private static long AGENTS_FINISHING_TIMEOUT = 5 * 60 * 1000; // 5 min
+
+ private static boolean allAgentsAttached;
+
+ private static List<String> attachedAgents = new ArrayList<String>();
+
+ private static boolean allAgentsFinished;
+
+ private static List<String> finishedAgents = new ArrayList<String>();
+
+ private static boolean targetApplicationInitialized;
+
+ static protected AODTargetArgParser argParser;
+
+ protected static Log log;
+
+ static private Object monitor = new Object();
+
+ /*
+ * Methods
+ * - agentLoaded(String agentName) and
+ * - agentFinished(String agentName, boolean finishedSuccessfully)
+ * are called from test agents to notify target application about its status
+ */
+
+ public static void agentLoaded(String agentName) {
+ synchronized (monitor) {
+ if (!targetApplicationInitialized)
+ waitForTargetApplicationInitialization();
+
+ // check test logic
+ if (attachedAgents.contains(agentName)) {
+ setStatusFailed("Agent '" + agentName + "' already attached");
+
+ // let TargetApplication complete execution in case of error
+ allAgentsAttached = true;
+ monitor.notifyAll();
+
+ throw new TestBug("Agent '" + agentName + "' calls method 'agentLoaded' more than 1 time");
+ } else {
+ attachedAgents.add(agentName);
+
+ log.display("Agent '" + agentName + "' was loaded");
+
+ allAgentsAttached = (attachedAgents.size() == argParser.getExpectedAgentsNumber());
+
+ if (allAgentsAttached)
+ monitor.notifyAll();
+
+ // check test logic
+ if (attachedAgents.size() > argParser.getExpectedAgentsNumber()) {
+ setStatusFailed("Unexpected agent attached (expected agents number: " +
+ argParser.getExpectedAgentsNumber() +
+ ", but " + attachedAgents.size() + " agents were loaded)");
+
+ throw new TestBug("More agents attached than it was expected" +
+ " (expected: " + argParser.getExpectedAgentsNumber() +
+ ", attached: " + attachedAgents.size() + ")");
+ }
+ }
+ }
+ }
+
+ public static void agentFinished(String agentName, boolean finishedSuccessfully) {
+ synchronized (monitor) {
+ // check test logic
+ if (!targetApplicationInitialized)
+ throw new TestBug("Method 'agentFinished' was called before TargetApplication was initialized");
+
+ boolean algorithmError = false;
+ String errorMessage = "Test algorithm error:";
+
+ if (!attachedAgents.contains(agentName)) {
+ algorithmError = true;
+ errorMessage += " agent '" + agentName + "' didn't call method 'agentLoaded';";
+ log.complain(errorMessage);
+ }
+
+ if (finishedAgents.contains(agentName)) {
+ algorithmError = true;
+ errorMessage += " agent '" + agentName + "' already called method 'agentFinished';";
+ log.complain(errorMessage);
+ }
+
+ if (algorithmError) {
+ // let TargetApplication complete execution in case of error
+ allAgentsFinished = true;
+ monitor.notifyAll();
+
+ throw new TestBug(errorMessage);
+ } else {
+ finishedAgents.add(agentName);
+
+ log.display("Agent '" + agentName + "' finished execution (finishedSuccessfully: " + finishedSuccessfully + ")");
+
+ if (!finishedSuccessfully)
+ setStatusFailed("Agent '" + agentName + " finished with error status");
+
+ allAgentsFinished = (finishedAgents.size() == argParser.getExpectedAgentsNumber());
+
+ if (allAgentsAttached)
+ monitor.notifyAll();
+ }
+ }
+ }
+
+ /*
+ * This method is called from the method 'agentLoaded' in case
+ * when target application isn't initialized yet at the moment
+ * when agent is connecting
+ */
+ static private void waitForTargetApplicationInitialization() {
+ synchronized (monitor) {
+ while (!targetApplicationInitialized) {
+ try {
+ monitor.wait();
+ } catch (InterruptedException e) {
+ // should never happen
+ exitAsFailed(e);
+ }
+ }
+ }
+ }
+
+ /*
+ * This method is introduced to let subclasses to create its own parsers
+ */
+ protected AODTargetArgParser createArgParser(String[] args) {
+ return new AODTargetArgParser(args);
+ }
+
+ /*
+ * Target application initialization
+ */
+ private void initTargetApplication(String[] args) {
+ synchronized (monitor) {
+ if (targetApplicationInitialized)
+ throw new TestBug("TargetApplication already initialized");
+
+ log = new Log(System.out, true);
+
+ argParser = createArgParser(args);
+
+ // test-specific initialization
+ init(args);
+
+ targetApplicationInitialized = true;
+ monitor.notifyAll();
+ }
+ }
+
+ static private void waitAgentsConnection() {
+ synchronized (monitor) {
+ long waitFinishTime = System.currentTimeMillis() + AGENTS_CONNECTION_TIMEOUT;
+
+ while (!allAgentsAttached && (System.currentTimeMillis() < waitFinishTime)) {
+ try {
+ monitor.wait(AGENTS_CONNECTION_TIMEOUT);
+ } catch (InterruptedException e) {
+ // should never happen
+ exitAsFailed(e);
+ }
+ }
+ }
+
+ if (!allAgentsAttached) {
+ exitAsFailed("Agents didn't attach in " + AGENTS_CONNECTION_TIMEOUT + "ms, stop execution " +
+ "(expected agents number: " + argParser.getExpectedAgentsNumber() +
+ ", attached agents number: " + attachedAgents.size() + ")");
+ }
+ }
+
+ static private void waitAgentsFinishing() {
+ synchronized (monitor) {
+ long waitFinishTime = System.currentTimeMillis() + AGENTS_FINISHING_TIMEOUT;
+
+ while (!allAgentsFinished && (System.currentTimeMillis() < waitFinishTime)) {
+ try {
+ monitor.wait(AGENTS_FINISHING_TIMEOUT);
+ } catch (InterruptedException e) {
+ // should never happen
+ exitAsFailed(e);
+ }
+ }
+ }
+
+ if (!allAgentsFinished)
+ exitAsFailed("Agents didn't finish in " + AGENTS_FINISHING_TIMEOUT + "ms, stop execution " +
+ "(attached agents number: " + attachedAgents.size() +
+ ", finished agents number: " + finishedAgents.size() + ")");
+ }
+
+ /*
+ * Print error message and set failed status, but don't exit
+ */
+
+ static public void setStatusFailed(String message) {
+ testFailed = true;
+ log.complain(message);
+ }
+
+ static public void setStatusFailed(Throwable t) {
+ testFailed = true;
+ log.complain("Unexpected exception: " + t);
+ t.printStackTrace(log.getOutStream());
+ }
+
+ /*
+ * Print error message and exit with fail status
+ */
+ static protected void exitAsFailed(String errorMessage) {
+ try {
+ log.complain(errorMessage);
+ log.complain("Stop execution");
+ } finally {
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+
+ /*
+ * Print error message and exit with fail status
+ */
+ static protected void exitAsFailed(Throwable t) {
+ try {
+ log.complain("Unexpected exception was thrown during TargetApplication execution: " + t);
+ t.printStackTrace(log.getOutStream());
+ log.display("Stop execution");
+ } finally {
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+
+ /*
+ * Following 3 methods can be overridden in subclasses:
+ *
+ * - init(String[] args)
+ *
+ * - targetApplicationActions()
+ *
+ * - afterAgentsFinished()
+ */
+
+ /*
+ * Test-specific initialization
+ */
+ protected void init(String[] args) {
+
+ }
+
+ protected void targetApplicationActions() throws Throwable {
+ // do nothing by default
+ }
+
+ protected void afterAgentsFinished() {
+ // do nothing by default
+ }
+
+ public final void runTargetApplication(String[] args) {
+ initTargetApplication(args);
+
+ SocketIOPipe pipe = null;
+
+ try {
+ if (argParser.getPort() > 0) {
+ /*
+ * When target application initialized send signal to AODTestRunner
+ */
+ pipe = SocketIOPipe.createClientIOPipe(log, "localhost", argParser.getPort(), 0);
+ log.display("Sending signal '" + AODTestRunner.SIGNAL_READY_FOR_ATTACH + "'");
+ pipe.println(AODTestRunner.SIGNAL_READY_FOR_ATTACH);
+ }
+
+ log.display("Waiting for agents connection");
+ waitAgentsConnection();
+ log.display("All expected agents connected");
+
+ try {
+ targetApplicationActions();
+ } catch (Throwable e) {
+ /*
+ * If something goes wrong during test execution it is better
+ * to exit without waiting for agents
+ */
+
+ if (pipe != null)
+ pipe.close();
+
+ exitAsFailed(e);
+ }
+
+ log.display("Waiting for agents finishing");
+ waitAgentsFinishing();
+ log.display("All agents finished execution");
+
+ afterAgentsFinished();
+
+ if (pipe != null) {
+ /*
+ * Don't finish execution until AODTestRunner attached agents
+ */
+ String signal = pipe.readln();
+ log.display("Signal received: '" + signal + "'");
+ if ((signal == null) || !signal.equals(AODTestRunner.SIGNAL_FINISH))
+ throw new TestBug("Unexpected AODTestRunner signal: '" + signal + "'");
+
+ if (testFailed) {
+ if (pipe != null)
+ pipe.close();
+
+ exitAsFailed("Error happened during TargetApplication execution (see error messages for details)");
+ } else {
+ log.display("Test passed");
+ }
+ }
+ } finally {
+ if (pipe != null)
+ pipe.close();
+ }
+ }
+
+ public static void main(String[] args) {
+ new TargetApplicationWaitingAgents().runTargetApplication(args);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/Utils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.aod;
+
+import java.io.File;
+
+import nsk.share.*;
+
+public class Utils {
+
+ // prevent class instantiation
+ private Utils() {
+ }
+
+ public static final long JPS_WORK_TIMEOUT = 60000; // 1 min
+
+ /**
+ * Find id of VM with certain value of property key. Method findVMIdUsingJPS
+ * runs 'jps -v' and seeks in jps output line containing this unique string,
+ * discovered string should also contain VM id.
+ *
+ * @param jdkPath - path to jdk
+ * @param key - name of property
+ * @param value - value of property
+ * @return VM id
+ */
+ public static String findVMIdUsingJPS(String jdkPath, String key, String value) {
+ try {
+ if (value == null) {
+ return null;
+ }
+ String idString = key + "=" + value;
+ String jpsPath = jdkPath + File.separator + "bin" + File.separator + "jps";
+
+ while (true) {
+ ProcessExecutor executor = new ProcessExecutor(jpsPath + " -v", JPS_WORK_TIMEOUT, "jps -v");
+ executor.startProcess();
+ executor.waitForProcess();
+
+ if (executor.getExitCode() != 0) {
+ throw new Failure("jps finished with non-zero code " + executor.getExitCode());
+ }
+
+ for (String jpsOutLine : executor.getProcessOut()) {
+ if (jpsOutLine.contains(idString)) {
+ if (jpsOutLine.indexOf(' ') < 0)
+ throw new Failure("Unexpected format of the jps output '" + jpsOutLine + " (line doesn't contain space)");
+
+ return jpsOutLine.substring(0, jpsOutLine.indexOf(' '));
+ }
+ }
+ Thread.sleep(100);
+ }
+ } catch (Failure f) {
+ throw f;
+ } catch (Throwable t) {
+ throw new Failure("Unexpected exception during jps execution: " + t, t);
+ }
+ }
+
+ public static String findCurrentVMIdUsingJPS(String jdkPath) {
+ /*
+ * VM should be run with special property which allows to find VM id using jps
+ * (see comments for method Utils.findVMIdUsingJPS)
+ */
+ String applicationId = System.getProperty(AODTestRunner.targetAppIdProperty);
+ if (applicationId == null)
+ throw new TestBug("Property '" + AODTestRunner.targetAppIdProperty + "' isn't defined");
+
+ String targetVMId = Utils.findVMIdUsingJPS(jdkPath, AODTestRunner.targetAppIdProperty, applicationId);
+
+ return targetVMId;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <jni.h>
+#include <jni_tools.h>
+#include <nsk_tools.h>
+#include <aod.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static volatile int internalError = 0;
+
+/*
+ * This function can be used to inform AOD framework that some non critical for test logic
+ * error happened inside shared function (e.g. JVMTI Deallocate failed).
+ *
+ * If this function was called status of all finishing AOD agents is changed to failed.
+ */
+
+void nsk_aod_internal_error() {
+ NSK_COMPLAIN0("WARNING: some error happened inside common function, see log for details\n");
+ internalError = 1;
+}
+
+void nsk_free_options(Options* options) {
+ if (options != NULL) {
+ int i;
+ for (i = 0; i < NSK_AOD_MAX_OPTIONS; i++) {
+ if (options->names[i] != NULL) {
+ free(options->names[i]);
+ }
+ if (options->values[i] != NULL) {
+ free(options->values[i]);
+ }
+ }
+ free(options);
+ }
+}
+/*
+ * Work with agent options
+ */
+
+/*
+ * Parse options and create structure Options
+ */
+static Options* nsk_aod_createOptionsObject(char* optionsString) {
+ int i = 0;
+ Options* options;
+ char* name;
+ char* value;
+ char* sep;
+
+ if (optionsString == NULL) {
+ NSK_COMPLAIN0("options were not passed to the native agent\n");
+ return NULL;
+ }
+ options = (Options*) malloc(sizeof(Options));
+ memset(options, 0, sizeof(Options));
+ options->size = 0;
+ name = optionsString;
+ while (name != NULL && i < NSK_AOD_MAX_OPTIONS) {
+ sep = strchr(name, '=');
+ if (sep == NULL) { // name not found
+ NSK_COMPLAIN1("Invalid options format: '%s'\n", optionsString);
+ nsk_free_options(options);
+ return NULL;
+ }
+ *sep = '\0';
+ options->names[i] = strdup(name);
+ value = sep + 1;
+ if (*value == '\0') { // value not found
+ NSK_COMPLAIN1("Option '%s' is empty\n", options->names[i]);
+ nsk_free_options(options);
+ return NULL;
+ }
+ sep = strchr(value, ' ');
+ if (sep != NULL) {
+ *sep = '\0';
+ name = sep + 1;
+ } else {
+ name = strchr(value, '\0');
+ }
+ options->values[i] = strdup(value);
+ i++;
+
+ if (*name == '\0') {
+ name = NULL;
+ }
+ }
+ if (name != NULL) {
+ NSK_COMPLAIN1("WARNING: not all options were parsed, only %d options can be specified\n",
+ NSK_AOD_MAX_OPTIONS);
+ }
+ options->size = i;
+ return options;
+}
+
+Options* nsk_aod_createOptions(char* optionsString) {
+ Options* options;
+
+ if (!NSK_VERIFY((options = (Options*) nsk_aod_createOptionsObject(optionsString)) != NULL))
+ return NULL;
+
+ if (!NSK_VERIFY(nsk_aod_optionSpecified(options, NSK_AOD_AGENT_NAME_OPTION))) {
+ NSK_COMPLAIN0("Agent name wasn't specified\n");
+ return NULL;
+ }
+
+ /*
+ * verbose mode is true by default
+ */
+ nsk_setVerboseMode(NSK_TRUE);
+
+ if (nsk_aod_optionSpecified(options, NSK_AOD_VERBOSE_OPTION)) {
+ if (strcmp(nsk_aod_getOptionValue(options, NSK_AOD_VERBOSE_OPTION), "false") == 0)
+ nsk_setVerboseMode(NSK_FALSE);
+ }
+
+ return options;
+}
+
+const char* nsk_aod_getOptionValue(Options* options, const char* option) {
+ int i;
+
+ if (!NSK_VERIFY(options != NULL)) {
+ NSK_COMPLAIN0("Options NULL\n");
+ return NULL;
+ }
+
+ for(i = 0; i < options->size; i++) {
+ if (strcmp(option, options->names[i]) == 0) {
+ return options->values[i];
+ }
+ }
+
+ NSK_COMPLAIN1("Option '%s' isn't defined\n", option);
+
+ return NULL;
+}
+
+int nsk_aod_optionSpecified(Options* options, const char* option) {
+ int i;
+
+ if (!NSK_VERIFY(options != NULL)) {
+ NSK_COMPLAIN0("Options NULL\n");
+ return NSK_FALSE;
+ }
+
+ for(i = 0; i < options->size; i++) {
+ if (strcmp(option, options->names[i]) == 0) {
+ return NSK_TRUE;
+ }
+ }
+
+ return NSK_FALSE;
+}
+
+/*
+ * Agent synchronization with target application
+ */
+
+static const char* TARGET_APP_CLASS_NAME = "nsk/share/aod/TargetApplicationWaitingAgents";
+
+static const char* AGENT_LOADED_METHOD_NAME = "agentLoaded";
+static const char* AGENT_LOADED_METHOD_SIGNATURE = "(Ljava/lang/String;)V";
+
+static const char* AGENT_FINISHED_METHOD_NAME = "agentFinished";
+static const char* AGENT_FINISHED_METHOD_SIGNATURE = "(Ljava/lang/String;Z)V";
+
+static jclass targetAppClass = NULL;
+static jmethodID agentLoadedMethod = NULL;
+static jmethodID agentFinishedMethod = NULL;
+
+// this function is used to notify target application that native agent has been loaded
+int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName) {
+ jstring agentNameString;
+
+ NSK_DISPLAY1("Agent %s is loaded\n", agentName);
+
+ if (targetAppClass == NULL) {
+ /*
+ * FindClass returns local reference, to cache reference to target application class
+ * global reference should be created
+ */
+ jclass localTargetAppClass;
+ if (!NSK_JNI_VERIFY(jni, (localTargetAppClass =
+ NSK_CPP_STUB2(FindClass, jni, TARGET_APP_CLASS_NAME)) != NULL)) {
+ return NSK_FALSE;
+ }
+
+ if (!NSK_JNI_VERIFY(jni, (targetAppClass =
+ NSK_CPP_STUB2(NewGlobalRef, jni, localTargetAppClass)) != NULL)) {
+ return NSK_FALSE;
+ }
+ }
+
+ if (agentLoadedMethod == NULL) {
+ if (!NSK_JNI_VERIFY(jni, (agentLoadedMethod =
+ NSK_CPP_STUB4(GetStaticMethodID, jni, targetAppClass,
+ AGENT_LOADED_METHOD_NAME, AGENT_LOADED_METHOD_SIGNATURE)) != NULL))
+ return NSK_FALSE;
+ }
+
+ if (!NSK_JNI_VERIFY(jni, (agentNameString =
+ NSK_CPP_STUB2(NewStringUTF, jni, agentName)) != NULL))
+ return NSK_FALSE;
+
+ NSK_CPP_STUB4(CallStaticVoidMethod, jni, targetAppClass, agentLoadedMethod, agentNameString);
+
+ return NSK_TRUE;
+}
+
+// this function is used to notify target application that native agent has been finished execution
+int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success) {
+ jstring agentNameString;
+
+ if (!targetAppClass) {
+ NSK_COMPLAIN1("%s: TEST LOGIC ERROR: method 'agentFinished' was called before "\
+ "targetAppClass was initialized\n", agentName);
+ return NSK_FALSE;
+ }
+
+ if (internalError && success) {
+ success = 0;
+ NSK_COMPLAIN1("Status of agent '%s' is 'passed', but some error happened during test execution "\
+ "(see log for details), change agent status to 'failed'\n",
+ agentName);
+ }
+
+ NSK_DISPLAY2("Agent %s finished (success: %d)\n", agentName, success);
+
+ if (agentFinishedMethod == NULL) {
+ if (!NSK_JNI_VERIFY(jni, (agentFinishedMethod =
+ NSK_CPP_STUB4(GetStaticMethodID, jni, targetAppClass,
+ AGENT_FINISHED_METHOD_NAME, AGENT_FINISHED_METHOD_SIGNATURE)) != NULL))
+ return NSK_FALSE;
+ }
+
+ if (!NSK_JNI_VERIFY(jni, (agentNameString = NSK_CPP_STUB2(NewStringUTF, jni, agentName)) != NULL))
+ return NSK_FALSE;
+
+ NSK_CPP_STUB5(CallStaticVoidMethod, jni, targetAppClass,
+ agentFinishedMethod, agentNameString, success ? JNI_TRUE : JNI_FALSE);
+
+ return NSK_TRUE;
+}
+
+/*
+ * Auxiliary functions
+ */
+
+// JNI env creation
+
+JNIEnv* nsk_aod_createJNIEnv(JavaVM* vm) {
+ JNIEnv* jni;
+ NSK_CPP_STUB3(GetEnv, vm, (void**)&jni, JNI_VERSION_1_2);
+
+ NSK_VERIFY(jni != NULL);
+
+ return jni;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+#ifndef NSK_SHARE_AOD_H
+#define NSK_SHARE_AOD_H
+
+#include <jni.h>
+#include <jni_tools.h>
+#include <nsk_tools.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This function can be used to inform AOD framework that some non-critical for test logic
+ * error happened inside shared function (e.g. JVMTI Deallocate failed).
+ *
+ * If this function was called status of all finishing AOD agents is changed to failed.
+ */
+
+void nsk_aod_internal_error();
+
+/*
+ * Work with agent options
+ */
+
+#define NSK_AOD_MAX_OPTIONS 10
+
+#define NSK_AOD_AGENT_NAME_OPTION "-agentName"
+#define NSK_AOD_VERBOSE_OPTION "-verbose"
+
+typedef struct {
+ char* names[NSK_AOD_MAX_OPTIONS];
+ char* values[NSK_AOD_MAX_OPTIONS];
+ int size;
+} Options;
+
+Options* nsk_aod_createOptions(char* optionsString);
+
+const char* nsk_aod_getOptionValue(Options* options, const char* option);
+
+int nsk_aod_optionSpecified(Options* options, const char* option);
+
+/*
+ * Agent synchronization with target application
+ */
+
+// this function is used to notify target application that native agent has been loaded
+int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName);
+
+// this function is used to notify target application that native agent has been finished execution
+int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success);
+
+
+// JNI env creation
+
+JNIEnv* nsk_aod_createJNIEnv(JavaVM* vm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* END OF NSK_SHARE_AOD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/ClassPathNonDelegatingClassLoader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.classload;
+
+import java.io.*;
+import java.util.*;
+
+import nsk.share.FileUtils;
+
+/**
+ * Custom classloader that does not delegate to it's parent.
+ *
+ * It can load classes from classpath that have name containing
+ * "Class" (any package).
+ */
+public class ClassPathNonDelegatingClassLoader extends ClassLoader {
+ private String [] classPath;
+
+ public ClassPathNonDelegatingClassLoader() {
+ classPath = System.getProperty("java.class.path").split(File.pathSeparator);
+ }
+
+ public synchronized Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+ Class c = findLoadedClass(name);
+ if (c != null) {
+ System.out.println("Found class: " + name);
+ return c;
+ }
+ if (name.contains("Class")) {
+ String newName = name.replace('.', '/');
+ return loadClassFromFile(name, newName + ".class", resolve);
+ } else {
+ return findSystemClass(name);
+ }
+ }
+
+ private Class loadClassFromFile(String name, String fname, boolean resolve)
+ throws ClassNotFoundException {
+ try {
+ File target = new File("");
+
+ for(int i = 0; i < classPath.length; ++i) {
+ target = new File(classPath[i] + File.separator + fname);
+ if (target.exists())
+ break;
+ }
+ if (!target.exists())
+ throw new java.io.FileNotFoundException();
+ byte[] buffer = FileUtils.readFile(target);
+ Class c = defineClass(name, buffer, 0, buffer.length);
+ if (resolve)
+ resolveClass(c);
+ return c;
+ } catch (IOException e) {
+ throw new ClassNotFoundException("Exception while reading classfile data", e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.classload;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.*;
+
+/**
+ * Classloader that generates classes on the fly.
+ *
+ * This classloader can load classes with name starting with 'Class'.
+ * It will use nsk.share.classload.TemplateClass as template and will
+ * replace class name in the bytecode of template class. It can be used
+ * for example to detect memory leaks in class loading or to quickly
+ * fill PermGen.
+ */
+public class GeneratingClassLoader extends ClassLoader {
+ public static final String DEFAULT_CLASSNAME = TemplateClass.class.getName();
+ public static final String PREFIX = "Class";
+
+ private final String [] classPath;
+ private byte[] bytecode;
+ private int[] offsets;
+ private final String encoding = "UTF8";
+ private final String templateClassName;
+ private final byte[] templateClassNameBytes;
+
+ /**
+ * Create generating class loader that will use class file
+ * for given class from classpath as template.
+ */
+ public GeneratingClassLoader(String templateClassName) {
+ this.templateClassName = templateClassName;
+ classPath = System.getProperty("java.class.path").split(File.pathSeparator);
+ try {
+ templateClassNameBytes = templateClassName.getBytes(encoding);
+ } catch (UnsupportedEncodingException e) {
+ throw new TestBug(e);
+ }
+ }
+
+ /**
+ * Create generating class loader that will use class file
+ * for nsk.share.classload.TemplateClass as template.
+ */
+ public GeneratingClassLoader() {
+ this("nsk.share.classload.TemplateClass");
+ }
+
+ public int getNameLength() {
+ return templateClassName.length();
+ }
+
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ public String getClassName(int number) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(PREFIX);
+ sb.append(number);
+ int n = templateClassName.length() - sb.length();
+ for (int i = 0; i < n; ++i)
+ sb.append("_");
+ return sb.toString();
+ }
+
+ public synchronized Class loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ public synchronized Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+ Class c = findLoadedClass(name);
+ if (c != null)
+ return c;
+ if (!name.startsWith(PREFIX))
+ return super.loadClass(name, resolve);
+ if (name.length() != templateClassName.length())
+ throw new ClassNotFoundException("Only can load classes with name.length() = " + getNameLength() + " got: '" + name + "' length: " + name.length());
+ byte[] bytecode = getPatchedByteCode(name);
+ c = defineClass(name, bytecode, 0, bytecode.length);
+ if (resolve)
+ resolveClass(c);
+ return c;
+ }
+
+ private byte[] getPatchedByteCode(String name) throws ClassNotFoundException {
+ try {
+ byte[] bytecode = getByteCode();
+ String fname = name.replace(".", File.separator);
+ byte[] replaceBytes = fname.getBytes(encoding);
+ for (int offset : offsets) {
+ for (int i = 0; i < replaceBytes.length; ++i)
+ bytecode[offset + i] = replaceBytes[i];
+ }
+ return bytecode;
+ } catch (UnsupportedEncodingException e) {
+ throw new TestBug(e);
+ } catch (IOException e) {
+ throw new TestBug(e);
+ }
+ }
+
+ private byte[] getByteCode() throws ClassNotFoundException {
+ if (bytecode == null)
+ readByteCode();
+ if (offsets == null) {
+ getOffsets(bytecode);
+ if (offsets == null)
+ throw new TestBug("Class name not found in template class file");
+ }
+ return (byte[]) bytecode.clone();
+ }
+
+ private void readByteCode() throws ClassNotFoundException {
+ String fname = templateClassName.replace(".", File.separator) + ".class";
+ File target = null;
+ for (int i = 0; i < classPath.length; ++i) {
+ target = new File(classPath[i] + File.separator + fname);
+ if (target.exists())
+ break;
+ }
+
+ if (target == null || !target.exists())
+ throw new ClassNotFoundException("File not found: " + target);
+ try {
+ bytecode = FileUtils.readFile(target);
+ } catch (IOException e) {
+ throw new ClassNotFoundException(templateClassName, e);
+ }
+ }
+
+ private void getOffsets(byte[] bytecode) {
+ List<Integer> offsets = new ArrayList<Integer>();
+ if (this.offsets == null) {
+ String pname = templateClassName.replace(".", "/");
+ try {
+ byte[] pnameb = pname.getBytes(encoding);
+ int i = 0;
+ while (true) {
+ while (i < bytecode.length) {
+ int j = 0;
+ while (j < pnameb.length && bytecode[i + j] == pnameb[j])
+ ++j;
+ if (j == pnameb.length)
+ break;
+ i++;
+ }
+ if (i == bytecode.length)
+ break;
+ offsets.add(new Integer(i));
+ i++;
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new TestBug(e);
+ }
+ this.offsets = new int[offsets.size()];
+ for (int i = 0; i < offsets.size(); ++i)
+ this.offsets[i] = offsets.get(i).intValue();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/TemplateClass.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.classload;
+
+public class TemplateClass {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Algorithms.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.*;
+import nsk.share.gc.gp.*;
+import nsk.share.test.ExecutionController;
+
+/**
+ * <tt>Algorithms</tt> class collects main algorithms that are used in
+ * GC testing.
+ */
+public class Algorithms {
+ /** Number of threads that one CPU can manage. */
+ public final static long THREADS_MANAGED_BY_ONE_CPU = 100;
+
+ /** Number of threads that one block of memory can manage. */
+ public final static long THREADS_MANAGED_BY_ONE_BLOCK = 200;
+
+ /** Default maximum number of elements in array. */
+ public final static int MAX_ARRAY_SIZE = 65535;
+
+ // Block of memory is 64M
+ private final static long BLOCK_SIZE = 64 * 1024 * 1024; // 64M
+
+ // Minimal memory chunk size to eat
+ private final static int MIN_MEMORY_CHUNK = 512; // Bytes
+
+ // Number of attempts to print a string. Print may fail because of
+ // OutOfMemoryError, so this constat specifies the number of attemts
+ // to print despite of OOME.
+ private final static int ATTEMPTS_TO_PRINT = 3;
+
+ // This object stores any Failure that is thrown in Gourmand class
+ // and used in eatMemory(int) method
+ private static Failure failure = null;
+
+ // This object is intended for wait()
+ private static Object object = new Object();
+
+ /**
+ * Default constructor.
+ */
+ private Algorithms() {}
+
+ /**
+ * Stresses memory by allocating arrays of bytes. The method allocates
+ * objects in the same thread and does not invoke GC explicitly by
+ * calling <tt>System.gc()</tt>.
+ * <p>
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * This method uses nsk.share.test.Stresser class to control
+ * it's execution. Consumed number of iterations depends on
+ * available memory.
+ *
+ * @throws <tt>nsk.share.Failure</tt> if any unexpected exception is
+ * thrown during allocating of the objects.
+ *
+ * @see nsk.share.test.Stresser
+ */
+ public static void eatMemory(ExecutionController stresser) {
+ GarbageUtils.eatMemory(stresser, 50, MIN_MEMORY_CHUNK, 2);
+ }
+
+ /**
+ * Calculates and returns recomended number of threads to start in the
+ * particular machine (with particular amount of memory and number of CPUs).
+ * The returned value is minimum of two values:
+ * {@link #THREADS_MANAGED_BY_ONE_CPU} * (number of processors) and
+ * {@link #THREADS_MANAGED_BY_ONE_BLOCK} * (number of blocks of the memory).
+ *
+ * @return recomended number of threads to start.
+ *
+ */
+ public static int getThreadsCount() {
+ Runtime runtime = Runtime.getRuntime();
+ int processors = runtime.availableProcessors();
+ long maxMemory = runtime.maxMemory();
+ long blocks = Math.round((double) maxMemory / BLOCK_SIZE);
+
+ return (int) Math.min(THREADS_MANAGED_BY_ONE_CPU * processors,
+ THREADS_MANAGED_BY_ONE_BLOCK * blocks);
+ }
+
+ /**
+ * Returns the number of processors available to the Java virtual machine.
+ *
+ * @return number of processors available to the Java virtual machine.
+ *
+ * @see Runtime#availableProcessors
+ *
+ */
+ public static int availableProcessors() {
+ Runtime runtime = Runtime.getRuntime();
+ return runtime.availableProcessors();
+ }
+
+ /**
+ * Makes a few attempts to print the string into specified PrintStream.
+ * If <code>PrintStream.println(String)</code> throws OutOfMemoryError,
+ * the method waits for a few milliseconds and repeats the attempt.
+ *
+ * @param out PrintStream to print the string.
+ * @param s the string to print.
+ */
+ public static void tryToPrintln(PrintStream out, String s) {
+ for (int i = 0; i < ATTEMPTS_TO_PRINT; i++) {
+ try {
+ out.println(s);
+
+ // The string is printed into the PrintStream
+ return;
+ } catch (OutOfMemoryError e) {
+
+ // Catch the error and wait for a while
+ synchronized(object) {
+ try {
+ object.wait(500);
+ } catch (InterruptedException ie) {
+
+ // Ignore the exception
+ }
+ } // synchronized
+ }
+ }
+ } // tryToPrintln()
+
+ /**
+ * Makes a few attempts to print each stack trace of <code>Throwable</code>
+ * into specified PrintStream. If <code>PrintStream.println(String)</code>
+ * throws OutOfMemoryError, the method waits for a few milliseconds and
+ * repeats the attempt.
+ *
+ * @param out PrintStream to print the string.
+ * @param t the throwable to print.
+ *
+ * @see #tryToPrintln
+ */
+ public static void tryToPrintStack(PrintStream out, Throwable t) {
+ StackTraceElement[] trace = t.getStackTrace();
+
+ for (int i = 0; i < trace.length; i++) {
+ for (int j = 0; j < ATTEMPTS_TO_PRINT; j++) {
+ try {
+ out.println(trace[i].toString());
+
+ // The string is printed into the PrintStream
+ return;
+ } catch (OutOfMemoryError e) {
+
+ // Catch the error and wait for a while
+ synchronized(object) {
+ try {
+ object.wait(500);
+ } catch (InterruptedException ie) {
+
+ // Ignore the exception
+ }
+ } // synchronized
+ } // try
+ } // for j
+ } // for i
+ } // tryToPrintStack()
+
+ /**
+ * Returns recommended size for an array. Default implemetation returns
+ * minimum between <code>size</code> and
+ * {@link #MAX_ARRAY_SIZE MAX_ARRAY_SIZE}.
+ *
+ * @return recommended size for an array.
+ *
+ */
+ public static int getArraySize(long size) {
+ long min = Math.min(MAX_ARRAY_SIZE, size);
+ return (int) min;
+ } // getArraySize()
+} // class Algorithms
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllDiag.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.runner.RunParams;
+
+/**
+ * Helper that prints information about AllMemoryObjects.
+ */
+public class AllDiag implements Runnable {
+ private long sleepTime;
+
+ public AllDiag() {
+ this(RunParams.getInstance().getSleepTime());
+ }
+
+ public AllDiag(long sleepTime) {
+ this.sleepTime = sleepTime;
+ }
+
+ public void run() {
+ AllMemoryObject.dumpStatistics();
+ // Ensure that interrupt status is not lost
+ if (Thread.currentThread().isInterrupted())
+ return;
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/AllMemoryObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.PrintStream;
+
+/**
+ * An object that occupies approximately given number of bytes in memory
+ * and also records number of allocated instances.
+ */
+public class AllMemoryObject extends MemoryObject {
+ private static int allocatedCount;
+
+ public AllMemoryObject(int size) {
+ super(size);
+ synchronized (AllMemoryObject.class) {
+ ++allocatedCount;
+ }
+ }
+
+ /**
+ * Returns the number of allocated FinMemoryObjects.
+ */
+ public static int getAllocatedCount() {
+ return allocatedCount;
+ }
+
+ public static void dumpStatistics(PrintStream out) {
+ out.println("Object count: " + getAllocatedCount());
+ }
+
+ public static void dumpStatistics() {
+ dumpStatistics(System.out);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ArgumentHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.*;
+
+/**
+ * Parser for GC tests' arguments.
+ * <p>
+ * <code>ArgumentHandler</code> handles specific command line arguments
+ * related to way of execution of a test in addition to general arguments
+ * recognized by {@link ArgumentParser <code>ArgumentParser</code>}.
+ * <p>
+ * Following is the list of specific options for <code>ArgumentHandler</code>:
+ * <ul>
+ * <li><code>-iterations="<i>value</i>"</code>, where <i>value</i> must either
+ * be "infinity", or an integer number, greater than 0. This parameter
+ * specifies the number of iterations to run the testcase. If the value is
+ * "infinity", then the test will be run for at least <code>gcTimeout</code>
+ * minutes. Otherwise, the testcase will be repeated for
+ * <code>iterations</code> times.
+ * <li><code>-gcTimeout="<i>value</i>"</code>, where <i>value</i> must be an
+ * integer number, greater than 0. If <i>infinity</i> is set to
+ * <code>iterations</code>, then the test consider <code>gcTimeout</code>
+ * argument to run the test for at least specified number of minutes.
+ * <li><code>-threads="<i>value</i>"</code>, where <i>value</i> must be an
+ * integer number, greater than 0. A user may specify the number of threads
+ * to start in the test with that paramenter. However, a test may ignore
+ * this value, if it does know the number of threads to start. It
+ * depends on a test: read its README file.
+ * <li><code>-memoryEater="<i>value</i>"</code>, where <i>value</i> must be
+ * either "single", or "multi" string. This argument specifies if a single
+ * thread should be used to eat the whole heap or not. If "multi" string is
+ * assigned to <code>-memoryEater</code>, then a number of threads will be
+ * started to eat the heap. The number is equal to number of available
+ * processors plus 1.
+ * <li><code>-largeClassesPath="<i>value</i>"</code>, where <i>value</i> is a
+ * directory to load large classes from.
+ * <li><code>-fieldsLimitation="<i>value</i>"</code>, where <i>value</i> must
+ * be either "over", or "under" string. This argument specifies what classes
+ * should be loaded from <code>largeClassesPath</code> directory. If
+ * <i>over</i> is set, then the classes that have number of fileds over
+ * JVM limitation should be loaded, otherwise -- classes that have number
+ * of fileds under limitation.
+ * </ul>
+ * @see ArgumentParser
+ */
+public class ArgumentHandler extends ArgumentParser {
+
+ // Define all possible arguments
+ private final static String ITERATIONS = "iterations";
+ private final static String AGGREGATION_DEPTH = "aggregationDepth";
+ private final static String GC_TIMEOUT = "gcTimeout";
+ private final static String THREADS = "threads";
+ private final static String MEM_EATER = "memoryEater";
+ private final static String LARGE_CLASSES_PATH = "largeClassesPath";
+ private final static String FIELDS_LIMITATION = "fieldsLimitation";
+
+ // An acceptible value for ITERATIONS
+ private final static String INFINITY = "infinity";
+
+ // Acceptible values for MEM_EATER
+ private final static String ME_SINGLE = "single";
+ private final static String ME_MULTI = "multi";
+
+ // Acceptible values for FIELDS_LIMITATION
+ private final static String FL_OVER = "over";
+ private final static String FL_UNDER = "under";
+
+ /**
+ * Keep a copy of raw command-line arguments and parse them;
+ * but throw an exception on parsing error.
+ *
+ * @param args Array of the raw command-line arguments.
+ *
+ * @throws BadOption If unknown option or illegal option value found
+ *
+ * @see ArgumentParser
+ */
+ public ArgumentHandler(String args[]) {
+ super(args);
+ }
+
+ /**
+ * Returns number of iterations.
+ * <p>
+ * If <code>-iterations="<i>infinity</i>"</code>, the method returns -1.
+ * If the argument is not set, the method returns 1. Otherwise, the
+ * specified number is returned.
+ *
+ * @return number of iterations.
+ *
+ */
+ public int getIterations() {
+ String value = options.getProperty(ITERATIONS, "1");
+
+ if (INFINITY.equals(value))
+ return -1;
+
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not an integer value of \"" + ITERATIONS
+ + "\" argument: " + value);
+ }
+ }
+
+
+ /**
+ * Returns the depth of object aggregation.
+ * <p>
+ * If the argument is not set, the method returns 0. Otherwise, the
+ * specified number is returned.
+ *
+ * @return number of aggregation depth.
+ *
+ */
+ public int getAggregationDepth() {
+ String value = options.getProperty(AGGREGATION_DEPTH, "0");
+
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not an integer value of \"" + AGGREGATION_DEPTH
+ + "\" argument: " + value);
+ }
+ }
+
+
+ /**
+ * Returns number of minutes to run the test.
+ * <p>
+ * @return number of minutes to run the test.
+ *
+ */
+ public int getGCTimeout() {
+ String value = options.getProperty(GC_TIMEOUT);
+
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("\"" + GC_TIMEOUT + "\" argument is not defined "
+ + "or is not integer: " + value);
+ }
+ }
+
+ /**
+ * Returns a directory to load large classes from.
+ * <p>
+ * @return a directory to load large classes from.
+ *
+ */
+ public String getLargeClassesPath() {
+ return options.getProperty(LARGE_CLASSES_PATH);
+ }
+
+ /**
+ * Returns number of threads to start in a test. If <code>threads</code>
+ * is not set, the method returns specified number of threads.
+ * <p>
+ * @param defaultValue default value, if <code>threads</code> is not set.
+ * @return number of threads to start in a test.
+ *
+ */
+ public int getThreads(int defaultValue) {
+ String value = options.getProperty(THREADS);
+
+ if (value == null)
+ return defaultValue;
+
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not an integer value of \"" + THREADS
+ + "\" argument: " + value);
+ }
+ }
+
+ /**
+ * Returns true if single thread should be used to eat the whole heap,
+ * false otherwise.
+ *
+ * @return true if single thread should be used to eat the whole heap,
+ * false otherwise.
+ *
+ */
+ public boolean isSingleMemoryEater() {
+ String value = options.getProperty(MEM_EATER);
+
+ if (value == null)
+ return true;
+ else if (value.equals(ME_SINGLE))
+ return true;
+ else if (value.equals(ME_MULTI))
+ return false;
+ else
+ throw new TestBug("Value for \"" + MEM_EATER + "\" must be either "
+ + ME_SINGLE + ", or " + ME_MULTI);
+ }
+
+ /**
+ * Returns true if classes with number of fileds over limitation should be
+ * loaded, false otherwise.
+ *
+ * @return true if classes with number of fileds over limitation should be
+ * loaded, false otherwise.
+ *
+ */
+ public boolean isOverFieldsLimitation() {
+ String value = options.getProperty(FIELDS_LIMITATION);
+
+ if (value == null)
+ return false;
+ else if (value.equals(FL_OVER))
+ return true;
+ else if (value.equals(FL_UNDER))
+ return false;
+ else
+ throw new TestBug("Value for \"" + FIELDS_LIMITATION + "\" must be "
+ + "either " + FL_OVER + ", or " + FL_UNDER);
+ }
+
+ /**
+ * Checks if an option is allowed and has proper value.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @param option option name
+ * @param value string representation of value
+ * (could be an empty string too)
+ * null if this option has no value
+ * @return <i>true</i> if option is allowed and has proper value,
+ * <i>false</i> if option is not admissible
+ *
+ * @throws <i>BadOption</i> if option has an illegal value
+ *
+ * @see #parseArguments()
+ */
+ protected boolean checkOption(String option, String value) {
+
+ // Define iterations
+ if (option.equals(ITERATIONS)) {
+ if (INFINITY.equals(value))
+ return true;
+
+ try {
+ int number = Integer.parseInt(value);
+
+ if (number < 1)
+ throw new BadOption(option + ": value must be greater than "
+ + "zero.");
+ } catch (NumberFormatException e) {
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be integer or \"" + INFINITY + "\": "
+ + value);
+ }
+ return true;
+ }
+
+ // Define timeout
+ if (option.equals(GC_TIMEOUT)) {
+ try {
+ int number = Integer.parseInt(value);
+
+ if (number < 0)
+ throw new BadOption(option + ": value must be a positive "
+ + "integer");
+ } catch (NumberFormatException e) {
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be integer: " + value);
+ }
+ return true;
+ }
+
+ // Define threads
+ if (option.equals(THREADS)) {
+ try {
+ int number = Integer.parseInt(value);
+
+ if (number < 0)
+ throw new BadOption(option + ": value must be a positive "
+ + "integer");
+ } catch (NumberFormatException e) {
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be integer: " + value);
+ }
+ return true;
+ }
+
+ // Define path to large classes
+ if (option.equals(LARGE_CLASSES_PATH))
+ return true;
+
+ // Define memory eater
+ if (option.equals(MEM_EATER)) {
+ if ( (ME_SINGLE.equals(value)) || (ME_MULTI.equals(value)) )
+ return true;
+ else
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be either " + ME_SINGLE + ", or "
+ + ME_MULTI + ": " + value);
+ }
+
+ // Define fields limitation
+ if (option.equals(FIELDS_LIMITATION)) {
+ if ( (FL_OVER.equals(value)) || (FL_UNDER.equals(value)) )
+ return true;
+ else
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be either " + FL_OVER + ", or "
+ + FL_UNDER + ": " + value);
+ }
+
+ // Define aggregationDepth
+ if (option.equals(AGGREGATION_DEPTH)) {
+ try {
+ int number = Integer.parseInt(value);
+
+ if (number < 0)
+ throw new BadOption(option + ": value must be a positive "
+ + "integer");
+ } catch (NumberFormatException e) {
+ throw new BadOption("Value for option \"" + option + "\" must "
+ + "be integer: " + value);
+ }
+ return true;
+ }
+
+ return super.checkOption(option, value);
+ }
+
+ /**
+ * Checks if the values of all options are consistent.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @throws <i>BadOption</i> if options have inconsistent values
+ *
+ * @see ArgumentParser#parseArguments()
+ */
+ protected void checkOptions() {
+ super.checkOptions();
+ }
+} // ArgumentHandler
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Cell.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.gc.MemoryObject;
+
+public class Cell extends MemoryObject {
+ private int number;
+
+ public Cell(int size, int number) {
+ super(size - 4);
+ setNumber(number);
+ }
+
+ public final int getNumber() {
+ return number;
+ }
+
+ public final void setNumber(int number) {
+ this.number = number;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/CircularLinkedList.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+public class CircularLinkedList {
+ private int objectSize;
+ private LinkedMemoryObject root;
+
+ /**
+ * Create empty circular linked list.
+ *
+ * @param objectSize size of each node in the list
+ */
+ public CircularLinkedList(int objectSize) {
+ this.objectSize = objectSize;
+ }
+
+ /**
+ * Insert new node in the list.
+ */
+ public void grow() {
+ LinkedMemoryObject newnode = new LinkedMemoryObject(objectSize);
+ if (root == null){
+ root = newnode;
+ root.setNext(root);
+ root.setPrev(root);
+ } else {
+ newnode.setNext(root.getNext());
+ root.getNext().setPrev(newnode);
+ root.setNext(newnode);
+ newnode.setPrev(root);
+ }
+ }
+
+ /**
+ * Get length of the list.
+ *
+ * @return length
+ */
+ public int getLength() {
+ return Memory.getListLength(root);
+ }
+
+ /**
+ * Get length of another list.
+ *
+ * @param list another list
+ * @return length of list
+ */
+ public int getLength(CircularLinkedList list) {
+ return Memory.getListLength(list.root);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ClassChain.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,5035 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+/**
+ * Object with long dependency chain.
+ *
+ * Instantiation of this class forces loading of all classes Class*.
+ */
+public class ClassChain {
+ public ClassChain(){
+ new Class1();
+ }
+}
+
+class Class1 {
+ public Class1(){
+ new Class2();
+ }
+}
+class Class2 {
+ public Class2(){
+ new Class3();
+ }
+}
+class Class3 {
+ public Class3(){
+ new Class4();
+ }
+}
+class Class4 {
+ public Class4(){
+ new Class5();
+ }
+}
+class Class5 {
+ public Class5(){
+ new Class6();
+ }
+}
+class Class6 {
+ public Class6(){
+ new Class7();
+ }
+}
+class Class7 {
+ public Class7(){
+ new Class8();
+ }
+}
+class Class8 {
+ public Class8(){
+ new Class9();
+ }
+}
+class Class9 {
+ public Class9(){
+ new Class10();
+ }
+}
+class Class10 {
+ public Class10(){
+ new Class11();
+ }
+}
+class Class11 {
+ public Class11(){
+ new Class12();
+ }
+}
+class Class12 {
+ public Class12(){
+ new Class13();
+ }
+}
+class Class13 {
+ public Class13(){
+ new Class14();
+ }
+}
+class Class14 {
+ public Class14(){
+ new Class15();
+ }
+}
+class Class15 {
+ public Class15(){
+ new Class16();
+ }
+}
+class Class16 {
+ public Class16(){
+ new Class17();
+ }
+}
+class Class17 {
+ public Class17(){
+ new Class18();
+ }
+}
+class Class18 {
+ public Class18(){
+ new Class19();
+ }
+}
+class Class19 {
+ public Class19(){
+ new Class20();
+ }
+}
+class Class20 {
+ public Class20(){
+ new Class21();
+ }
+}
+class Class21 {
+ public Class21(){
+ new Class22();
+ }
+}
+class Class22 {
+ public Class22(){
+ new Class23();
+ }
+}
+class Class23 {
+ public Class23(){
+ new Class24();
+ }
+}
+class Class24 {
+ public Class24(){
+ new Class25();
+ }
+}
+class Class25 {
+ public Class25(){
+ new Class26();
+ }
+}
+class Class26 {
+ public Class26(){
+ new Class27();
+ }
+}
+class Class27 {
+ public Class27(){
+ new Class28();
+ }
+}
+class Class28 {
+ public Class28(){
+ new Class29();
+ }
+}
+class Class29 {
+ public Class29(){
+ new Class30();
+ }
+}
+class Class30 {
+ public Class30(){
+ new Class31();
+ }
+}
+class Class31 {
+ public Class31(){
+ new Class32();
+ }
+}
+class Class32 {
+ public Class32(){
+ new Class33();
+ }
+}
+class Class33 {
+ public Class33(){
+ new Class34();
+ }
+}
+class Class34 {
+ public Class34(){
+ new Class35();
+ }
+}
+class Class35 {
+ public Class35(){
+ new Class36();
+ }
+}
+class Class36 {
+ public Class36(){
+ new Class37();
+ }
+}
+class Class37 {
+ public Class37(){
+ new Class38();
+ }
+}
+class Class38 {
+ public Class38(){
+ new Class39();
+ }
+}
+class Class39 {
+ public Class39(){
+ new Class40();
+ }
+}
+class Class40 {
+ public Class40(){
+ new Class41();
+ }
+}
+class Class41 {
+ public Class41(){
+ new Class42();
+ }
+}
+class Class42 {
+ public Class42(){
+ new Class43();
+ }
+}
+class Class43 {
+ public Class43(){
+ new Class44();
+ }
+}
+class Class44 {
+ public Class44(){
+ new Class45();
+ }
+}
+class Class45 {
+ public Class45(){
+ new Class46();
+ }
+}
+class Class46 {
+ public Class46(){
+ new Class47();
+ }
+}
+class Class47 {
+ public Class47(){
+ new Class48();
+ }
+}
+class Class48 {
+ public Class48(){
+ new Class49();
+ }
+}
+class Class49 {
+ public Class49(){
+ new Class50();
+ }
+}
+class Class50 {
+ public Class50(){
+ new Class51();
+ }
+}
+class Class51 {
+ public Class51(){
+ new Class52();
+ }
+}
+class Class52 {
+ public Class52(){
+ new Class53();
+ }
+}
+class Class53 {
+ public Class53(){
+ new Class54();
+ }
+}
+class Class54 {
+ public Class54(){
+ new Class55();
+ }
+}
+class Class55 {
+ public Class55(){
+ new Class56();
+ }
+}
+class Class56 {
+ public Class56(){
+ new Class57();
+ }
+}
+class Class57 {
+ public Class57(){
+ new Class58();
+ }
+}
+class Class58 {
+ public Class58(){
+ new Class59();
+ }
+}
+class Class59 {
+ public Class59(){
+ new Class60();
+ }
+}
+class Class60 {
+ public Class60(){
+ new Class61();
+ }
+}
+class Class61 {
+ public Class61(){
+ new Class62();
+ }
+}
+class Class62 {
+ public Class62(){
+ new Class63();
+ }
+}
+class Class63 {
+ public Class63(){
+ new Class64();
+ }
+}
+class Class64 {
+ public Class64(){
+ new Class65();
+ }
+}
+class Class65 {
+ public Class65(){
+ new Class66();
+ }
+}
+class Class66 {
+ public Class66(){
+ new Class67();
+ }
+}
+class Class67 {
+ public Class67(){
+ new Class68();
+ }
+}
+class Class68 {
+ public Class68(){
+ new Class69();
+ }
+}
+class Class69 {
+ public Class69(){
+ new Class70();
+ }
+}
+class Class70 {
+ public Class70(){
+ new Class71();
+ }
+}
+class Class71 {
+ public Class71(){
+ new Class72();
+ }
+}
+class Class72 {
+ public Class72(){
+ new Class73();
+ }
+}
+class Class73 {
+ public Class73(){
+ new Class74();
+ }
+}
+class Class74 {
+ public Class74(){
+ new Class75();
+ }
+}
+class Class75 {
+ public Class75(){
+ new Class76();
+ }
+}
+class Class76 {
+ public Class76(){
+ new Class77();
+ }
+}
+class Class77 {
+ public Class77(){
+ new Class78();
+ }
+}
+class Class78 {
+ public Class78(){
+ new Class79();
+ }
+}
+class Class79 {
+ public Class79(){
+ new Class80();
+ }
+}
+class Class80 {
+ public Class80(){
+ new Class81();
+ }
+}
+class Class81 {
+ public Class81(){
+ new Class82();
+ }
+}
+class Class82 {
+ public Class82(){
+ new Class83();
+ }
+}
+class Class83 {
+ public Class83(){
+ new Class84();
+ }
+}
+class Class84 {
+ public Class84(){
+ new Class85();
+ }
+}
+class Class85 {
+ public Class85(){
+ new Class86();
+ }
+}
+class Class86 {
+ public Class86(){
+ new Class87();
+ }
+}
+class Class87 {
+ public Class87(){
+ new Class88();
+ }
+}
+class Class88 {
+ public Class88(){
+ new Class89();
+ }
+}
+class Class89 {
+ public Class89(){
+ new Class90();
+ }
+}
+class Class90 {
+ public Class90(){
+ new Class91();
+ }
+}
+class Class91 {
+ public Class91(){
+ new Class92();
+ }
+}
+class Class92 {
+ public Class92(){
+ new Class93();
+ }
+}
+class Class93 {
+ public Class93(){
+ new Class94();
+ }
+}
+class Class94 {
+ public Class94(){
+ new Class95();
+ }
+}
+class Class95 {
+ public Class95(){
+ new Class96();
+ }
+}
+class Class96 {
+ public Class96(){
+ new Class97();
+ }
+}
+class Class97 {
+ public Class97(){
+ new Class98();
+ }
+}
+class Class98 {
+ public Class98(){
+ new Class99();
+ }
+}
+class Class99 {
+ public Class99(){
+ new Class100();
+ }
+}
+class Class100 {
+ public Class100(){
+ new Class101();
+ }
+}
+class Class101 {
+ public Class101(){
+ new Class102();
+ }
+}
+class Class102 {
+ public Class102(){
+ new Class103();
+ }
+}
+class Class103 {
+ public Class103(){
+ new Class104();
+ }
+}
+class Class104 {
+ public Class104(){
+ new Class105();
+ }
+}
+class Class105 {
+ public Class105(){
+ new Class106();
+ }
+}
+class Class106 {
+ public Class106(){
+ new Class107();
+ }
+}
+class Class107 {
+ public Class107(){
+ new Class108();
+ }
+}
+class Class108 {
+ public Class108(){
+ new Class109();
+ }
+}
+class Class109 {
+ public Class109(){
+ new Class110();
+ }
+}
+class Class110 {
+ public Class110(){
+ new Class111();
+ }
+}
+class Class111 {
+ public Class111(){
+ new Class112();
+ }
+}
+class Class112 {
+ public Class112(){
+ new Class113();
+ }
+}
+class Class113 {
+ public Class113(){
+ new Class114();
+ }
+}
+class Class114 {
+ public Class114(){
+ new Class115();
+ }
+}
+class Class115 {
+ public Class115(){
+ new Class116();
+ }
+}
+class Class116 {
+ public Class116(){
+ new Class117();
+ }
+}
+class Class117 {
+ public Class117(){
+ new Class118();
+ }
+}
+class Class118 {
+ public Class118(){
+ new Class119();
+ }
+}
+class Class119 {
+ public Class119(){
+ new Class120();
+ }
+}
+class Class120 {
+ public Class120(){
+ new Class121();
+ }
+}
+class Class121 {
+ public Class121(){
+ new Class122();
+ }
+}
+class Class122 {
+ public Class122(){
+ new Class123();
+ }
+}
+class Class123 {
+ public Class123(){
+ new Class124();
+ }
+}
+class Class124 {
+ public Class124(){
+ new Class125();
+ }
+}
+class Class125 {
+ public Class125(){
+ new Class126();
+ }
+}
+class Class126 {
+ public Class126(){
+ new Class127();
+ }
+}
+class Class127 {
+ public Class127(){
+ new Class128();
+ }
+}
+class Class128 {
+ public Class128(){
+ new Class129();
+ }
+}
+class Class129 {
+ public Class129(){
+ new Class130();
+ }
+}
+class Class130 {
+ public Class130(){
+ new Class131();
+ }
+}
+class Class131 {
+ public Class131(){
+ new Class132();
+ }
+}
+class Class132 {
+ public Class132(){
+ new Class133();
+ }
+}
+class Class133 {
+ public Class133(){
+ new Class134();
+ }
+}
+class Class134 {
+ public Class134(){
+ new Class135();
+ }
+}
+class Class135 {
+ public Class135(){
+ new Class136();
+ }
+}
+class Class136 {
+ public Class136(){
+ new Class137();
+ }
+}
+class Class137 {
+ public Class137(){
+ new Class138();
+ }
+}
+class Class138 {
+ public Class138(){
+ new Class139();
+ }
+}
+class Class139 {
+ public Class139(){
+ new Class140();
+ }
+}
+class Class140 {
+ public Class140(){
+ new Class141();
+ }
+}
+class Class141 {
+ public Class141(){
+ new Class142();
+ }
+}
+class Class142 {
+ public Class142(){
+ new Class143();
+ }
+}
+class Class143 {
+ public Class143(){
+ new Class144();
+ }
+}
+class Class144 {
+ public Class144(){
+ new Class145();
+ }
+}
+class Class145 {
+ public Class145(){
+ new Class146();
+ }
+}
+class Class146 {
+ public Class146(){
+ new Class147();
+ }
+}
+class Class147 {
+ public Class147(){
+ new Class148();
+ }
+}
+class Class148 {
+ public Class148(){
+ new Class149();
+ }
+}
+class Class149 {
+ public Class149(){
+ new Class150();
+ }
+}
+class Class150 {
+ public Class150(){
+ new Class151();
+ }
+}
+class Class151 {
+ public Class151(){
+ new Class152();
+ }
+}
+class Class152 {
+ public Class152(){
+ new Class153();
+ }
+}
+class Class153 {
+ public Class153(){
+ new Class154();
+ }
+}
+class Class154 {
+ public Class154(){
+ new Class155();
+ }
+}
+class Class155 {
+ public Class155(){
+ new Class156();
+ }
+}
+class Class156 {
+ public Class156(){
+ new Class157();
+ }
+}
+class Class157 {
+ public Class157(){
+ new Class158();
+ }
+}
+class Class158 {
+ public Class158(){
+ new Class159();
+ }
+}
+class Class159 {
+ public Class159(){
+ new Class160();
+ }
+}
+class Class160 {
+ public Class160(){
+ new Class161();
+ }
+}
+class Class161 {
+ public Class161(){
+ new Class162();
+ }
+}
+class Class162 {
+ public Class162(){
+ new Class163();
+ }
+}
+class Class163 {
+ public Class163(){
+ new Class164();
+ }
+}
+class Class164 {
+ public Class164(){
+ new Class165();
+ }
+}
+class Class165 {
+ public Class165(){
+ new Class166();
+ }
+}
+class Class166 {
+ public Class166(){
+ new Class167();
+ }
+}
+class Class167 {
+ public Class167(){
+ new Class168();
+ }
+}
+class Class168 {
+ public Class168(){
+ new Class169();
+ }
+}
+class Class169 {
+ public Class169(){
+ new Class170();
+ }
+}
+class Class170 {
+ public Class170(){
+ new Class171();
+ }
+}
+class Class171 {
+ public Class171(){
+ new Class172();
+ }
+}
+class Class172 {
+ public Class172(){
+ new Class173();
+ }
+}
+class Class173 {
+ public Class173(){
+ new Class174();
+ }
+}
+class Class174 {
+ public Class174(){
+ new Class175();
+ }
+}
+class Class175 {
+ public Class175(){
+ new Class176();
+ }
+}
+class Class176 {
+ public Class176(){
+ new Class177();
+ }
+}
+class Class177 {
+ public Class177(){
+ new Class178();
+ }
+}
+class Class178 {
+ public Class178(){
+ new Class179();
+ }
+}
+class Class179 {
+ public Class179(){
+ new Class180();
+ }
+}
+class Class180 {
+ public Class180(){
+ new Class181();
+ }
+}
+class Class181 {
+ public Class181(){
+ new Class182();
+ }
+}
+class Class182 {
+ public Class182(){
+ new Class183();
+ }
+}
+class Class183 {
+ public Class183(){
+ new Class184();
+ }
+}
+class Class184 {
+ public Class184(){
+ new Class185();
+ }
+}
+class Class185 {
+ public Class185(){
+ new Class186();
+ }
+}
+class Class186 {
+ public Class186(){
+ new Class187();
+ }
+}
+class Class187 {
+ public Class187(){
+ new Class188();
+ }
+}
+class Class188 {
+ public Class188(){
+ new Class189();
+ }
+}
+class Class189 {
+ public Class189(){
+ new Class190();
+ }
+}
+class Class190 {
+ public Class190(){
+ new Class191();
+ }
+}
+class Class191 {
+ public Class191(){
+ new Class192();
+ }
+}
+class Class192 {
+ public Class192(){
+ new Class193();
+ }
+}
+class Class193 {
+ public Class193(){
+ new Class194();
+ }
+}
+class Class194 {
+ public Class194(){
+ new Class195();
+ }
+}
+class Class195 {
+ public Class195(){
+ new Class196();
+ }
+}
+class Class196 {
+ public Class196(){
+ new Class197();
+ }
+}
+class Class197 {
+ public Class197(){
+ new Class198();
+ }
+}
+class Class198 {
+ public Class198(){
+ new Class199();
+ }
+}
+class Class199 {
+ public Class199(){
+ new Class200();
+ }
+}
+class Class200 {
+ public Class200(){
+ new Class201();
+ }
+}
+class Class201 {
+ public Class201(){
+ new Class202();
+ }
+}
+class Class202 {
+ public Class202(){
+ new Class203();
+ }
+}
+class Class203 {
+ public Class203(){
+ new Class204();
+ }
+}
+class Class204 {
+ public Class204(){
+ new Class205();
+ }
+}
+class Class205 {
+ public Class205(){
+ new Class206();
+ }
+}
+class Class206 {
+ public Class206(){
+ new Class207();
+ }
+}
+class Class207 {
+ public Class207(){
+ new Class208();
+ }
+}
+class Class208 {
+ public Class208(){
+ new Class209();
+ }
+}
+class Class209 {
+ public Class209(){
+ new Class210();
+ }
+}
+class Class210 {
+ public Class210(){
+ new Class211();
+ }
+}
+class Class211 {
+ public Class211(){
+ new Class212();
+ }
+}
+class Class212 {
+ public Class212(){
+ new Class213();
+ }
+}
+class Class213 {
+ public Class213(){
+ new Class214();
+ }
+}
+class Class214 {
+ public Class214(){
+ new Class215();
+ }
+}
+class Class215 {
+ public Class215(){
+ new Class216();
+ }
+}
+class Class216 {
+ public Class216(){
+ new Class217();
+ }
+}
+class Class217 {
+ public Class217(){
+ new Class218();
+ }
+}
+class Class218 {
+ public Class218(){
+ new Class219();
+ }
+}
+class Class219 {
+ public Class219(){
+ new Class220();
+ }
+}
+class Class220 {
+ public Class220(){
+ new Class221();
+ }
+}
+class Class221 {
+ public Class221(){
+ new Class222();
+ }
+}
+class Class222 {
+ public Class222(){
+ new Class223();
+ }
+}
+class Class223 {
+ public Class223(){
+ new Class224();
+ }
+}
+class Class224 {
+ public Class224(){
+ new Class225();
+ }
+}
+class Class225 {
+ public Class225(){
+ new Class226();
+ }
+}
+class Class226 {
+ public Class226(){
+ new Class227();
+ }
+}
+class Class227 {
+ public Class227(){
+ new Class228();
+ }
+}
+class Class228 {
+ public Class228(){
+ new Class229();
+ }
+}
+class Class229 {
+ public Class229(){
+ new Class230();
+ }
+}
+class Class230 {
+ public Class230(){
+ new Class231();
+ }
+}
+class Class231 {
+ public Class231(){
+ new Class232();
+ }
+}
+class Class232 {
+ public Class232(){
+ new Class233();
+ }
+}
+class Class233 {
+ public Class233(){
+ new Class234();
+ }
+}
+class Class234 {
+ public Class234(){
+ new Class235();
+ }
+}
+class Class235 {
+ public Class235(){
+ new Class236();
+ }
+}
+class Class236 {
+ public Class236(){
+ new Class237();
+ }
+}
+class Class237 {
+ public Class237(){
+ new Class238();
+ }
+}
+class Class238 {
+ public Class238(){
+ new Class239();
+ }
+}
+class Class239 {
+ public Class239(){
+ new Class240();
+ }
+}
+class Class240 {
+ public Class240(){
+ new Class241();
+ }
+}
+class Class241 {
+ public Class241(){
+ new Class242();
+ }
+}
+class Class242 {
+ public Class242(){
+ new Class243();
+ }
+}
+class Class243 {
+ public Class243(){
+ new Class244();
+ }
+}
+class Class244 {
+ public Class244(){
+ new Class245();
+ }
+}
+class Class245 {
+ public Class245(){
+ new Class246();
+ }
+}
+class Class246 {
+ public Class246(){
+ new Class247();
+ }
+}
+class Class247 {
+ public Class247(){
+ new Class248();
+ }
+}
+class Class248 {
+ public Class248(){
+ new Class249();
+ }
+}
+class Class249 {
+ public Class249(){
+ new Class250();
+ }
+}
+class Class250 {
+ public Class250(){
+ new Class251();
+ }
+}
+class Class251 {
+ public Class251(){
+ new Class252();
+ }
+}
+class Class252 {
+ public Class252(){
+ new Class253();
+ }
+}
+class Class253 {
+ public Class253(){
+ new Class254();
+ }
+}
+class Class254 {
+ public Class254(){
+ new Class255();
+ }
+}
+class Class255 {
+ public Class255(){
+ new Class256();
+ }
+}
+class Class256 {
+ public Class256(){
+ new Class257();
+ }
+}
+class Class257 {
+ public Class257(){
+ new Class258();
+ }
+}
+class Class258 {
+ public Class258(){
+ new Class259();
+ }
+}
+class Class259 {
+ public Class259(){
+ new Class260();
+ }
+}
+class Class260 {
+ public Class260(){
+ new Class261();
+ }
+}
+class Class261 {
+ public Class261(){
+ new Class262();
+ }
+}
+class Class262 {
+ public Class262(){
+ new Class263();
+ }
+}
+class Class263 {
+ public Class263(){
+ new Class264();
+ }
+}
+class Class264 {
+ public Class264(){
+ new Class265();
+ }
+}
+class Class265 {
+ public Class265(){
+ new Class266();
+ }
+}
+class Class266 {
+ public Class266(){
+ new Class267();
+ }
+}
+class Class267 {
+ public Class267(){
+ new Class268();
+ }
+}
+class Class268 {
+ public Class268(){
+ new Class269();
+ }
+}
+class Class269 {
+ public Class269(){
+ new Class270();
+ }
+}
+class Class270 {
+ public Class270(){
+ new Class271();
+ }
+}
+class Class271 {
+ public Class271(){
+ new Class272();
+ }
+}
+class Class272 {
+ public Class272(){
+ new Class273();
+ }
+}
+class Class273 {
+ public Class273(){
+ new Class274();
+ }
+}
+class Class274 {
+ public Class274(){
+ new Class275();
+ }
+}
+class Class275 {
+ public Class275(){
+ new Class276();
+ }
+}
+class Class276 {
+ public Class276(){
+ new Class277();
+ }
+}
+class Class277 {
+ public Class277(){
+ new Class278();
+ }
+}
+class Class278 {
+ public Class278(){
+ new Class279();
+ }
+}
+class Class279 {
+ public Class279(){
+ new Class280();
+ }
+}
+class Class280 {
+ public Class280(){
+ new Class281();
+ }
+}
+class Class281 {
+ public Class281(){
+ new Class282();
+ }
+}
+class Class282 {
+ public Class282(){
+ new Class283();
+ }
+}
+class Class283 {
+ public Class283(){
+ new Class284();
+ }
+}
+class Class284 {
+ public Class284(){
+ new Class285();
+ }
+}
+class Class285 {
+ public Class285(){
+ new Class286();
+ }
+}
+class Class286 {
+ public Class286(){
+ new Class287();
+ }
+}
+class Class287 {
+ public Class287(){
+ new Class288();
+ }
+}
+class Class288 {
+ public Class288(){
+ new Class289();
+ }
+}
+class Class289 {
+ public Class289(){
+ new Class290();
+ }
+}
+class Class290 {
+ public Class290(){
+ new Class291();
+ }
+}
+class Class291 {
+ public Class291(){
+ new Class292();
+ }
+}
+class Class292 {
+ public Class292(){
+ new Class293();
+ }
+}
+class Class293 {
+ public Class293(){
+ new Class294();
+ }
+}
+class Class294 {
+ public Class294(){
+ new Class295();
+ }
+}
+class Class295 {
+ public Class295(){
+ new Class296();
+ }
+}
+class Class296 {
+ public Class296(){
+ new Class297();
+ }
+}
+class Class297 {
+ public Class297(){
+ new Class298();
+ }
+}
+class Class298 {
+ public Class298(){
+ new Class299();
+ }
+}
+class Class299 {
+ public Class299(){
+ new Class300();
+ }
+}
+class Class300 {
+ public Class300(){
+ new Class301();
+ }
+}
+class Class301 {
+ public Class301(){
+ new Class302();
+ }
+}
+class Class302 {
+ public Class302(){
+ new Class303();
+ }
+}
+class Class303 {
+ public Class303(){
+ new Class304();
+ }
+}
+class Class304 {
+ public Class304(){
+ new Class305();
+ }
+}
+class Class305 {
+ public Class305(){
+ new Class306();
+ }
+}
+class Class306 {
+ public Class306(){
+ new Class307();
+ }
+}
+class Class307 {
+ public Class307(){
+ new Class308();
+ }
+}
+class Class308 {
+ public Class308(){
+ new Class309();
+ }
+}
+class Class309 {
+ public Class309(){
+ new Class310();
+ }
+}
+class Class310 {
+ public Class310(){
+ new Class311();
+ }
+}
+class Class311 {
+ public Class311(){
+ new Class312();
+ }
+}
+class Class312 {
+ public Class312(){
+ new Class313();
+ }
+}
+class Class313 {
+ public Class313(){
+ new Class314();
+ }
+}
+class Class314 {
+ public Class314(){
+ new Class315();
+ }
+}
+class Class315 {
+ public Class315(){
+ new Class316();
+ }
+}
+class Class316 {
+ public Class316(){
+ new Class317();
+ }
+}
+class Class317 {
+ public Class317(){
+ new Class318();
+ }
+}
+class Class318 {
+ public Class318(){
+ new Class319();
+ }
+}
+class Class319 {
+ public Class319(){
+ new Class320();
+ }
+}
+class Class320 {
+ public Class320(){
+ new Class321();
+ }
+}
+class Class321 {
+ public Class321(){
+ new Class322();
+ }
+}
+class Class322 {
+ public Class322(){
+ new Class323();
+ }
+}
+class Class323 {
+ public Class323(){
+ new Class324();
+ }
+}
+class Class324 {
+ public Class324(){
+ new Class325();
+ }
+}
+class Class325 {
+ public Class325(){
+ new Class326();
+ }
+}
+class Class326 {
+ public Class326(){
+ new Class327();
+ }
+}
+class Class327 {
+ public Class327(){
+ new Class328();
+ }
+}
+class Class328 {
+ public Class328(){
+ new Class329();
+ }
+}
+class Class329 {
+ public Class329(){
+ new Class330();
+ }
+}
+class Class330 {
+ public Class330(){
+ new Class331();
+ }
+}
+class Class331 {
+ public Class331(){
+ new Class332();
+ }
+}
+class Class332 {
+ public Class332(){
+ new Class333();
+ }
+}
+class Class333 {
+ public Class333(){
+ new Class334();
+ }
+}
+class Class334 {
+ public Class334(){
+ new Class335();
+ }
+}
+class Class335 {
+ public Class335(){
+ new Class336();
+ }
+}
+class Class336 {
+ public Class336(){
+ new Class337();
+ }
+}
+class Class337 {
+ public Class337(){
+ new Class338();
+ }
+}
+class Class338 {
+ public Class338(){
+ new Class339();
+ }
+}
+class Class339 {
+ public Class339(){
+ new Class340();
+ }
+}
+class Class340 {
+ public Class340(){
+ new Class341();
+ }
+}
+class Class341 {
+ public Class341(){
+ new Class342();
+ }
+}
+class Class342 {
+ public Class342(){
+ new Class343();
+ }
+}
+class Class343 {
+ public Class343(){
+ new Class344();
+ }
+}
+class Class344 {
+ public Class344(){
+ new Class345();
+ }
+}
+class Class345 {
+ public Class345(){
+ new Class346();
+ }
+}
+class Class346 {
+ public Class346(){
+ new Class347();
+ }
+}
+class Class347 {
+ public Class347(){
+ new Class348();
+ }
+}
+class Class348 {
+ public Class348(){
+ new Class349();
+ }
+}
+class Class349 {
+ public Class349(){
+ new Class350();
+ }
+}
+class Class350 {
+ public Class350(){
+ new Class351();
+ }
+}
+class Class351 {
+ public Class351(){
+ new Class352();
+ }
+}
+class Class352 {
+ public Class352(){
+ new Class353();
+ }
+}
+class Class353 {
+ public Class353(){
+ new Class354();
+ }
+}
+class Class354 {
+ public Class354(){
+ new Class355();
+ }
+}
+class Class355 {
+ public Class355(){
+ new Class356();
+ }
+}
+class Class356 {
+ public Class356(){
+ new Class357();
+ }
+}
+class Class357 {
+ public Class357(){
+ new Class358();
+ }
+}
+class Class358 {
+ public Class358(){
+ new Class359();
+ }
+}
+class Class359 {
+ public Class359(){
+ new Class360();
+ }
+}
+class Class360 {
+ public Class360(){
+ new Class361();
+ }
+}
+class Class361 {
+ public Class361(){
+ new Class362();
+ }
+}
+class Class362 {
+ public Class362(){
+ new Class363();
+ }
+}
+class Class363 {
+ public Class363(){
+ new Class364();
+ }
+}
+class Class364 {
+ public Class364(){
+ new Class365();
+ }
+}
+class Class365 {
+ public Class365(){
+ new Class366();
+ }
+}
+class Class366 {
+ public Class366(){
+ new Class367();
+ }
+}
+class Class367 {
+ public Class367(){
+ new Class368();
+ }
+}
+class Class368 {
+ public Class368(){
+ new Class369();
+ }
+}
+class Class369 {
+ public Class369(){
+ new Class370();
+ }
+}
+class Class370 {
+ public Class370(){
+ new Class371();
+ }
+}
+class Class371 {
+ public Class371(){
+ new Class372();
+ }
+}
+class Class372 {
+ public Class372(){
+ new Class373();
+ }
+}
+class Class373 {
+ public Class373(){
+ new Class374();
+ }
+}
+class Class374 {
+ public Class374(){
+ new Class375();
+ }
+}
+class Class375 {
+ public Class375(){
+ new Class376();
+ }
+}
+class Class376 {
+ public Class376(){
+ new Class377();
+ }
+}
+class Class377 {
+ public Class377(){
+ new Class378();
+ }
+}
+class Class378 {
+ public Class378(){
+ new Class379();
+ }
+}
+class Class379 {
+ public Class379(){
+ new Class380();
+ }
+}
+class Class380 {
+ public Class380(){
+ new Class381();
+ }
+}
+class Class381 {
+ public Class381(){
+ new Class382();
+ }
+}
+class Class382 {
+ public Class382(){
+ new Class383();
+ }
+}
+class Class383 {
+ public Class383(){
+ new Class384();
+ }
+}
+class Class384 {
+ public Class384(){
+ new Class385();
+ }
+}
+class Class385 {
+ public Class385(){
+ new Class386();
+ }
+}
+class Class386 {
+ public Class386(){
+ new Class387();
+ }
+}
+class Class387 {
+ public Class387(){
+ new Class388();
+ }
+}
+class Class388 {
+ public Class388(){
+ new Class389();
+ }
+}
+class Class389 {
+ public Class389(){
+ new Class390();
+ }
+}
+class Class390 {
+ public Class390(){
+ new Class391();
+ }
+}
+class Class391 {
+ public Class391(){
+ new Class392();
+ }
+}
+class Class392 {
+ public Class392(){
+ new Class393();
+ }
+}
+class Class393 {
+ public Class393(){
+ new Class394();
+ }
+}
+class Class394 {
+ public Class394(){
+ new Class395();
+ }
+}
+class Class395 {
+ public Class395(){
+ new Class396();
+ }
+}
+class Class396 {
+ public Class396(){
+ new Class397();
+ }
+}
+class Class397 {
+ public Class397(){
+ new Class398();
+ }
+}
+class Class398 {
+ public Class398(){
+ new Class399();
+ }
+}
+class Class399 {
+ public Class399(){
+ new Class400();
+ }
+}
+class Class400 {
+ public Class400(){
+ new Class401();
+ }
+}
+class Class401 {
+ public Class401(){
+ new Class402();
+ }
+}
+class Class402 {
+ public Class402(){
+ new Class403();
+ }
+}
+class Class403 {
+ public Class403(){
+ new Class404();
+ }
+}
+class Class404 {
+ public Class404(){
+ new Class405();
+ }
+}
+class Class405 {
+ public Class405(){
+ new Class406();
+ }
+}
+class Class406 {
+ public Class406(){
+ new Class407();
+ }
+}
+class Class407 {
+ public Class407(){
+ new Class408();
+ }
+}
+class Class408 {
+ public Class408(){
+ new Class409();
+ }
+}
+class Class409 {
+ public Class409(){
+ new Class410();
+ }
+}
+class Class410 {
+ public Class410(){
+ new Class411();
+ }
+}
+class Class411 {
+ public Class411(){
+ new Class412();
+ }
+}
+class Class412 {
+ public Class412(){
+ new Class413();
+ }
+}
+class Class413 {
+ public Class413(){
+ new Class414();
+ }
+}
+class Class414 {
+ public Class414(){
+ new Class415();
+ }
+}
+class Class415 {
+ public Class415(){
+ new Class416();
+ }
+}
+class Class416 {
+ public Class416(){
+ new Class417();
+ }
+}
+class Class417 {
+ public Class417(){
+ new Class418();
+ }
+}
+class Class418 {
+ public Class418(){
+ new Class419();
+ }
+}
+class Class419 {
+ public Class419(){
+ new Class420();
+ }
+}
+class Class420 {
+ public Class420(){
+ new Class421();
+ }
+}
+class Class421 {
+ public Class421(){
+ new Class422();
+ }
+}
+class Class422 {
+ public Class422(){
+ new Class423();
+ }
+}
+class Class423 {
+ public Class423(){
+ new Class424();
+ }
+}
+class Class424 {
+ public Class424(){
+ new Class425();
+ }
+}
+class Class425 {
+ public Class425(){
+ new Class426();
+ }
+}
+class Class426 {
+ public Class426(){
+ new Class427();
+ }
+}
+class Class427 {
+ public Class427(){
+ new Class428();
+ }
+}
+class Class428 {
+ public Class428(){
+ new Class429();
+ }
+}
+class Class429 {
+ public Class429(){
+ new Class430();
+ }
+}
+class Class430 {
+ public Class430(){
+ new Class431();
+ }
+}
+class Class431 {
+ public Class431(){
+ new Class432();
+ }
+}
+class Class432 {
+ public Class432(){
+ new Class433();
+ }
+}
+class Class433 {
+ public Class433(){
+ new Class434();
+ }
+}
+class Class434 {
+ public Class434(){
+ new Class435();
+ }
+}
+class Class435 {
+ public Class435(){
+ new Class436();
+ }
+}
+class Class436 {
+ public Class436(){
+ new Class437();
+ }
+}
+class Class437 {
+ public Class437(){
+ new Class438();
+ }
+}
+class Class438 {
+ public Class438(){
+ new Class439();
+ }
+}
+class Class439 {
+ public Class439(){
+ new Class440();
+ }
+}
+class Class440 {
+ public Class440(){
+ new Class441();
+ }
+}
+class Class441 {
+ public Class441(){
+ new Class442();
+ }
+}
+class Class442 {
+ public Class442(){
+ new Class443();
+ }
+}
+class Class443 {
+ public Class443(){
+ new Class444();
+ }
+}
+class Class444 {
+ public Class444(){
+ new Class445();
+ }
+}
+class Class445 {
+ public Class445(){
+ new Class446();
+ }
+}
+class Class446 {
+ public Class446(){
+ new Class447();
+ }
+}
+class Class447 {
+ public Class447(){
+ new Class448();
+ }
+}
+class Class448 {
+ public Class448(){
+ new Class449();
+ }
+}
+class Class449 {
+ public Class449(){
+ new Class450();
+ }
+}
+class Class450 {
+ public Class450(){
+ new Class451();
+ }
+}
+class Class451 {
+ public Class451(){
+ new Class452();
+ }
+}
+class Class452 {
+ public Class452(){
+ new Class453();
+ }
+}
+class Class453 {
+ public Class453(){
+ new Class454();
+ }
+}
+class Class454 {
+ public Class454(){
+ new Class455();
+ }
+}
+class Class455 {
+ public Class455(){
+ new Class456();
+ }
+}
+class Class456 {
+ public Class456(){
+ new Class457();
+ }
+}
+class Class457 {
+ public Class457(){
+ new Class458();
+ }
+}
+class Class458 {
+ public Class458(){
+ new Class459();
+ }
+}
+class Class459 {
+ public Class459(){
+ new Class460();
+ }
+}
+class Class460 {
+ public Class460(){
+ new Class461();
+ }
+}
+class Class461 {
+ public Class461(){
+ new Class462();
+ }
+}
+class Class462 {
+ public Class462(){
+ new Class463();
+ }
+}
+class Class463 {
+ public Class463(){
+ new Class464();
+ }
+}
+class Class464 {
+ public Class464(){
+ new Class465();
+ }
+}
+class Class465 {
+ public Class465(){
+ new Class466();
+ }
+}
+class Class466 {
+ public Class466(){
+ new Class467();
+ }
+}
+class Class467 {
+ public Class467(){
+ new Class468();
+ }
+}
+class Class468 {
+ public Class468(){
+ new Class469();
+ }
+}
+class Class469 {
+ public Class469(){
+ new Class470();
+ }
+}
+class Class470 {
+ public Class470(){
+ new Class471();
+ }
+}
+class Class471 {
+ public Class471(){
+ new Class472();
+ }
+}
+class Class472 {
+ public Class472(){
+ new Class473();
+ }
+}
+class Class473 {
+ public Class473(){
+ new Class474();
+ }
+}
+class Class474 {
+ public Class474(){
+ new Class475();
+ }
+}
+class Class475 {
+ public Class475(){
+ new Class476();
+ }
+}
+class Class476 {
+ public Class476(){
+ new Class477();
+ }
+}
+class Class477 {
+ public Class477(){
+ new Class478();
+ }
+}
+class Class478 {
+ public Class478(){
+ new Class479();
+ }
+}
+class Class479 {
+ public Class479(){
+ new Class480();
+ }
+}
+class Class480 {
+ public Class480(){
+ new Class481();
+ }
+}
+class Class481 {
+ public Class481(){
+ new Class482();
+ }
+}
+class Class482 {
+ public Class482(){
+ new Class483();
+ }
+}
+class Class483 {
+ public Class483(){
+ new Class484();
+ }
+}
+class Class484 {
+ public Class484(){
+ new Class485();
+ }
+}
+class Class485 {
+ public Class485(){
+ new Class486();
+ }
+}
+class Class486 {
+ public Class486(){
+ new Class487();
+ }
+}
+class Class487 {
+ public Class487(){
+ new Class488();
+ }
+}
+class Class488 {
+ public Class488(){
+ new Class489();
+ }
+}
+class Class489 {
+ public Class489(){
+ new Class490();
+ }
+}
+class Class490 {
+ public Class490(){
+ new Class491();
+ }
+}
+class Class491 {
+ public Class491(){
+ new Class492();
+ }
+}
+class Class492 {
+ public Class492(){
+ new Class493();
+ }
+}
+class Class493 {
+ public Class493(){
+ new Class494();
+ }
+}
+class Class494 {
+ public Class494(){
+ new Class495();
+ }
+}
+class Class495 {
+ public Class495(){
+ new Class496();
+ }
+}
+class Class496 {
+ public Class496(){
+ new Class497();
+ }
+}
+class Class497 {
+ public Class497(){
+ new Class498();
+ }
+}
+class Class498 {
+ public Class498(){
+ new Class499();
+ }
+}
+class Class499 {
+ public Class499(){
+ new Class500();
+ }
+}
+class Class500 {
+ public Class500(){
+ new Class501();
+ }
+}
+class Class501 {
+ public Class501(){
+ new Class502();
+ }
+}
+class Class502 {
+ public Class502(){
+ new Class503();
+ }
+}
+class Class503 {
+ public Class503(){
+ new Class504();
+ }
+}
+class Class504 {
+ public Class504(){
+ new Class505();
+ }
+}
+class Class505 {
+ public Class505(){
+ new Class506();
+ }
+}
+class Class506 {
+ public Class506(){
+ new Class507();
+ }
+}
+class Class507 {
+ public Class507(){
+ new Class508();
+ }
+}
+class Class508 {
+ public Class508(){
+ new Class509();
+ }
+}
+class Class509 {
+ public Class509(){
+ new Class510();
+ }
+}
+class Class510 {
+ public Class510(){
+ new Class511();
+ }
+}
+class Class511 {
+ public Class511(){
+ new Class512();
+ }
+}
+class Class512 {
+ public Class512(){
+ new Class513();
+ }
+}
+class Class513 {
+ public Class513(){
+ new Class514();
+ }
+}
+class Class514 {
+ public Class514(){
+ new Class515();
+ }
+}
+class Class515 {
+ public Class515(){
+ new Class516();
+ }
+}
+class Class516 {
+ public Class516(){
+ new Class517();
+ }
+}
+class Class517 {
+ public Class517(){
+ new Class518();
+ }
+}
+class Class518 {
+ public Class518(){
+ new Class519();
+ }
+}
+class Class519 {
+ public Class519(){
+ new Class520();
+ }
+}
+class Class520 {
+ public Class520(){
+ new Class521();
+ }
+}
+class Class521 {
+ public Class521(){
+ new Class522();
+ }
+}
+class Class522 {
+ public Class522(){
+ new Class523();
+ }
+}
+class Class523 {
+ public Class523(){
+ new Class524();
+ }
+}
+class Class524 {
+ public Class524(){
+ new Class525();
+ }
+}
+class Class525 {
+ public Class525(){
+ new Class526();
+ }
+}
+class Class526 {
+ public Class526(){
+ new Class527();
+ }
+}
+class Class527 {
+ public Class527(){
+ new Class528();
+ }
+}
+class Class528 {
+ public Class528(){
+ new Class529();
+ }
+}
+class Class529 {
+ public Class529(){
+ new Class530();
+ }
+}
+class Class530 {
+ public Class530(){
+ new Class531();
+ }
+}
+class Class531 {
+ public Class531(){
+ new Class532();
+ }
+}
+class Class532 {
+ public Class532(){
+ new Class533();
+ }
+}
+class Class533 {
+ public Class533(){
+ new Class534();
+ }
+}
+class Class534 {
+ public Class534(){
+ new Class535();
+ }
+}
+class Class535 {
+ public Class535(){
+ new Class536();
+ }
+}
+class Class536 {
+ public Class536(){
+ new Class537();
+ }
+}
+class Class537 {
+ public Class537(){
+ new Class538();
+ }
+}
+class Class538 {
+ public Class538(){
+ new Class539();
+ }
+}
+class Class539 {
+ public Class539(){
+ new Class540();
+ }
+}
+class Class540 {
+ public Class540(){
+ new Class541();
+ }
+}
+class Class541 {
+ public Class541(){
+ new Class542();
+ }
+}
+class Class542 {
+ public Class542(){
+ new Class543();
+ }
+}
+class Class543 {
+ public Class543(){
+ new Class544();
+ }
+}
+class Class544 {
+ public Class544(){
+ new Class545();
+ }
+}
+class Class545 {
+ public Class545(){
+ new Class546();
+ }
+}
+class Class546 {
+ public Class546(){
+ new Class547();
+ }
+}
+class Class547 {
+ public Class547(){
+ new Class548();
+ }
+}
+class Class548 {
+ public Class548(){
+ new Class549();
+ }
+}
+class Class549 {
+ public Class549(){
+ new Class550();
+ }
+}
+class Class550 {
+ public Class550(){
+ new Class551();
+ }
+}
+class Class551 {
+ public Class551(){
+ new Class552();
+ }
+}
+class Class552 {
+ public Class552(){
+ new Class553();
+ }
+}
+class Class553 {
+ public Class553(){
+ new Class554();
+ }
+}
+class Class554 {
+ public Class554(){
+ new Class555();
+ }
+}
+class Class555 {
+ public Class555(){
+ new Class556();
+ }
+}
+class Class556 {
+ public Class556(){
+ new Class557();
+ }
+}
+class Class557 {
+ public Class557(){
+ new Class558();
+ }
+}
+class Class558 {
+ public Class558(){
+ new Class559();
+ }
+}
+class Class559 {
+ public Class559(){
+ new Class560();
+ }
+}
+class Class560 {
+ public Class560(){
+ new Class561();
+ }
+}
+class Class561 {
+ public Class561(){
+ new Class562();
+ }
+}
+class Class562 {
+ public Class562(){
+ new Class563();
+ }
+}
+class Class563 {
+ public Class563(){
+ new Class564();
+ }
+}
+class Class564 {
+ public Class564(){
+ new Class565();
+ }
+}
+class Class565 {
+ public Class565(){
+ new Class566();
+ }
+}
+class Class566 {
+ public Class566(){
+ new Class567();
+ }
+}
+class Class567 {
+ public Class567(){
+ new Class568();
+ }
+}
+class Class568 {
+ public Class568(){
+ new Class569();
+ }
+}
+class Class569 {
+ public Class569(){
+ new Class570();
+ }
+}
+class Class570 {
+ public Class570(){
+ new Class571();
+ }
+}
+class Class571 {
+ public Class571(){
+ new Class572();
+ }
+}
+class Class572 {
+ public Class572(){
+ new Class573();
+ }
+}
+class Class573 {
+ public Class573(){
+ new Class574();
+ }
+}
+class Class574 {
+ public Class574(){
+ new Class575();
+ }
+}
+class Class575 {
+ public Class575(){
+ new Class576();
+ }
+}
+class Class576 {
+ public Class576(){
+ new Class577();
+ }
+}
+class Class577 {
+ public Class577(){
+ new Class578();
+ }
+}
+class Class578 {
+ public Class578(){
+ new Class579();
+ }
+}
+class Class579 {
+ public Class579(){
+ new Class580();
+ }
+}
+class Class580 {
+ public Class580(){
+ new Class581();
+ }
+}
+class Class581 {
+ public Class581(){
+ new Class582();
+ }
+}
+class Class582 {
+ public Class582(){
+ new Class583();
+ }
+}
+class Class583 {
+ public Class583(){
+ new Class584();
+ }
+}
+class Class584 {
+ public Class584(){
+ new Class585();
+ }
+}
+class Class585 {
+ public Class585(){
+ new Class586();
+ }
+}
+class Class586 {
+ public Class586(){
+ new Class587();
+ }
+}
+class Class587 {
+ public Class587(){
+ new Class588();
+ }
+}
+class Class588 {
+ public Class588(){
+ new Class589();
+ }
+}
+class Class589 {
+ public Class589(){
+ new Class590();
+ }
+}
+class Class590 {
+ public Class590(){
+ new Class591();
+ }
+}
+class Class591 {
+ public Class591(){
+ new Class592();
+ }
+}
+class Class592 {
+ public Class592(){
+ new Class593();
+ }
+}
+class Class593 {
+ public Class593(){
+ new Class594();
+ }
+}
+class Class594 {
+ public Class594(){
+ new Class595();
+ }
+}
+class Class595 {
+ public Class595(){
+ new Class596();
+ }
+}
+class Class596 {
+ public Class596(){
+ new Class597();
+ }
+}
+class Class597 {
+ public Class597(){
+ new Class598();
+ }
+}
+class Class598 {
+ public Class598(){
+ new Class599();
+ }
+}
+class Class599 {
+ public Class599(){
+ new Class600();
+ }
+}
+class Class600 {
+ public Class600(){
+ new Class601();
+ }
+}
+class Class601 {
+ public Class601(){
+ new Class602();
+ }
+}
+class Class602 {
+ public Class602(){
+ new Class603();
+ }
+}
+class Class603 {
+ public Class603(){
+ new Class604();
+ }
+}
+class Class604 {
+ public Class604(){
+ new Class605();
+ }
+}
+class Class605 {
+ public Class605(){
+ new Class606();
+ }
+}
+class Class606 {
+ public Class606(){
+ new Class607();
+ }
+}
+class Class607 {
+ public Class607(){
+ new Class608();
+ }
+}
+class Class608 {
+ public Class608(){
+ new Class609();
+ }
+}
+class Class609 {
+ public Class609(){
+ new Class610();
+ }
+}
+class Class610 {
+ public Class610(){
+ new Class611();
+ }
+}
+class Class611 {
+ public Class611(){
+ new Class612();
+ }
+}
+class Class612 {
+ public Class612(){
+ new Class613();
+ }
+}
+class Class613 {
+ public Class613(){
+ new Class614();
+ }
+}
+class Class614 {
+ public Class614(){
+ new Class615();
+ }
+}
+class Class615 {
+ public Class615(){
+ new Class616();
+ }
+}
+class Class616 {
+ public Class616(){
+ new Class617();
+ }
+}
+class Class617 {
+ public Class617(){
+ new Class618();
+ }
+}
+class Class618 {
+ public Class618(){
+ new Class619();
+ }
+}
+class Class619 {
+ public Class619(){
+ new Class620();
+ }
+}
+class Class620 {
+ public Class620(){
+ new Class621();
+ }
+}
+class Class621 {
+ public Class621(){
+ new Class622();
+ }
+}
+class Class622 {
+ public Class622(){
+ new Class623();
+ }
+}
+class Class623 {
+ public Class623(){
+ new Class624();
+ }
+}
+class Class624 {
+ public Class624(){
+ new Class625();
+ }
+}
+class Class625 {
+ public Class625(){
+ new Class626();
+ }
+}
+class Class626 {
+ public Class626(){
+ new Class627();
+ }
+}
+class Class627 {
+ public Class627(){
+ new Class628();
+ }
+}
+class Class628 {
+ public Class628(){
+ new Class629();
+ }
+}
+class Class629 {
+ public Class629(){
+ new Class630();
+ }
+}
+class Class630 {
+ public Class630(){
+ new Class631();
+ }
+}
+class Class631 {
+ public Class631(){
+ new Class632();
+ }
+}
+class Class632 {
+ public Class632(){
+ new Class633();
+ }
+}
+class Class633 {
+ public Class633(){
+ new Class634();
+ }
+}
+class Class634 {
+ public Class634(){
+ new Class635();
+ }
+}
+class Class635 {
+ public Class635(){
+ new Class636();
+ }
+}
+class Class636 {
+ public Class636(){
+ new Class637();
+ }
+}
+class Class637 {
+ public Class637(){
+ new Class638();
+ }
+}
+class Class638 {
+ public Class638(){
+ new Class639();
+ }
+}
+class Class639 {
+ public Class639(){
+ new Class640();
+ }
+}
+class Class640 {
+ public Class640(){
+ new Class641();
+ }
+}
+class Class641 {
+ public Class641(){
+ new Class642();
+ }
+}
+class Class642 {
+ public Class642(){
+ new Class643();
+ }
+}
+class Class643 {
+ public Class643(){
+ new Class644();
+ }
+}
+class Class644 {
+ public Class644(){
+ new Class645();
+ }
+}
+class Class645 {
+ public Class645(){
+ new Class646();
+ }
+}
+class Class646 {
+ public Class646(){
+ new Class647();
+ }
+}
+class Class647 {
+ public Class647(){
+ new Class648();
+ }
+}
+class Class648 {
+ public Class648(){
+ new Class649();
+ }
+}
+class Class649 {
+ public Class649(){
+ new Class650();
+ }
+}
+class Class650 {
+ public Class650(){
+ new Class651();
+ }
+}
+class Class651 {
+ public Class651(){
+ new Class652();
+ }
+}
+class Class652 {
+ public Class652(){
+ new Class653();
+ }
+}
+class Class653 {
+ public Class653(){
+ new Class654();
+ }
+}
+class Class654 {
+ public Class654(){
+ new Class655();
+ }
+}
+class Class655 {
+ public Class655(){
+ new Class656();
+ }
+}
+class Class656 {
+ public Class656(){
+ new Class657();
+ }
+}
+class Class657 {
+ public Class657(){
+ new Class658();
+ }
+}
+class Class658 {
+ public Class658(){
+ new Class659();
+ }
+}
+class Class659 {
+ public Class659(){
+ new Class660();
+ }
+}
+class Class660 {
+ public Class660(){
+ new Class661();
+ }
+}
+class Class661 {
+ public Class661(){
+ new Class662();
+ }
+}
+class Class662 {
+ public Class662(){
+ new Class663();
+ }
+}
+class Class663 {
+ public Class663(){
+ new Class664();
+ }
+}
+class Class664 {
+ public Class664(){
+ new Class665();
+ }
+}
+class Class665 {
+ public Class665(){
+ new Class666();
+ }
+}
+class Class666 {
+ public Class666(){
+ new Class667();
+ }
+}
+class Class667 {
+ public Class667(){
+ new Class668();
+ }
+}
+class Class668 {
+ public Class668(){
+ new Class669();
+ }
+}
+class Class669 {
+ public Class669(){
+ new Class670();
+ }
+}
+class Class670 {
+ public Class670(){
+ new Class671();
+ }
+}
+class Class671 {
+ public Class671(){
+ new Class672();
+ }
+}
+class Class672 {
+ public Class672(){
+ new Class673();
+ }
+}
+class Class673 {
+ public Class673(){
+ new Class674();
+ }
+}
+class Class674 {
+ public Class674(){
+ new Class675();
+ }
+}
+class Class675 {
+ public Class675(){
+ new Class676();
+ }
+}
+class Class676 {
+ public Class676(){
+ new Class677();
+ }
+}
+class Class677 {
+ public Class677(){
+ new Class678();
+ }
+}
+class Class678 {
+ public Class678(){
+ new Class679();
+ }
+}
+class Class679 {
+ public Class679(){
+ new Class680();
+ }
+}
+class Class680 {
+ public Class680(){
+ new Class681();
+ }
+}
+class Class681 {
+ public Class681(){
+ new Class682();
+ }
+}
+class Class682 {
+ public Class682(){
+ new Class683();
+ }
+}
+class Class683 {
+ public Class683(){
+ new Class684();
+ }
+}
+class Class684 {
+ public Class684(){
+ new Class685();
+ }
+}
+class Class685 {
+ public Class685(){
+ new Class686();
+ }
+}
+class Class686 {
+ public Class686(){
+ new Class687();
+ }
+}
+class Class687 {
+ public Class687(){
+ new Class688();
+ }
+}
+class Class688 {
+ public Class688(){
+ new Class689();
+ }
+}
+class Class689 {
+ public Class689(){
+ new Class690();
+ }
+}
+class Class690 {
+ public Class690(){
+ new Class691();
+ }
+}
+class Class691 {
+ public Class691(){
+ new Class692();
+ }
+}
+class Class692 {
+ public Class692(){
+ new Class693();
+ }
+}
+class Class693 {
+ public Class693(){
+ new Class694();
+ }
+}
+class Class694 {
+ public Class694(){
+ new Class695();
+ }
+}
+class Class695 {
+ public Class695(){
+ new Class696();
+ }
+}
+class Class696 {
+ public Class696(){
+ new Class697();
+ }
+}
+class Class697 {
+ public Class697(){
+ new Class698();
+ }
+}
+class Class698 {
+ public Class698(){
+ new Class699();
+ }
+}
+class Class699 {
+ public Class699(){
+ new Class700();
+ }
+}
+class Class700 {
+ public Class700(){
+ new Class701();
+ }
+}
+class Class701 {
+ public Class701(){
+ new Class702();
+ }
+}
+class Class702 {
+ public Class702(){
+ new Class703();
+ }
+}
+class Class703 {
+ public Class703(){
+ new Class704();
+ }
+}
+class Class704 {
+ public Class704(){
+ new Class705();
+ }
+}
+class Class705 {
+ public Class705(){
+ new Class706();
+ }
+}
+class Class706 {
+ public Class706(){
+ new Class707();
+ }
+}
+class Class707 {
+ public Class707(){
+ new Class708();
+ }
+}
+class Class708 {
+ public Class708(){
+ new Class709();
+ }
+}
+class Class709 {
+ public Class709(){
+ new Class710();
+ }
+}
+class Class710 {
+ public Class710(){
+ new Class711();
+ }
+}
+class Class711 {
+ public Class711(){
+ new Class712();
+ }
+}
+class Class712 {
+ public Class712(){
+ new Class713();
+ }
+}
+class Class713 {
+ public Class713(){
+ new Class714();
+ }
+}
+class Class714 {
+ public Class714(){
+ new Class715();
+ }
+}
+class Class715 {
+ public Class715(){
+ new Class716();
+ }
+}
+class Class716 {
+ public Class716(){
+ new Class717();
+ }
+}
+class Class717 {
+ public Class717(){
+ new Class718();
+ }
+}
+class Class718 {
+ public Class718(){
+ new Class719();
+ }
+}
+class Class719 {
+ public Class719(){
+ new Class720();
+ }
+}
+class Class720 {
+ public Class720(){
+ new Class721();
+ }
+}
+class Class721 {
+ public Class721(){
+ new Class722();
+ }
+}
+class Class722 {
+ public Class722(){
+ new Class723();
+ }
+}
+class Class723 {
+ public Class723(){
+ new Class724();
+ }
+}
+class Class724 {
+ public Class724(){
+ new Class725();
+ }
+}
+class Class725 {
+ public Class725(){
+ new Class726();
+ }
+}
+class Class726 {
+ public Class726(){
+ new Class727();
+ }
+}
+class Class727 {
+ public Class727(){
+ new Class728();
+ }
+}
+class Class728 {
+ public Class728(){
+ new Class729();
+ }
+}
+class Class729 {
+ public Class729(){
+ new Class730();
+ }
+}
+class Class730 {
+ public Class730(){
+ new Class731();
+ }
+}
+class Class731 {
+ public Class731(){
+ new Class732();
+ }
+}
+class Class732 {
+ public Class732(){
+ new Class733();
+ }
+}
+class Class733 {
+ public Class733(){
+ new Class734();
+ }
+}
+class Class734 {
+ public Class734(){
+ new Class735();
+ }
+}
+class Class735 {
+ public Class735(){
+ new Class736();
+ }
+}
+class Class736 {
+ public Class736(){
+ new Class737();
+ }
+}
+class Class737 {
+ public Class737(){
+ new Class738();
+ }
+}
+class Class738 {
+ public Class738(){
+ new Class739();
+ }
+}
+class Class739 {
+ public Class739(){
+ new Class740();
+ }
+}
+class Class740 {
+ public Class740(){
+ new Class741();
+ }
+}
+class Class741 {
+ public Class741(){
+ new Class742();
+ }
+}
+class Class742 {
+ public Class742(){
+ new Class743();
+ }
+}
+class Class743 {
+ public Class743(){
+ new Class744();
+ }
+}
+class Class744 {
+ public Class744(){
+ new Class745();
+ }
+}
+class Class745 {
+ public Class745(){
+ new Class746();
+ }
+}
+class Class746 {
+ public Class746(){
+ new Class747();
+ }
+}
+class Class747 {
+ public Class747(){
+ new Class748();
+ }
+}
+class Class748 {
+ public Class748(){
+ new Class749();
+ }
+}
+class Class749 {
+ public Class749(){
+ new Class750();
+ }
+}
+class Class750 {
+ public Class750(){
+ new Class751();
+ }
+}
+class Class751 {
+ public Class751(){
+ new Class752();
+ }
+}
+class Class752 {
+ public Class752(){
+ new Class753();
+ }
+}
+class Class753 {
+ public Class753(){
+ new Class754();
+ }
+}
+class Class754 {
+ public Class754(){
+ new Class755();
+ }
+}
+class Class755 {
+ public Class755(){
+ new Class756();
+ }
+}
+class Class756 {
+ public Class756(){
+ new Class757();
+ }
+}
+class Class757 {
+ public Class757(){
+ new Class758();
+ }
+}
+class Class758 {
+ public Class758(){
+ new Class759();
+ }
+}
+class Class759 {
+ public Class759(){
+ new Class760();
+ }
+}
+class Class760 {
+ public Class760(){
+ new Class761();
+ }
+}
+class Class761 {
+ public Class761(){
+ new Class762();
+ }
+}
+class Class762 {
+ public Class762(){
+ new Class763();
+ }
+}
+class Class763 {
+ public Class763(){
+ new Class764();
+ }
+}
+class Class764 {
+ public Class764(){
+ new Class765();
+ }
+}
+class Class765 {
+ public Class765(){
+ new Class766();
+ }
+}
+class Class766 {
+ public Class766(){
+ new Class767();
+ }
+}
+class Class767 {
+ public Class767(){
+ new Class768();
+ }
+}
+class Class768 {
+ public Class768(){
+ new Class769();
+ }
+}
+class Class769 {
+ public Class769(){
+ new Class770();
+ }
+}
+class Class770 {
+ public Class770(){
+ new Class771();
+ }
+}
+class Class771 {
+ public Class771(){
+ new Class772();
+ }
+}
+class Class772 {
+ public Class772(){
+ new Class773();
+ }
+}
+class Class773 {
+ public Class773(){
+ new Class774();
+ }
+}
+class Class774 {
+ public Class774(){
+ new Class775();
+ }
+}
+class Class775 {
+ public Class775(){
+ new Class776();
+ }
+}
+class Class776 {
+ public Class776(){
+ new Class777();
+ }
+}
+class Class777 {
+ public Class777(){
+ new Class778();
+ }
+}
+class Class778 {
+ public Class778(){
+ new Class779();
+ }
+}
+class Class779 {
+ public Class779(){
+ new Class780();
+ }
+}
+class Class780 {
+ public Class780(){
+ new Class781();
+ }
+}
+class Class781 {
+ public Class781(){
+ new Class782();
+ }
+}
+class Class782 {
+ public Class782(){
+ new Class783();
+ }
+}
+class Class783 {
+ public Class783(){
+ new Class784();
+ }
+}
+class Class784 {
+ public Class784(){
+ new Class785();
+ }
+}
+class Class785 {
+ public Class785(){
+ new Class786();
+ }
+}
+class Class786 {
+ public Class786(){
+ new Class787();
+ }
+}
+class Class787 {
+ public Class787(){
+ new Class788();
+ }
+}
+class Class788 {
+ public Class788(){
+ new Class789();
+ }
+}
+class Class789 {
+ public Class789(){
+ new Class790();
+ }
+}
+class Class790 {
+ public Class790(){
+ new Class791();
+ }
+}
+class Class791 {
+ public Class791(){
+ new Class792();
+ }
+}
+class Class792 {
+ public Class792(){
+ new Class793();
+ }
+}
+class Class793 {
+ public Class793(){
+ new Class794();
+ }
+}
+class Class794 {
+ public Class794(){
+ new Class795();
+ }
+}
+class Class795 {
+ public Class795(){
+ new Class796();
+ }
+}
+class Class796 {
+ public Class796(){
+ new Class797();
+ }
+}
+class Class797 {
+ public Class797(){
+ new Class798();
+ }
+}
+class Class798 {
+ public Class798(){
+ new Class799();
+ }
+}
+class Class799 {
+ public Class799(){
+ new Class800();
+ }
+}
+class Class800 {
+ public Class800(){
+ new Class801();
+ }
+}
+class Class801 {
+ public Class801(){
+ new Class802();
+ }
+}
+class Class802 {
+ public Class802(){
+ new Class803();
+ }
+}
+class Class803 {
+ public Class803(){
+ new Class804();
+ }
+}
+class Class804 {
+ public Class804(){
+ new Class805();
+ }
+}
+class Class805 {
+ public Class805(){
+ new Class806();
+ }
+}
+class Class806 {
+ public Class806(){
+ new Class807();
+ }
+}
+class Class807 {
+ public Class807(){
+ new Class808();
+ }
+}
+class Class808 {
+ public Class808(){
+ new Class809();
+ }
+}
+class Class809 {
+ public Class809(){
+ new Class810();
+ }
+}
+class Class810 {
+ public Class810(){
+ new Class811();
+ }
+}
+class Class811 {
+ public Class811(){
+ new Class812();
+ }
+}
+class Class812 {
+ public Class812(){
+ new Class813();
+ }
+}
+class Class813 {
+ public Class813(){
+ new Class814();
+ }
+}
+class Class814 {
+ public Class814(){
+ new Class815();
+ }
+}
+class Class815 {
+ public Class815(){
+ new Class816();
+ }
+}
+class Class816 {
+ public Class816(){
+ new Class817();
+ }
+}
+class Class817 {
+ public Class817(){
+ new Class818();
+ }
+}
+class Class818 {
+ public Class818(){
+ new Class819();
+ }
+}
+class Class819 {
+ public Class819(){
+ new Class820();
+ }
+}
+class Class820 {
+ public Class820(){
+ new Class821();
+ }
+}
+class Class821 {
+ public Class821(){
+ new Class822();
+ }
+}
+class Class822 {
+ public Class822(){
+ new Class823();
+ }
+}
+class Class823 {
+ public Class823(){
+ new Class824();
+ }
+}
+class Class824 {
+ public Class824(){
+ new Class825();
+ }
+}
+class Class825 {
+ public Class825(){
+ new Class826();
+ }
+}
+class Class826 {
+ public Class826(){
+ new Class827();
+ }
+}
+class Class827 {
+ public Class827(){
+ new Class828();
+ }
+}
+class Class828 {
+ public Class828(){
+ new Class829();
+ }
+}
+class Class829 {
+ public Class829(){
+ new Class830();
+ }
+}
+class Class830 {
+ public Class830(){
+ new Class831();
+ }
+}
+class Class831 {
+ public Class831(){
+ new Class832();
+ }
+}
+class Class832 {
+ public Class832(){
+ new Class833();
+ }
+}
+class Class833 {
+ public Class833(){
+ new Class834();
+ }
+}
+class Class834 {
+ public Class834(){
+ new Class835();
+ }
+}
+class Class835 {
+ public Class835(){
+ new Class836();
+ }
+}
+class Class836 {
+ public Class836(){
+ new Class837();
+ }
+}
+class Class837 {
+ public Class837(){
+ new Class838();
+ }
+}
+class Class838 {
+ public Class838(){
+ new Class839();
+ }
+}
+class Class839 {
+ public Class839(){
+ new Class840();
+ }
+}
+class Class840 {
+ public Class840(){
+ new Class841();
+ }
+}
+class Class841 {
+ public Class841(){
+ new Class842();
+ }
+}
+class Class842 {
+ public Class842(){
+ new Class843();
+ }
+}
+class Class843 {
+ public Class843(){
+ new Class844();
+ }
+}
+class Class844 {
+ public Class844(){
+ new Class845();
+ }
+}
+class Class845 {
+ public Class845(){
+ new Class846();
+ }
+}
+class Class846 {
+ public Class846(){
+ new Class847();
+ }
+}
+class Class847 {
+ public Class847(){
+ new Class848();
+ }
+}
+class Class848 {
+ public Class848(){
+ new Class849();
+ }
+}
+class Class849 {
+ public Class849(){
+ new Class850();
+ }
+}
+class Class850 {
+ public Class850(){
+ new Class851();
+ }
+}
+class Class851 {
+ public Class851(){
+ new Class852();
+ }
+}
+class Class852 {
+ public Class852(){
+ new Class853();
+ }
+}
+class Class853 {
+ public Class853(){
+ new Class854();
+ }
+}
+class Class854 {
+ public Class854(){
+ new Class855();
+ }
+}
+class Class855 {
+ public Class855(){
+ new Class856();
+ }
+}
+class Class856 {
+ public Class856(){
+ new Class857();
+ }
+}
+class Class857 {
+ public Class857(){
+ new Class858();
+ }
+}
+class Class858 {
+ public Class858(){
+ new Class859();
+ }
+}
+class Class859 {
+ public Class859(){
+ new Class860();
+ }
+}
+class Class860 {
+ public Class860(){
+ new Class861();
+ }
+}
+class Class861 {
+ public Class861(){
+ new Class862();
+ }
+}
+class Class862 {
+ public Class862(){
+ new Class863();
+ }
+}
+class Class863 {
+ public Class863(){
+ new Class864();
+ }
+}
+class Class864 {
+ public Class864(){
+ new Class865();
+ }
+}
+class Class865 {
+ public Class865(){
+ new Class866();
+ }
+}
+class Class866 {
+ public Class866(){
+ new Class867();
+ }
+}
+class Class867 {
+ public Class867(){
+ new Class868();
+ }
+}
+class Class868 {
+ public Class868(){
+ new Class869();
+ }
+}
+class Class869 {
+ public Class869(){
+ new Class870();
+ }
+}
+class Class870 {
+ public Class870(){
+ new Class871();
+ }
+}
+class Class871 {
+ public Class871(){
+ new Class872();
+ }
+}
+class Class872 {
+ public Class872(){
+ new Class873();
+ }
+}
+class Class873 {
+ public Class873(){
+ new Class874();
+ }
+}
+class Class874 {
+ public Class874(){
+ new Class875();
+ }
+}
+class Class875 {
+ public Class875(){
+ new Class876();
+ }
+}
+class Class876 {
+ public Class876(){
+ new Class877();
+ }
+}
+class Class877 {
+ public Class877(){
+ new Class878();
+ }
+}
+class Class878 {
+ public Class878(){
+ new Class879();
+ }
+}
+class Class879 {
+ public Class879(){
+ new Class880();
+ }
+}
+class Class880 {
+ public Class880(){
+ new Class881();
+ }
+}
+class Class881 {
+ public Class881(){
+ new Class882();
+ }
+}
+class Class882 {
+ public Class882(){
+ new Class883();
+ }
+}
+class Class883 {
+ public Class883(){
+ new Class884();
+ }
+}
+class Class884 {
+ public Class884(){
+ new Class885();
+ }
+}
+class Class885 {
+ public Class885(){
+ new Class886();
+ }
+}
+class Class886 {
+ public Class886(){
+ new Class887();
+ }
+}
+class Class887 {
+ public Class887(){
+ new Class888();
+ }
+}
+class Class888 {
+ public Class888(){
+ new Class889();
+ }
+}
+class Class889 {
+ public Class889(){
+ new Class890();
+ }
+}
+class Class890 {
+ public Class890(){
+ new Class891();
+ }
+}
+class Class891 {
+ public Class891(){
+ new Class892();
+ }
+}
+class Class892 {
+ public Class892(){
+ new Class893();
+ }
+}
+class Class893 {
+ public Class893(){
+ new Class894();
+ }
+}
+class Class894 {
+ public Class894(){
+ new Class895();
+ }
+}
+class Class895 {
+ public Class895(){
+ new Class896();
+ }
+}
+class Class896 {
+ public Class896(){
+ new Class897();
+ }
+}
+class Class897 {
+ public Class897(){
+ new Class898();
+ }
+}
+class Class898 {
+ public Class898(){
+ new Class899();
+ }
+}
+class Class899 {
+ public Class899(){
+ new Class900();
+ }
+}
+class Class900 {
+ public Class900(){
+ new Class901();
+ }
+}
+class Class901 {
+ public Class901(){
+ new Class902();
+ }
+}
+class Class902 {
+ public Class902(){
+ new Class903();
+ }
+}
+class Class903 {
+ public Class903(){
+ new Class904();
+ }
+}
+class Class904 {
+ public Class904(){
+ new Class905();
+ }
+}
+class Class905 {
+ public Class905(){
+ new Class906();
+ }
+}
+class Class906 {
+ public Class906(){
+ new Class907();
+ }
+}
+class Class907 {
+ public Class907(){
+ new Class908();
+ }
+}
+class Class908 {
+ public Class908(){
+ new Class909();
+ }
+}
+class Class909 {
+ public Class909(){
+ new Class910();
+ }
+}
+class Class910 {
+ public Class910(){
+ new Class911();
+ }
+}
+class Class911 {
+ public Class911(){
+ new Class912();
+ }
+}
+class Class912 {
+ public Class912(){
+ new Class913();
+ }
+}
+class Class913 {
+ public Class913(){
+ new Class914();
+ }
+}
+class Class914 {
+ public Class914(){
+ new Class915();
+ }
+}
+class Class915 {
+ public Class915(){
+ new Class916();
+ }
+}
+class Class916 {
+ public Class916(){
+ new Class917();
+ }
+}
+class Class917 {
+ public Class917(){
+ new Class918();
+ }
+}
+class Class918 {
+ public Class918(){
+ new Class919();
+ }
+}
+class Class919 {
+ public Class919(){
+ new Class920();
+ }
+}
+class Class920 {
+ public Class920(){
+ new Class921();
+ }
+}
+class Class921 {
+ public Class921(){
+ new Class922();
+ }
+}
+class Class922 {
+ public Class922(){
+ new Class923();
+ }
+}
+class Class923 {
+ public Class923(){
+ new Class924();
+ }
+}
+class Class924 {
+ public Class924(){
+ new Class925();
+ }
+}
+class Class925 {
+ public Class925(){
+ new Class926();
+ }
+}
+class Class926 {
+ public Class926(){
+ new Class927();
+ }
+}
+class Class927 {
+ public Class927(){
+ new Class928();
+ }
+}
+class Class928 {
+ public Class928(){
+ new Class929();
+ }
+}
+class Class929 {
+ public Class929(){
+ new Class930();
+ }
+}
+class Class930 {
+ public Class930(){
+ new Class931();
+ }
+}
+class Class931 {
+ public Class931(){
+ new Class932();
+ }
+}
+class Class932 {
+ public Class932(){
+ new Class933();
+ }
+}
+class Class933 {
+ public Class933(){
+ new Class934();
+ }
+}
+class Class934 {
+ public Class934(){
+ new Class935();
+ }
+}
+class Class935 {
+ public Class935(){
+ new Class936();
+ }
+}
+class Class936 {
+ public Class936(){
+ new Class937();
+ }
+}
+class Class937 {
+ public Class937(){
+ new Class938();
+ }
+}
+class Class938 {
+ public Class938(){
+ new Class939();
+ }
+}
+class Class939 {
+ public Class939(){
+ new Class940();
+ }
+}
+class Class940 {
+ public Class940(){
+ new Class941();
+ }
+}
+class Class941 {
+ public Class941(){
+ new Class942();
+ }
+}
+class Class942 {
+ public Class942(){
+ new Class943();
+ }
+}
+class Class943 {
+ public Class943(){
+ new Class944();
+ }
+}
+class Class944 {
+ public Class944(){
+ new Class945();
+ }
+}
+class Class945 {
+ public Class945(){
+ new Class946();
+ }
+}
+class Class946 {
+ public Class946(){
+ new Class947();
+ }
+}
+class Class947 {
+ public Class947(){
+ new Class948();
+ }
+}
+class Class948 {
+ public Class948(){
+ new Class949();
+ }
+}
+class Class949 {
+ public Class949(){
+ new Class950();
+ }
+}
+class Class950 {
+ public Class950(){
+ new Class951();
+ }
+}
+class Class951 {
+ public Class951(){
+ new Class952();
+ }
+}
+class Class952 {
+ public Class952(){
+ new Class953();
+ }
+}
+class Class953 {
+ public Class953(){
+ new Class954();
+ }
+}
+class Class954 {
+ public Class954(){
+ new Class955();
+ }
+}
+class Class955 {
+ public Class955(){
+ new Class956();
+ }
+}
+class Class956 {
+ public Class956(){
+ new Class957();
+ }
+}
+class Class957 {
+ public Class957(){
+ new Class958();
+ }
+}
+class Class958 {
+ public Class958(){
+ new Class959();
+ }
+}
+class Class959 {
+ public Class959(){
+ new Class960();
+ }
+}
+class Class960 {
+ public Class960(){
+ new Class961();
+ }
+}
+class Class961 {
+ public Class961(){
+ new Class962();
+ }
+}
+class Class962 {
+ public Class962(){
+ new Class963();
+ }
+}
+class Class963 {
+ public Class963(){
+ new Class964();
+ }
+}
+class Class964 {
+ public Class964(){
+ new Class965();
+ }
+}
+class Class965 {
+ public Class965(){
+ new Class966();
+ }
+}
+class Class966 {
+ public Class966(){
+ new Class967();
+ }
+}
+class Class967 {
+ public Class967(){
+ new Class968();
+ }
+}
+class Class968 {
+ public Class968(){
+ new Class969();
+ }
+}
+class Class969 {
+ public Class969(){
+ new Class970();
+ }
+}
+class Class970 {
+ public Class970(){
+ new Class971();
+ }
+}
+class Class971 {
+ public Class971(){
+ new Class972();
+ }
+}
+class Class972 {
+ public Class972(){
+ new Class973();
+ }
+}
+class Class973 {
+ public Class973(){
+ new Class974();
+ }
+}
+class Class974 {
+ public Class974(){
+ new Class975();
+ }
+}
+class Class975 {
+ public Class975(){
+ new Class976();
+ }
+}
+class Class976 {
+ public Class976(){
+ new Class977();
+ }
+}
+class Class977 {
+ public Class977(){
+ new Class978();
+ }
+}
+class Class978 {
+ public Class978(){
+ new Class979();
+ }
+}
+class Class979 {
+ public Class979(){
+ new Class980();
+ }
+}
+class Class980 {
+ public Class980(){
+ new Class981();
+ }
+}
+class Class981 {
+ public Class981(){
+ new Class982();
+ }
+}
+class Class982 {
+ public Class982(){
+ new Class983();
+ }
+}
+class Class983 {
+ public Class983(){
+ new Class984();
+ }
+}
+class Class984 {
+ public Class984(){
+ new Class985();
+ }
+}
+class Class985 {
+ public Class985(){
+ new Class986();
+ }
+}
+class Class986 {
+ public Class986(){
+ new Class987();
+ }
+}
+class Class987 {
+ public Class987(){
+ new Class988();
+ }
+}
+class Class988 {
+ public Class988(){
+ new Class989();
+ }
+}
+class Class989 {
+ public Class989(){
+ new Class990();
+ }
+}
+class Class990 {
+ public Class990(){
+ new Class991();
+ }
+}
+class Class991 {
+ public Class991(){
+ new Class992();
+ }
+}
+class Class992 {
+ public Class992(){
+ new Class993();
+ }
+}
+class Class993 {
+ public Class993(){
+ new Class994();
+ }
+}
+class Class994 {
+ public Class994(){
+ new Class995();
+ }
+}
+class Class995 {
+ public Class995(){
+ new Class996();
+ }
+}
+class Class996 {
+ public Class996(){
+ new Class997();
+ }
+}
+class Class997 {
+ public Class997(){
+ new Class998();
+ }
+}
+class Class998 {
+ public Class998(){
+ new Class999();
+ }
+}
+class Class999 {
+ public Class999(){
+ new Class1000();
+ }
+}
+class Class1000 {
+ public Class1000(){
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinDiag.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.runner.RunParams;
+
+/**
+ * Helper that prints information about FinMemoryObjects.
+ */
+public class FinDiag implements Runnable {
+ private long sleepTime;
+
+ public FinDiag() {
+ this(RunParams.getInstance().getSleepTime());
+ }
+
+ public FinDiag(long sleepTime) {
+ this.sleepTime = sleepTime;
+ }
+
+ public void run() {
+ FinMemoryObject.dumpStatistics();
+ // Ensure that interrupt status is not lost
+ if (Thread.currentThread().isInterrupted())
+ return;
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.PrintStream;
+
+/**
+ * An object that occupies approximately given number of bytes in memory
+ * and also records number of allocated and finalized instances.
+ */
+public class FinMemoryObject extends FinMemoryObject1 {
+ private static int finalizedCount;
+
+ public FinMemoryObject(int size) {
+ super(size);
+ }
+
+ protected void finalize() {
+ synchronized (FinMemoryObject.class) {
+ ++finalizedCount;
+ }
+ }
+
+ /**
+ * Returns the number of finalized FinMemoryObjects.
+ */
+ public static int getFinalizedCount() {
+ return finalizedCount;
+ }
+
+ /**
+ * Returns the number of live FinMemoryObjects (allocated but not finalized).
+ */
+ public static int getLiveCount() {
+ return allocatedCount - finalizedCount;
+ }
+
+ public static void dumpStatistics(PrintStream out) {
+ Algorithms.tryToPrintln(out, "Object count: " + getLiveCount());
+ }
+
+ public static void dumpStatistics() {
+ dumpStatistics(System.out);
+ }
+
+ public static boolean isAllFinalized() {
+ return getLiveCount() == 0;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/FinMemoryObject1.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.PrintStream;
+import nsk.share.gc.Algorithms;
+
+/**
+ * An object that occupies approximately given number of bytes in memory
+ * and also has finalizer that does nothing.
+ */
+public class FinMemoryObject1 extends MemoryObject {
+ protected static int allocatedCount;
+
+ public FinMemoryObject1(int size) {
+ super(size);
+ synchronized (FinMemoryObject.class) {
+ ++allocatedCount;
+ }
+ }
+
+ protected void finalize() {
+ }
+
+ /**
+ * Returns the number of allocated FinMemoryObjects.
+ */
+ public static int getAllocatedCount() {
+ return allocatedCount;
+ }
+
+ public static void dumpStatistics(PrintStream out) {
+ Algorithms.tryToPrintln(out, "Object count: " + getAllocatedCount());
+ }
+
+ public static void dumpStatistics() {
+ dumpStatistics(System.out);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GC.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.test.*;
+import nsk.share.runner.*;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.GarbageProducerAware;
+import nsk.share.gc.gp.GarbageProducer1Aware;
+import nsk.share.gc.gp.MemoryStrategy;
+import nsk.share.gc.gp.MemoryStrategyAware;
+import nsk.share.gc.gp.GarbageUtils;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.LockersAware;
+import nsk.share.gc.lock.LockerUtils;
+
+/**
+ * Utility methods for GC tests.
+ */
+public class GC extends nsk.share.test.Tests {
+ protected static class GCTestRunner extends TestRunner {
+ private GCParams gcParams;
+ private GarbageProducer garbageProducer;
+ private GarbageProducer garbageProducer1;
+ private MemoryStrategy memoryStrategy;
+ private Lockers lockers;
+
+ public GCTestRunner(Test test, String[] args) {
+ super(test, args);
+ }
+
+ private GCParams getGCParams(String[] args) {
+ if (gcParams == null) {
+ gcParams = GCParams.getInstance();
+ gcParams.parseCommandLine(args);
+ }
+ return gcParams;
+ }
+
+ private GarbageProducer getGarbageProducer(String[] args) {
+ if (garbageProducer == null) {
+ garbageProducer = GarbageUtils.getGarbageProducer(getGCParams(args).getGarbageProducerId());
+ configure(garbageProducer);
+ }
+ return garbageProducer;
+ }
+
+ private GarbageProducer getGarbageProducer1(String[] args) {
+ if (garbageProducer1 == null) {
+ garbageProducer1 = GarbageUtils.getGarbageProducer(getGCParams(args).getGarbageProducer1Id());
+ configure(garbageProducer1);
+ }
+ return garbageProducer1;
+ }
+
+ private MemoryStrategy getMemoryStrategy(String[] args) {
+ if (memoryStrategy == null) {
+ memoryStrategy = MemoryStrategy.fromString(getGCParams(args).getMemoryStrategyId());
+ configure(memoryStrategy);
+ }
+ return memoryStrategy;
+ }
+
+ private Lockers getLockers(String[] args) {
+ if (lockers == null) {
+ lockers = LockerUtils.getLockers(getGCParams(args).getLockersId());
+ configure(lockers);
+ }
+ return lockers;
+ }
+
+ public void configure(Object test) {
+ super.configure(test);
+ if (test instanceof GCParamsAware)
+ ((GCParamsAware) test).setGCParams(getGCParams(args));
+ if (test instanceof GarbageProducerAware)
+ ((GarbageProducerAware) test).setGarbageProducer(getGarbageProducer(args));
+ if (test instanceof GarbageProducer1Aware)
+ ((GarbageProducer1Aware) test).setGarbageProducer1(getGarbageProducer1(args));
+ if (test instanceof MemoryStrategyAware)
+ ((MemoryStrategyAware) test).setMemoryStrategy(getMemoryStrategy(args));
+ if (test instanceof LockersAware)
+ ((LockersAware) test).setLockers(getLockers(args));
+ }
+
+
+ }
+
+ private GC() {
+ }
+
+ public static void runTest(Test test, String[] args) {
+ new GCTestRunner(test, args).run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParams.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.PrintStream;
+
+public class GCParams {
+ private String garbageProducerId;
+ private String garbageProducer1Id;
+ private String memoryStrategyId;
+ private String lockersId;
+
+ public final String getGarbageProducerId() {
+ return garbageProducerId;
+ }
+
+ public final void setGarbageProducerId(String garbageProducerId) {
+ this.garbageProducerId = garbageProducerId;
+ }
+
+ public final String getGarbageProducer1Id() {
+ return garbageProducer1Id;
+ }
+
+ public final void setGarbageProducer1Id(String garbageProducer1Id) {
+ this.garbageProducer1Id = garbageProducer1Id;
+ }
+
+ public final String getMemoryStrategyId() {
+ return memoryStrategyId;
+ }
+
+ public final void setMemoryStrategyId(String memoryStrategyId) {
+ this.memoryStrategyId = memoryStrategyId;
+ }
+
+ public final String getLockersId() {
+ return lockersId;
+ }
+
+ public final void setLockersId(String lockersId) {
+ this.lockersId = lockersId;
+ }
+
+ public void parseCommandLine(String[] args) {
+ if (args == null)
+ return;
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].equals("-gp"))
+ garbageProducerId = args[++i];
+ else if (args[i].equals("-gp1"))
+ garbageProducer1Id = args[++i];
+ else if (args[i].equals("-ms"))
+ memoryStrategyId = args[++i];
+ else if (args[i].equals("-lockers"))
+ lockersId = args[++i];
+ }
+ printConfig(System.out);
+ }
+
+ public void prinUsage() {
+ }
+
+ public void printConfig(PrintStream out) {
+ }
+
+ private static GCParams instance;
+
+ public static GCParams getInstance() {
+ synchronized (GCParams.class) {
+ if (instance == null)
+ instance = new GCParams();
+ return instance;
+ }
+ }
+
+ public static void setInstance(GCParams gcParams) {
+ synchronized (GCParams.class) {
+ instance = gcParams;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCParamsAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+/**
+ * Marker interface to signify that run params are needed.
+ */
+public interface GCParamsAware {
+ public void setGCParams(GCParams gcParams);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/GCTestBase.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.test.TestBase;
+import nsk.share.runner.RunParams;
+import nsk.share.runner.RunParamsAware;
+
+public abstract class GCTestBase extends TestBase implements RunParamsAware, GCParamsAware {
+ protected RunParams runParams;
+ protected GCParams gcParams;
+
+ public final void setRunParams(RunParams runParams) {
+ this.runParams = runParams;
+ }
+
+ public final void setGCParams(GCParams gcParams) {
+ this.gcParams = gcParams;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/IndexPair.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+public final class IndexPair {
+ private int i, j;
+
+ public IndexPair(int i, int j) {
+ setI(i);
+ setJ(j);
+ }
+
+ public int getI() {
+ return i;
+ }
+
+ public void setI(int i) {
+ this.i = i;
+ }
+
+ public int getJ() {
+ return j;
+ }
+
+ public void setJ(int j) {
+ this.j = j;
+ }
+
+ public boolean equals(IndexPair pair) {
+ return (this.i == pair.i && this.j == pair.j);
+ }
+
+ public boolean equals(Object o) {
+ return o instanceof IndexPair && equals((IndexPair) o);
+ }
+
+ public int hashCode() {
+ return i << 16 + j;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/LinkedMemoryObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+/**
+ * An object that occupies approximately given number of bytes in memory
+ * and has forward and backward links to other objects.
+ */
+public class LinkedMemoryObject extends MemoryObject {
+ private LinkedMemoryObject next;
+ private LinkedMemoryObject prev;
+
+ /**
+ * Create an object that occupies given number of bytes.
+ *
+ * @param arraySize size
+ */
+ public LinkedMemoryObject(int size) {
+ super(size - 2 * Memory.getReferenceSize());
+ }
+
+ public LinkedMemoryObject(int size, LinkedMemoryObject next) {
+ super(size - 2 * Memory.getReferenceSize());
+ setNext(next);
+ }
+
+ public LinkedMemoryObject(int size, LinkedMemoryObject next, LinkedMemoryObject prev) {
+ super(size - 2 * Memory.getReferenceSize());
+ setNext(next);
+ setPrev(prev);
+ }
+
+ public final void setNext(LinkedMemoryObject next) {
+ this.next = next;
+ }
+
+ public final void setPrev(LinkedMemoryObject prev) {
+ this.prev = prev;
+ }
+
+ public final LinkedMemoryObject getNext() {
+ return next;
+ }
+
+ public final LinkedMemoryObject getPrev() {
+ return prev;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Matrix.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+public class Matrix {
+ private int cellSize;
+ private int matrixSize;
+ private Cell matrix[][];
+ private int nKnockedOut; // number of cells "nulled out"
+
+ public Matrix(int matrixSize, int cellSize) {
+ this.matrixSize = matrixSize;
+ this.cellSize = cellSize;
+ matrix = new Cell[matrixSize][matrixSize];
+ populate();
+ }
+
+ public void populate() {
+ for (int i = 0; i < matrixSize ; i++) {
+ for( int j = 0 ; j < matrixSize ; j++) {
+ matrix[i][j] = new Cell(cellSize, i);
+ }
+ }
+ }
+
+ public int returnArrayBound() {
+ return matrixSize - 1;
+ }
+
+ public synchronized void clear(int i, int j) {
+ matrix[i][j] = null;
+ ++nKnockedOut;
+ }
+
+ public synchronized void repopulate(int i, int j) {
+ matrix[i][j] = new Cell(cellSize, i + j);
+ --nKnockedOut;
+ }
+
+ public synchronized void resetCellCount() {
+ nKnockedOut = 0;
+ }
+
+ public synchronized int getCellCount() {
+ return nKnockedOut;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.test.LocalRandom;
+import java.io.PrintStream;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.tree.*;
+import nsk.share.gc.gp.MemoryStrategy;
+import nsk.share.log.Log;
+
+/**
+ * Different utility methods to work with memory objects.
+ */
+public final class Memory {
+ private static int bits = 0;
+ private static int referenceSize = 0;
+ private static int objectExtraSize = 0;
+
+ private Memory() {
+ }
+
+ private static int getBits() {
+ if (bits == 0)
+ bits = Integer.parseInt(System.getProperty("sun.arch.data.model"));
+ return bits;
+ }
+
+ /**
+ * Get size of one object reference.
+ *
+ * TODO: somehow determine the real value
+ */
+ public static int getReferenceSize() {
+ if (referenceSize == 0)
+ referenceSize = (getBits() == 64) ? 8 : 4;
+ return referenceSize;
+ }
+
+ /**
+ * Get size of primitive type int.
+ */
+ public static int getIntSize() {
+ return 4;
+ }
+
+ /**
+ * Get size of primitive type boolean.
+ */
+ public static int getBooleanSize() {
+ return 1;
+ }
+
+ /**
+ * Get size of primitive type byte.
+ */
+ public static int getByteSize() {
+ return 1;
+ }
+
+ /**
+ * Get size of primitive type char.
+ */
+ public static int getCharSize() {
+ return 2;
+ }
+
+ /**
+ * Get size of primitive type short.
+ */
+ public static int getShortSize() {
+ return 2;
+ }
+
+ /**
+ * Get size of primitive type long.
+ */
+ public static int getLongSize() {
+ return 8;
+ }
+
+ /**
+ * Get size of primitive type float.
+ */
+ public static int getFloatSize() {
+ return 4;
+ }
+
+ /**
+ * Get size of primitive type double.
+ */
+ public static int getDoubleSize() {
+ return 8;
+ }
+
+ /**
+ * Get how many extra bytes an object occupies in the heap
+ * compared to sum of it's fields.
+ *
+ * TODO: somehow determine the real value
+ */
+ public static int getObjectExtraSize() {
+ if (objectExtraSize == 0)
+ objectExtraSize = 2 * getReferenceSize();
+ return objectExtraSize;
+ }
+ /**
+ * Get how many extra bytes an array occupies in the heap
+ * compared to sum of it's fields.
+ *
+ * TODO: somehow determine the real value
+ */
+ public static int getArrayExtraSize() {
+ return getObjectExtraSize();
+ }
+
+ /**
+ * Return size of reference object (SoftReference, WeakReference, PhantomReference)
+ */
+ public static int getReferenceObjectSize() {
+ return getReferenceSize() + getObjectExtraSize();
+ }
+
+ /**
+ * Get an approximate length of array that will occupy a given memory.
+ *
+ * @param memory size of memory
+ * @param objectSize size of each object in array
+ * @return length of array
+ */
+ public static int getArrayLength(long memory, long objectSize) {
+ int referenceSize = getReferenceSize();
+ int arrayExtraSize = getArrayExtraSize();
+ return (int) Math.min(
+ (memory - arrayExtraSize) / (objectSize + referenceSize),
+ Integer.MAX_VALUE
+ );
+ }
+
+ /**
+ * Get an approximate size of array of given length and object size.
+ *
+ * @param length length of arary
+ * @param objectSize size of object in array
+ * @return size of array
+ */
+ public static long getArraySize(int length, long objectSize) {
+ return getObjectExtraSize() + length * (objectSize + getReferenceSize());
+ }
+
+ /**
+ * Calculate approximate size of biggest of MemoryObjects.
+ */
+ public static long getMemoryObjectSize(long size) {
+ return size + 2 * getReferenceSize() + getObjectExtraSize();
+ }
+
+ /**
+ * Calculate approximate size of linked list in memory.
+ *
+ * @param length length of list
+ * @param size size of object
+ * @return size
+ */
+ public static long getListSize(int length, int size) {
+ return getObjectExtraSize() + length * (getReferenceSize() + getMemoryObjectSize(size));
+ }
+
+ /**
+ * Calculate length of linear or circular linked list.
+ *
+ * @param mobj head of list
+ * @return length of list
+ */
+ public static int getListLength(LinkedMemoryObject mobj) {
+ LinkedMemoryObject tobj = mobj;
+ int length = 0;
+ do {
+ ++length;
+ tobj = tobj.getNext();
+ } while (tobj != null && tobj != mobj);
+ return length;
+ }
+
+ /**
+ * Calculate length of array of linear or circular linked lists.
+ *
+ * @param mobjs array containting heads of lists
+ * @return length of all lists
+ */
+ public static int getListsLength(LinkedMemoryObject[] mobjs) {
+ int length = 0;
+ for (int i = 0; i < mobjs.length; ++i) {
+ LinkedMemoryObject mobj = mobjs[i];
+ if (mobj != null)
+ length += getListLength(mobj);
+ }
+ return length;
+ }
+
+ /**
+ * Calculate size of all objects in linear or circular linked list.
+ *
+ * @param mobj head of list
+ * @return size of list
+ */
+ public static long getListSize(LinkedMemoryObject mobj) {
+ LinkedMemoryObject tobj = mobj;
+ long size = 0;
+ do {
+ size += tobj.getSize();
+ tobj = tobj.getNext();
+ } while (tobj != null && tobj != mobj);
+ return size;
+ }
+
+ /**
+ * Calculate size of array of linear or circular linked lists.
+ *
+ * @param mobjs array containting heads of lists
+ * @return size of all lists
+ */
+ public static long getListsSize(LinkedMemoryObject[] mobjs) {
+ long size = 0;
+ for (int i = 0; i < mobjs.length; ++i) {
+ LinkedMemoryObject mobj = mobjs[i];
+ if (mobj != null)
+ size += getListSize(mobj);
+ }
+ return size;
+ }
+
+ /**
+ * Create singly linked linear list of objects of fixed size.
+ *
+ * @param depth length of list
+ * @param size size of each object
+ * @return head of created list or null if depth = 0
+ */
+ public static LinkedMemoryObject makeLinearList(int depth, int size) {
+ LinkedMemoryObject mobj = null;
+ for (int i = 0; i < depth; ++i)
+ mobj = new LinkedMemoryObject(size, mobj);
+ return mobj;
+ }
+
+ /**
+ * Create singly linked linear list of objects of varying size.
+ *
+ * @param depth length of list
+ * @param size maximum size of each object
+ * @return head of created list or null if depth = 0
+ */
+ public static LinkedMemoryObject makeRandomLinearList(int depth, int size) {
+ if (depth == 0)
+ return null;
+ LinkedMemoryObject mobj = new LinkedMemoryObject(size);
+ for (int i = 0; i < depth - 1; ++i)
+ mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj);
+ return mobj;
+ }
+
+ /**
+ * Create singly linked circular linear list of objects of fixed size.
+ *
+ * @param depth length of list
+ * @param size size of each object
+ * @return head of created list or null if depth = 0
+ */
+ public static LinkedMemoryObject makeCircularList(int depth, int size) {
+ if (depth == 0)
+ return null;
+ LinkedMemoryObject mobj = new LinkedMemoryObject(size);
+ LinkedMemoryObject tmpobj = mobj;
+ for (int i = 1; i < depth; i++)
+ mobj = new LinkedMemoryObject(size, mobj);
+ tmpobj.setNext(mobj);
+ return tmpobj;
+ }
+
+ /**
+ * Create singly linked circular linear list of objects of varying size.
+ *
+ * @param depth length of list
+ * @param size maximum size of each object
+ * @return head of created list or null if depth = 0
+ */
+ public static LinkedMemoryObject makeRandomCircularList(int depth, int size) {
+ if (depth == 0)
+ return null;
+ LinkedMemoryObject mobj = new LinkedMemoryObject(size);
+ LinkedMemoryObject tmpobj = mobj;
+ for (int i = 0; i < depth - 1; i++)
+ mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj);
+ tmpobj.setNext(mobj);
+ return tmpobj;
+ }
+
+ /**
+ * Create new nonbranchy binary tree.
+ *
+ * Each node in the tree except leaves always has left son. A node
+ * will have right son with probability branchiness.
+ *
+ * @param numberOfNodes number of nodes
+ * @param branchiness branchiness
+ * @param size size of each node
+ * @return root of created tree
+ */
+ public static LinkedMemoryObject makeNonbranchyTree(int numberOfNodes, float branchiness, int size) {
+ LinkedMemoryObject root = null;
+ LinkedMemoryObject current = null;
+ if (numberOfNodes == 0)
+ return null;
+ else if (numberOfNodes == 1)
+ return new LinkedMemoryObject(size);
+ else if (numberOfNodes == 2)
+ return new LinkedMemoryObject(size, makeNonbranchyTree(1, branchiness, size));
+ else {
+ if (LocalRandom.nextFloat() < branchiness) {
+ int numberOfLeftNodes = LocalRandom.nextInt(1, numberOfNodes - 1);
+ int numberOfRightNodes = numberOfNodes - 1 - numberOfLeftNodes;
+ return new LinkedMemoryObject(
+ size,
+ makeNonbranchyTree(numberOfLeftNodes, branchiness, size),
+ makeNonbranchyTree(numberOfRightNodes, branchiness, size)
+ );
+ } else {
+ return new LinkedMemoryObject(size, makeNonbranchyTree(numberOfNodes - 1, branchiness, size));
+ }
+ }
+ }
+
+ /**
+ * Create a balanced tree of given height.
+ *
+ * @param height height of the tree
+ * @param size size of each node
+ * @return created tree
+ */
+ public static Tree makeBalancedTree(int height, long size) {
+ return new Tree(makeBalancedTreeNode(height, size));
+ }
+
+ /**
+ * Get a number of nodes in balanced tree of given height.
+ *
+ * @param heigh height of the tree
+ * @return number of nodes
+ */
+ public static int balancedTreeNodes(int height) {
+ if (height == 0)
+ return 0;
+ int n = 1;
+ while (height > 1) {
+ n *= 2;
+ height--;
+ }
+ return n * 2 - 1;
+ }
+
+ /**
+ * Get approximate memory size occupied by balanced tree
+ * of given height and given node size.
+ *
+ * @param height height of the tree
+ * @param nodeSize size of each node
+ * @return memory size
+ */
+ public static long balancedTreeSize(int height, long nodeSize) {
+ return balancedTreeNodes(height) * nodeSize;
+ }
+
+ /**
+ * Get a height of balanced tree with given number of nodes.
+ *
+ * @param nodes number of nodes
+ * @return height of the tree
+ */
+ public static int balancedTreeHeightFromNodes(int nodes) {
+ if (nodes == 0)
+ return 0;
+ int h = 1;
+ long n = 1;
+ while (n + n - 1 <= nodes) {
+ n = n + n;
+ h = h + 1;
+ }
+ return h - 1;
+ }
+
+ /**
+ * Get approximate height of balanced tree which will occupy
+ * given memory with given node size.
+ *
+ * @param memory memory size
+ * @param nodeSize size of each node
+ * @return approximate height of the tree
+ */
+ public static int balancedTreeHeightFromMemory(long memory, long nodeSize) {
+ return balancedTreeHeightFromNodes((int) (memory / nodeSize));
+ }
+
+ /**
+ * Create balanced tree of given height and node size.
+ *
+ * @param height height of the tree
+ * @param size size of each node
+ * @return root of created tree
+ */
+ public static TreeNode makeBalancedTreeNode(int height, long size) {
+ if (height == 0)
+ return null;
+ else
+ return new TreeNode(size, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size));
+ }
+
+ /**
+ * Create balanced tree of given height and node size.
+ *
+ * @param height height of the tree
+ * @param size size of each node
+ * @return root of created tree
+ */
+ public static TreeNode makeBalancedTreeNode(int height, long size, GarbageProducer gp) {
+ if (height == 0)
+ return null;
+ else
+ return new TreeNode(size, gp, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size));
+ }
+
+ /**
+ * Determine if given tree is a balanced tree.
+ *
+ * @param tree tree
+ * @return true if tree is balanced
+ */
+ public static boolean isBalancedTree(TreeNode tree) {
+ return
+ tree.getActualHeight() == tree.getHeight() &&
+ tree.getShortestPath() == tree.getHeight();
+ }
+
+ /**
+ * Fill an array of MemoryObject's with new objects of given size.
+ *
+ * @param array array
+ * @param count number of objects to create
+ * @param size size of each object
+ */
+ public static void fillArray(MemoryObject[] array, int count, int size) {
+ for (int i = 0; i < count; ++i)
+ array[i] = new MemoryObject(size);
+ }
+
+ /**
+ * Fill an array of MemoryObject's with new objects of random size.
+ *
+ * @param array array
+ * @param count number of objects to create
+ * @param size maximum size of each object
+ */
+ public static void fillArrayRandom(MemoryObject[] array, int count, int size) {
+ for (int i = 0; i < count; ++i)
+ array[i] = new MemoryObject(LocalRandom.nextInt(size));
+ }
+
+ /**
+ * Fill an array of MemoryObject's with new objects of random size.
+ *
+ * @param array array
+ * @param count number of objects to create
+ * @param size maximum size of each object
+ */
+ public static void fillArrayRandom(LinkedMemoryObject[] array, int count, int size) {
+ for (int i = 0; i < count; ++i)
+ array[i] = new LinkedMemoryObject(LocalRandom.nextInt(size));
+ }
+
+ public static void dumpStatistics(PrintStream out) {
+ out.println(Runtime.getRuntime().freeMemory());
+ out.flush();
+ }
+
+ public static void dumpStatistics(Log log) {
+ log.info(Runtime.getRuntime().freeMemory());
+ }
+
+ public static void dumpStatistics() {
+ dumpStatistics(System.out);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/MemoryObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+/**
+ * An object that occupies approximately given number of bytes in memory.
+ */
+public class MemoryObject {
+ private static int diff = (int) Memory.getObjectExtraSize();
+ private byte storage[];
+
+ /**
+ * Create an object that occupies given number of bytes.
+ *
+ * @param size size
+ */
+ public MemoryObject(int size) {
+ if (size > diff)
+ storage = new byte[size - diff];
+ }
+
+ public final byte[] getStorage() {
+ return storage;
+ }
+
+ public final int getSize() {
+ return storage.length;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/NonbranchyTree.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import java.io.*;
+import java.util.*;
+
+import nsk.share.test.ExecutionController;
+
+/**
+ * <tt>NonbranchyTree</tt> defines a tree structure. Each node of the tree
+ * always has one son. A node may have the second son with probability
+ * <tt>branchiness</tt>.
+ */
+public class NonbranchyTree {
+
+ /** Minimal size of each node (in bytes) */
+ public final static int MIN_NODE_SIZE = 20;
+ private Node root;
+ private Random random;
+ private int numberOfNodes;
+ private float branchiness;
+ private int size;
+ private ExecutionController controller;
+
+ /**
+ * Creates a new tree with number of nodes not more than
+ * <tt>numberOfNodes</tt>. The implementation uses recursion to build the
+ * tree, so if <tt>StackOverflowError</tt> or <tt>OutOfMemoryError</tt> is
+ * thrown, the recursion is stopped and the method finishes building of the
+ * tree. Each node consists of <tt>byte[]</tt> of length <tt>size</tt>.
+ *
+ * @param numberOfNodes maximum number of nodes for the tree.
+ * @param branchiness probability for each node to have the second son.
+ * @param size number of bytes to store in a node.
+ *
+ * @throws <i>IllegalArgumentException</i> if <tt>numberOfNodes</tt> is
+ * less than 1; or <tt>branchiness</tt> is greater than 1, or less
+ * or equal than 0; or <tt>size</tt> is less than 1.
+ *
+ */
+ public NonbranchyTree(int numberOfNodes, float branchiness, int size) {
+ this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), null);
+ initTree();
+ }
+
+ public NonbranchyTree(int numberOfNodes, float branchiness, int size, ExecutionController controller) {
+ this(numberOfNodes, branchiness, size, new Random(System.currentTimeMillis()), controller);
+ initTree();
+ }
+
+ private NonbranchyTree(int numberOfNodes, float branchiness, int size, Random random, ExecutionController controller) {
+ this.numberOfNodes = numberOfNodes;
+ this.branchiness = branchiness;
+ this.size = size;
+ this.random = random;
+ this.controller = controller;
+ }
+
+ private void initTree() {
+ if (numberOfNodes < 1) {
+ throw new IllegalArgumentException("Illegal number of nodes: "
+ + numberOfNodes + ", must be at "
+ + "least 1.");
+ }
+ if ( (branchiness >= 1) || (branchiness <= 0) ) {
+ throw new IllegalArgumentException("Illegal value of branchiness: "
+ + numberOfNodes + ", must be at "
+ + "greater than 0 and less than "
+ + " 1.");
+ }
+ if (size < 1) {
+ throw new IllegalArgumentException("Illegal size of nodes: "
+ + size + ", must be at least 1.");
+ }
+ root = createTree(numberOfNodes, size);
+ }
+
+ // Create a new tree with specified number of nodes and size of each node
+ private Node createTree(int numberOfNodes, int size) {
+ // Make sure we respect the controller and stop test after
+ // given time.
+ if (controller != null && !controller.continueExecution()) {
+ return null;
+ }
+
+ Node node = new Node(size);
+ try {
+ if (numberOfNodes == 0) {
+ // No more nodes need to be built
+ return null;
+ } else if (numberOfNodes == 1) {
+ return node;
+ } else if (numberOfNodes == 2) {
+ node.left = createTree(1, size);
+ return node;
+ } else {
+ // Create a few nodes
+ if (makeRightNode()) {
+ // The node will have two sons
+ int leftNodes = 1 + random.nextInt(numberOfNodes - 2);
+ int rightNodes = numberOfNodes - 1 - leftNodes;
+
+ node.left = createTree(leftNodes, size);
+ node.right = createTree(rightNodes, size);
+ } else {
+ // The node will have just one son
+ Node leftTree = createTree(numberOfNodes - 1, size);
+ node.left = leftTree;
+ }
+ return node;
+ } // if
+ } catch(StackOverflowError e) {
+ // No more memory for such long tree
+ return node;
+ } catch(OutOfMemoryError e) {
+ // No more memory for such long tree
+ return node;
+ } // try
+ } // createTree()
+
+ // Define the "branchiness" of the tree
+ private boolean makeRightNode() {
+ return (random.nextFloat() < branchiness);
+ }
+
+ /**
+ * Bends the tree. A son of a leaf of the tree is set to the root node.
+ *
+ */
+ public void bend() {
+ bend(root);
+ }
+
+ // Bend the tree: make a reference from a leat of the tree to the specified
+ // node
+ private void bend(Node markedNode) {
+ Node node = root;
+
+ while ( (node.left != null) || (node.right != null) )
+ node = node.left;
+ node.right = markedNode;
+ }
+
+ /**
+ * Prints the whole tree from the root to the defined PrintStream.
+ *
+ * @param out PrintStream to print the tree in
+ *
+ */
+ public void print(PrintStream out) {
+ print(out, root);
+ }
+
+ // Print the sub-tree from the specified node and down
+ private void print(PrintStream out, Node node) {
+ node.print(out);
+ if (node.left != null)
+ print(out, node.left);
+ if (node.right != null)
+ print(out, node.right);
+ }
+}
+
+// The class defines a node of a tree
+class Node {
+ Node left;
+ Node right;
+ byte[] core;
+
+ Node(int size) {
+ left = null;
+ right = null;
+ core = new byte[size];
+
+ // Initizlize the core array
+ for (int i = 0; i < size; i++)
+ core[i] = (byte) i;
+ }
+
+ // Print the node info
+ void print(PrintStream out) {
+ out.println("node = " + this + " (" + left + ", " + right + ")");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/OOMStress.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+/**
+ * Marker interface to tell that a something stresses OOM.
+ */
+public interface OOMStress {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/ThreadedGCTest.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc;
+
+import nsk.share.runner.*;
+import nsk.share.test.ExecutionController;
+import nsk.share.Consts;
+
+/**
+ * Test that executes a number of tasks.
+ *
+ * How these tasks are used is determined by MultiRunner.
+ * Usually they are executed in separate threads in cycle
+ * for some time or for some iterations.
+ *
+ * @see nsk.share.runner.MultiRunner
+ * @see nsk.share.runner.ThreadsRunner
+ */
+public abstract class ThreadedGCTest extends GCTestBase implements MultiRunnerAware {
+ private MultiRunner runner;
+
+ /**
+ * Create a task with index i.
+ *
+ * Subclasses should to override this method
+ * to created neccessary tasks.
+ *
+ * @param i index of task
+ * @return task to run or null
+ */
+ protected abstract Runnable createRunnable(int i);
+
+ protected ExecutionController getExecutionController() {
+ return runner.getExecutionController();
+ }
+
+ protected final boolean runThreads() {
+ for (int i = 0; i < runParams.getNumberOfThreads(); ++i) {
+ Runnable runnable = createRunnable(i);
+ if (runnable != null)
+ runner.add(runnable);
+ }
+ runner.run();
+ return runner.isSuccessful();
+ }
+
+ public void run() {
+ if (!runThreads())
+ setFailed(true);
+ }
+
+ public final void setRunner(MultiRunner runner) {
+ this.runner = runner;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/TwoFieldsObject.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.gc;
+
+/**
+ * An object with two fields of same type.
+ */
+public class TwoFieldsObject<T> {
+ private T left, right;
+
+ public TwoFieldsObject(T left, T right) {
+ setLeft(left);
+ setRight(right);
+ }
+
+ public final void setLeft(T left) {
+ this.left = left;
+ }
+
+ public final void setRight(T right) {
+ this.right = right;
+ }
+
+ public final T getLeft() {
+ return left;
+ }
+
+ public final T getRight() {
+ return right;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/classes/Classes.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,5024 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.classes;
+
+class Class1 {
+ public Class1(){
+
+ }
+}
+class Class2 {
+ public Class2(){
+
+ }
+}
+class Class3 {
+ public Class3(){
+
+ }
+}
+class Class4 {
+ public Class4(){
+
+ }
+}
+class Class5 {
+ public Class5(){
+
+ }
+}
+class Class6 {
+ public Class6(){
+
+ }
+}
+class Class7 {
+ public Class7(){
+
+ }
+}
+class Class8 {
+ public Class8(){
+
+ }
+}
+class Class9 {
+ public Class9(){
+
+ }
+}
+class Class10 {
+ public Class10(){
+
+ }
+}
+class Class11 {
+ public Class11(){
+
+ }
+}
+class Class12 {
+ public Class12(){
+
+ }
+}
+class Class13 {
+ public Class13(){
+
+ }
+}
+class Class14 {
+ public Class14(){
+
+ }
+}
+class Class15 {
+ public Class15(){
+
+ }
+}
+class Class16 {
+ public Class16(){
+
+ }
+}
+class Class17 {
+ public Class17(){
+
+ }
+}
+class Class18 {
+ public Class18(){
+
+ }
+}
+class Class19 {
+ public Class19(){
+
+ }
+}
+class Class20 {
+ public Class20(){
+
+ }
+}
+class Class21 {
+ public Class21(){
+
+ }
+}
+class Class22 {
+ public Class22(){
+
+ }
+}
+class Class23 {
+ public Class23(){
+
+ }
+}
+class Class24 {
+ public Class24(){
+
+ }
+}
+class Class25 {
+ public Class25(){
+
+ }
+}
+class Class26 {
+ public Class26(){
+
+ }
+}
+class Class27 {
+ public Class27(){
+
+ }
+}
+class Class28 {
+ public Class28(){
+
+ }
+}
+class Class29 {
+ public Class29(){
+
+ }
+}
+class Class30 {
+ public Class30(){
+
+ }
+}
+class Class31 {
+ public Class31(){
+
+ }
+}
+class Class32 {
+ public Class32(){
+
+ }
+}
+class Class33 {
+ public Class33(){
+
+ }
+}
+class Class34 {
+ public Class34(){
+
+ }
+}
+class Class35 {
+ public Class35(){
+
+ }
+}
+class Class36 {
+ public Class36(){
+
+ }
+}
+class Class37 {
+ public Class37(){
+
+ }
+}
+class Class38 {
+ public Class38(){
+
+ }
+}
+class Class39 {
+ public Class39(){
+
+ }
+}
+class Class40 {
+ public Class40(){
+
+ }
+}
+class Class41 {
+ public Class41(){
+
+ }
+}
+class Class42 {
+ public Class42(){
+
+ }
+}
+class Class43 {
+ public Class43(){
+
+ }
+}
+class Class44 {
+ public Class44(){
+
+ }
+}
+class Class45 {
+ public Class45(){
+
+ }
+}
+class Class46 {
+ public Class46(){
+
+ }
+}
+class Class47 {
+ public Class47(){
+
+ }
+}
+class Class48 {
+ public Class48(){
+
+ }
+}
+class Class49 {
+ public Class49(){
+
+ }
+}
+class Class50 {
+ public Class50(){
+
+ }
+}
+class Class51 {
+ public Class51(){
+
+ }
+}
+class Class52 {
+ public Class52(){
+
+ }
+}
+class Class53 {
+ public Class53(){
+
+ }
+}
+class Class54 {
+ public Class54(){
+
+ }
+}
+class Class55 {
+ public Class55(){
+
+ }
+}
+class Class56 {
+ public Class56(){
+
+ }
+}
+class Class57 {
+ public Class57(){
+
+ }
+}
+class Class58 {
+ public Class58(){
+
+ }
+}
+class Class59 {
+ public Class59(){
+
+ }
+}
+class Class60 {
+ public Class60(){
+
+ }
+}
+class Class61 {
+ public Class61(){
+
+ }
+}
+class Class62 {
+ public Class62(){
+
+ }
+}
+class Class63 {
+ public Class63(){
+
+ }
+}
+class Class64 {
+ public Class64(){
+
+ }
+}
+class Class65 {
+ public Class65(){
+
+ }
+}
+class Class66 {
+ public Class66(){
+
+ }
+}
+class Class67 {
+ public Class67(){
+
+ }
+}
+class Class68 {
+ public Class68(){
+
+ }
+}
+class Class69 {
+ public Class69(){
+
+ }
+}
+class Class70 {
+ public Class70(){
+
+ }
+}
+class Class71 {
+ public Class71(){
+
+ }
+}
+class Class72 {
+ public Class72(){
+
+ }
+}
+class Class73 {
+ public Class73(){
+
+ }
+}
+class Class74 {
+ public Class74(){
+
+ }
+}
+class Class75 {
+ public Class75(){
+
+ }
+}
+class Class76 {
+ public Class76(){
+
+ }
+}
+class Class77 {
+ public Class77(){
+
+ }
+}
+class Class78 {
+ public Class78(){
+
+ }
+}
+class Class79 {
+ public Class79(){
+
+ }
+}
+class Class80 {
+ public Class80(){
+
+ }
+}
+class Class81 {
+ public Class81(){
+
+ }
+}
+class Class82 {
+ public Class82(){
+
+ }
+}
+class Class83 {
+ public Class83(){
+
+ }
+}
+class Class84 {
+ public Class84(){
+
+ }
+}
+class Class85 {
+ public Class85(){
+
+ }
+}
+class Class86 {
+ public Class86(){
+
+ }
+}
+class Class87 {
+ public Class87(){
+
+ }
+}
+class Class88 {
+ public Class88(){
+
+ }
+}
+class Class89 {
+ public Class89(){
+
+ }
+}
+class Class90 {
+ public Class90(){
+
+ }
+}
+class Class91 {
+ public Class91(){
+
+ }
+}
+class Class92 {
+ public Class92(){
+
+ }
+}
+class Class93 {
+ public Class93(){
+
+ }
+}
+class Class94 {
+ public Class94(){
+
+ }
+}
+class Class95 {
+ public Class95(){
+
+ }
+}
+class Class96 {
+ public Class96(){
+
+ }
+}
+class Class97 {
+ public Class97(){
+
+ }
+}
+class Class98 {
+ public Class98(){
+
+ }
+}
+class Class99 {
+ public Class99(){
+
+ }
+}
+class Class100 {
+ public Class100(){
+
+ }
+}
+class Class101 {
+ public Class101(){
+
+ }
+}
+class Class102 {
+ public Class102(){
+
+ }
+}
+class Class103 {
+ public Class103(){
+
+ }
+}
+class Class104 {
+ public Class104(){
+
+ }
+}
+class Class105 {
+ public Class105(){
+
+ }
+}
+class Class106 {
+ public Class106(){
+
+ }
+}
+class Class107 {
+ public Class107(){
+
+ }
+}
+class Class108 {
+ public Class108(){
+
+ }
+}
+class Class109 {
+ public Class109(){
+
+ }
+}
+class Class110 {
+ public Class110(){
+
+ }
+}
+class Class111 {
+ public Class111(){
+
+ }
+}
+class Class112 {
+ public Class112(){
+
+ }
+}
+class Class113 {
+ public Class113(){
+
+ }
+}
+class Class114 {
+ public Class114(){
+
+ }
+}
+class Class115 {
+ public Class115(){
+
+ }
+}
+class Class116 {
+ public Class116(){
+
+ }
+}
+class Class117 {
+ public Class117(){
+
+ }
+}
+class Class118 {
+ public Class118(){
+
+ }
+}
+class Class119 {
+ public Class119(){
+
+ }
+}
+class Class120 {
+ public Class120(){
+
+ }
+}
+class Class121 {
+ public Class121(){
+
+ }
+}
+class Class122 {
+ public Class122(){
+
+ }
+}
+class Class123 {
+ public Class123(){
+
+ }
+}
+class Class124 {
+ public Class124(){
+
+ }
+}
+class Class125 {
+ public Class125(){
+
+ }
+}
+class Class126 {
+ public Class126(){
+
+ }
+}
+class Class127 {
+ public Class127(){
+
+ }
+}
+class Class128 {
+ public Class128(){
+
+ }
+}
+class Class129 {
+ public Class129(){
+
+ }
+}
+class Class130 {
+ public Class130(){
+
+ }
+}
+class Class131 {
+ public Class131(){
+
+ }
+}
+class Class132 {
+ public Class132(){
+
+ }
+}
+class Class133 {
+ public Class133(){
+
+ }
+}
+class Class134 {
+ public Class134(){
+
+ }
+}
+class Class135 {
+ public Class135(){
+
+ }
+}
+class Class136 {
+ public Class136(){
+
+ }
+}
+class Class137 {
+ public Class137(){
+
+ }
+}
+class Class138 {
+ public Class138(){
+
+ }
+}
+class Class139 {
+ public Class139(){
+
+ }
+}
+class Class140 {
+ public Class140(){
+
+ }
+}
+class Class141 {
+ public Class141(){
+
+ }
+}
+class Class142 {
+ public Class142(){
+
+ }
+}
+class Class143 {
+ public Class143(){
+
+ }
+}
+class Class144 {
+ public Class144(){
+
+ }
+}
+class Class145 {
+ public Class145(){
+
+ }
+}
+class Class146 {
+ public Class146(){
+
+ }
+}
+class Class147 {
+ public Class147(){
+
+ }
+}
+class Class148 {
+ public Class148(){
+
+ }
+}
+class Class149 {
+ public Class149(){
+
+ }
+}
+class Class150 {
+ public Class150(){
+
+ }
+}
+class Class151 {
+ public Class151(){
+
+ }
+}
+class Class152 {
+ public Class152(){
+
+ }
+}
+class Class153 {
+ public Class153(){
+
+ }
+}
+class Class154 {
+ public Class154(){
+
+ }
+}
+class Class155 {
+ public Class155(){
+
+ }
+}
+class Class156 {
+ public Class156(){
+
+ }
+}
+class Class157 {
+ public Class157(){
+
+ }
+}
+class Class158 {
+ public Class158(){
+
+ }
+}
+class Class159 {
+ public Class159(){
+
+ }
+}
+class Class160 {
+ public Class160(){
+
+ }
+}
+class Class161 {
+ public Class161(){
+
+ }
+}
+class Class162 {
+ public Class162(){
+
+ }
+}
+class Class163 {
+ public Class163(){
+
+ }
+}
+class Class164 {
+ public Class164(){
+
+ }
+}
+class Class165 {
+ public Class165(){
+
+ }
+}
+class Class166 {
+ public Class166(){
+
+ }
+}
+class Class167 {
+ public Class167(){
+
+ }
+}
+class Class168 {
+ public Class168(){
+
+ }
+}
+class Class169 {
+ public Class169(){
+
+ }
+}
+class Class170 {
+ public Class170(){
+
+ }
+}
+class Class171 {
+ public Class171(){
+
+ }
+}
+class Class172 {
+ public Class172(){
+
+ }
+}
+class Class173 {
+ public Class173(){
+
+ }
+}
+class Class174 {
+ public Class174(){
+
+ }
+}
+class Class175 {
+ public Class175(){
+
+ }
+}
+class Class176 {
+ public Class176(){
+
+ }
+}
+class Class177 {
+ public Class177(){
+
+ }
+}
+class Class178 {
+ public Class178(){
+
+ }
+}
+class Class179 {
+ public Class179(){
+
+ }
+}
+class Class180 {
+ public Class180(){
+
+ }
+}
+class Class181 {
+ public Class181(){
+
+ }
+}
+class Class182 {
+ public Class182(){
+
+ }
+}
+class Class183 {
+ public Class183(){
+
+ }
+}
+class Class184 {
+ public Class184(){
+
+ }
+}
+class Class185 {
+ public Class185(){
+
+ }
+}
+class Class186 {
+ public Class186(){
+
+ }
+}
+class Class187 {
+ public Class187(){
+
+ }
+}
+class Class188 {
+ public Class188(){
+
+ }
+}
+class Class189 {
+ public Class189(){
+
+ }
+}
+class Class190 {
+ public Class190(){
+
+ }
+}
+class Class191 {
+ public Class191(){
+
+ }
+}
+class Class192 {
+ public Class192(){
+
+ }
+}
+class Class193 {
+ public Class193(){
+
+ }
+}
+class Class194 {
+ public Class194(){
+
+ }
+}
+class Class195 {
+ public Class195(){
+
+ }
+}
+class Class196 {
+ public Class196(){
+
+ }
+}
+class Class197 {
+ public Class197(){
+
+ }
+}
+class Class198 {
+ public Class198(){
+
+ }
+}
+class Class199 {
+ public Class199(){
+
+ }
+}
+class Class200 {
+ public Class200(){
+
+ }
+}
+class Class201 {
+ public Class201(){
+
+ }
+}
+class Class202 {
+ public Class202(){
+
+ }
+}
+class Class203 {
+ public Class203(){
+
+ }
+}
+class Class204 {
+ public Class204(){
+
+ }
+}
+class Class205 {
+ public Class205(){
+
+ }
+}
+class Class206 {
+ public Class206(){
+
+ }
+}
+class Class207 {
+ public Class207(){
+
+ }
+}
+class Class208 {
+ public Class208(){
+
+ }
+}
+class Class209 {
+ public Class209(){
+
+ }
+}
+class Class210 {
+ public Class210(){
+
+ }
+}
+class Class211 {
+ public Class211(){
+
+ }
+}
+class Class212 {
+ public Class212(){
+
+ }
+}
+class Class213 {
+ public Class213(){
+
+ }
+}
+class Class214 {
+ public Class214(){
+
+ }
+}
+class Class215 {
+ public Class215(){
+
+ }
+}
+class Class216 {
+ public Class216(){
+
+ }
+}
+class Class217 {
+ public Class217(){
+
+ }
+}
+class Class218 {
+ public Class218(){
+
+ }
+}
+class Class219 {
+ public Class219(){
+
+ }
+}
+class Class220 {
+ public Class220(){
+
+ }
+}
+class Class221 {
+ public Class221(){
+
+ }
+}
+class Class222 {
+ public Class222(){
+
+ }
+}
+class Class223 {
+ public Class223(){
+
+ }
+}
+class Class224 {
+ public Class224(){
+
+ }
+}
+class Class225 {
+ public Class225(){
+
+ }
+}
+class Class226 {
+ public Class226(){
+
+ }
+}
+class Class227 {
+ public Class227(){
+
+ }
+}
+class Class228 {
+ public Class228(){
+
+ }
+}
+class Class229 {
+ public Class229(){
+
+ }
+}
+class Class230 {
+ public Class230(){
+
+ }
+}
+class Class231 {
+ public Class231(){
+
+ }
+}
+class Class232 {
+ public Class232(){
+
+ }
+}
+class Class233 {
+ public Class233(){
+
+ }
+}
+class Class234 {
+ public Class234(){
+
+ }
+}
+class Class235 {
+ public Class235(){
+
+ }
+}
+class Class236 {
+ public Class236(){
+
+ }
+}
+class Class237 {
+ public Class237(){
+
+ }
+}
+class Class238 {
+ public Class238(){
+
+ }
+}
+class Class239 {
+ public Class239(){
+
+ }
+}
+class Class240 {
+ public Class240(){
+
+ }
+}
+class Class241 {
+ public Class241(){
+
+ }
+}
+class Class242 {
+ public Class242(){
+
+ }
+}
+class Class243 {
+ public Class243(){
+
+ }
+}
+class Class244 {
+ public Class244(){
+
+ }
+}
+class Class245 {
+ public Class245(){
+
+ }
+}
+class Class246 {
+ public Class246(){
+
+ }
+}
+class Class247 {
+ public Class247(){
+
+ }
+}
+class Class248 {
+ public Class248(){
+
+ }
+}
+class Class249 {
+ public Class249(){
+
+ }
+}
+class Class250 {
+ public Class250(){
+
+ }
+}
+class Class251 {
+ public Class251(){
+
+ }
+}
+class Class252 {
+ public Class252(){
+
+ }
+}
+class Class253 {
+ public Class253(){
+
+ }
+}
+class Class254 {
+ public Class254(){
+
+ }
+}
+class Class255 {
+ public Class255(){
+
+ }
+}
+class Class256 {
+ public Class256(){
+
+ }
+}
+class Class257 {
+ public Class257(){
+
+ }
+}
+class Class258 {
+ public Class258(){
+
+ }
+}
+class Class259 {
+ public Class259(){
+
+ }
+}
+class Class260 {
+ public Class260(){
+
+ }
+}
+class Class261 {
+ public Class261(){
+
+ }
+}
+class Class262 {
+ public Class262(){
+
+ }
+}
+class Class263 {
+ public Class263(){
+
+ }
+}
+class Class264 {
+ public Class264(){
+
+ }
+}
+class Class265 {
+ public Class265(){
+
+ }
+}
+class Class266 {
+ public Class266(){
+
+ }
+}
+class Class267 {
+ public Class267(){
+
+ }
+}
+class Class268 {
+ public Class268(){
+
+ }
+}
+class Class269 {
+ public Class269(){
+
+ }
+}
+class Class270 {
+ public Class270(){
+
+ }
+}
+class Class271 {
+ public Class271(){
+
+ }
+}
+class Class272 {
+ public Class272(){
+
+ }
+}
+class Class273 {
+ public Class273(){
+
+ }
+}
+class Class274 {
+ public Class274(){
+
+ }
+}
+class Class275 {
+ public Class275(){
+
+ }
+}
+class Class276 {
+ public Class276(){
+
+ }
+}
+class Class277 {
+ public Class277(){
+
+ }
+}
+class Class278 {
+ public Class278(){
+
+ }
+}
+class Class279 {
+ public Class279(){
+
+ }
+}
+class Class280 {
+ public Class280(){
+
+ }
+}
+class Class281 {
+ public Class281(){
+
+ }
+}
+class Class282 {
+ public Class282(){
+
+ }
+}
+class Class283 {
+ public Class283(){
+
+ }
+}
+class Class284 {
+ public Class284(){
+
+ }
+}
+class Class285 {
+ public Class285(){
+
+ }
+}
+class Class286 {
+ public Class286(){
+
+ }
+}
+class Class287 {
+ public Class287(){
+
+ }
+}
+class Class288 {
+ public Class288(){
+
+ }
+}
+class Class289 {
+ public Class289(){
+
+ }
+}
+class Class290 {
+ public Class290(){
+
+ }
+}
+class Class291 {
+ public Class291(){
+
+ }
+}
+class Class292 {
+ public Class292(){
+
+ }
+}
+class Class293 {
+ public Class293(){
+
+ }
+}
+class Class294 {
+ public Class294(){
+
+ }
+}
+class Class295 {
+ public Class295(){
+
+ }
+}
+class Class296 {
+ public Class296(){
+
+ }
+}
+class Class297 {
+ public Class297(){
+
+ }
+}
+class Class298 {
+ public Class298(){
+
+ }
+}
+class Class299 {
+ public Class299(){
+
+ }
+}
+class Class300 {
+ public Class300(){
+
+ }
+}
+class Class301 {
+ public Class301(){
+
+ }
+}
+class Class302 {
+ public Class302(){
+
+ }
+}
+class Class303 {
+ public Class303(){
+
+ }
+}
+class Class304 {
+ public Class304(){
+
+ }
+}
+class Class305 {
+ public Class305(){
+
+ }
+}
+class Class306 {
+ public Class306(){
+
+ }
+}
+class Class307 {
+ public Class307(){
+
+ }
+}
+class Class308 {
+ public Class308(){
+
+ }
+}
+class Class309 {
+ public Class309(){
+
+ }
+}
+class Class310 {
+ public Class310(){
+
+ }
+}
+class Class311 {
+ public Class311(){
+
+ }
+}
+class Class312 {
+ public Class312(){
+
+ }
+}
+class Class313 {
+ public Class313(){
+
+ }
+}
+class Class314 {
+ public Class314(){
+
+ }
+}
+class Class315 {
+ public Class315(){
+
+ }
+}
+class Class316 {
+ public Class316(){
+
+ }
+}
+class Class317 {
+ public Class317(){
+
+ }
+}
+class Class318 {
+ public Class318(){
+
+ }
+}
+class Class319 {
+ public Class319(){
+
+ }
+}
+class Class320 {
+ public Class320(){
+
+ }
+}
+class Class321 {
+ public Class321(){
+
+ }
+}
+class Class322 {
+ public Class322(){
+
+ }
+}
+class Class323 {
+ public Class323(){
+
+ }
+}
+class Class324 {
+ public Class324(){
+
+ }
+}
+class Class325 {
+ public Class325(){
+
+ }
+}
+class Class326 {
+ public Class326(){
+
+ }
+}
+class Class327 {
+ public Class327(){
+
+ }
+}
+class Class328 {
+ public Class328(){
+
+ }
+}
+class Class329 {
+ public Class329(){
+
+ }
+}
+class Class330 {
+ public Class330(){
+
+ }
+}
+class Class331 {
+ public Class331(){
+
+ }
+}
+class Class332 {
+ public Class332(){
+
+ }
+}
+class Class333 {
+ public Class333(){
+
+ }
+}
+class Class334 {
+ public Class334(){
+
+ }
+}
+class Class335 {
+ public Class335(){
+
+ }
+}
+class Class336 {
+ public Class336(){
+
+ }
+}
+class Class337 {
+ public Class337(){
+
+ }
+}
+class Class338 {
+ public Class338(){
+
+ }
+}
+class Class339 {
+ public Class339(){
+
+ }
+}
+class Class340 {
+ public Class340(){
+
+ }
+}
+class Class341 {
+ public Class341(){
+
+ }
+}
+class Class342 {
+ public Class342(){
+
+ }
+}
+class Class343 {
+ public Class343(){
+
+ }
+}
+class Class344 {
+ public Class344(){
+
+ }
+}
+class Class345 {
+ public Class345(){
+
+ }
+}
+class Class346 {
+ public Class346(){
+
+ }
+}
+class Class347 {
+ public Class347(){
+
+ }
+}
+class Class348 {
+ public Class348(){
+
+ }
+}
+class Class349 {
+ public Class349(){
+
+ }
+}
+class Class350 {
+ public Class350(){
+
+ }
+}
+class Class351 {
+ public Class351(){
+
+ }
+}
+class Class352 {
+ public Class352(){
+
+ }
+}
+class Class353 {
+ public Class353(){
+
+ }
+}
+class Class354 {
+ public Class354(){
+
+ }
+}
+class Class355 {
+ public Class355(){
+
+ }
+}
+class Class356 {
+ public Class356(){
+
+ }
+}
+class Class357 {
+ public Class357(){
+
+ }
+}
+class Class358 {
+ public Class358(){
+
+ }
+}
+class Class359 {
+ public Class359(){
+
+ }
+}
+class Class360 {
+ public Class360(){
+
+ }
+}
+class Class361 {
+ public Class361(){
+
+ }
+}
+class Class362 {
+ public Class362(){
+
+ }
+}
+class Class363 {
+ public Class363(){
+
+ }
+}
+class Class364 {
+ public Class364(){
+
+ }
+}
+class Class365 {
+ public Class365(){
+
+ }
+}
+class Class366 {
+ public Class366(){
+
+ }
+}
+class Class367 {
+ public Class367(){
+
+ }
+}
+class Class368 {
+ public Class368(){
+
+ }
+}
+class Class369 {
+ public Class369(){
+
+ }
+}
+class Class370 {
+ public Class370(){
+
+ }
+}
+class Class371 {
+ public Class371(){
+
+ }
+}
+class Class372 {
+ public Class372(){
+
+ }
+}
+class Class373 {
+ public Class373(){
+
+ }
+}
+class Class374 {
+ public Class374(){
+
+ }
+}
+class Class375 {
+ public Class375(){
+
+ }
+}
+class Class376 {
+ public Class376(){
+
+ }
+}
+class Class377 {
+ public Class377(){
+
+ }
+}
+class Class378 {
+ public Class378(){
+
+ }
+}
+class Class379 {
+ public Class379(){
+
+ }
+}
+class Class380 {
+ public Class380(){
+
+ }
+}
+class Class381 {
+ public Class381(){
+
+ }
+}
+class Class382 {
+ public Class382(){
+
+ }
+}
+class Class383 {
+ public Class383(){
+
+ }
+}
+class Class384 {
+ public Class384(){
+
+ }
+}
+class Class385 {
+ public Class385(){
+
+ }
+}
+class Class386 {
+ public Class386(){
+
+ }
+}
+class Class387 {
+ public Class387(){
+
+ }
+}
+class Class388 {
+ public Class388(){
+
+ }
+}
+class Class389 {
+ public Class389(){
+
+ }
+}
+class Class390 {
+ public Class390(){
+
+ }
+}
+class Class391 {
+ public Class391(){
+
+ }
+}
+class Class392 {
+ public Class392(){
+
+ }
+}
+class Class393 {
+ public Class393(){
+
+ }
+}
+class Class394 {
+ public Class394(){
+
+ }
+}
+class Class395 {
+ public Class395(){
+
+ }
+}
+class Class396 {
+ public Class396(){
+
+ }
+}
+class Class397 {
+ public Class397(){
+
+ }
+}
+class Class398 {
+ public Class398(){
+
+ }
+}
+class Class399 {
+ public Class399(){
+
+ }
+}
+class Class400 {
+ public Class400(){
+
+ }
+}
+class Class401 {
+ public Class401(){
+
+ }
+}
+class Class402 {
+ public Class402(){
+
+ }
+}
+class Class403 {
+ public Class403(){
+
+ }
+}
+class Class404 {
+ public Class404(){
+
+ }
+}
+class Class405 {
+ public Class405(){
+
+ }
+}
+class Class406 {
+ public Class406(){
+
+ }
+}
+class Class407 {
+ public Class407(){
+
+ }
+}
+class Class408 {
+ public Class408(){
+
+ }
+}
+class Class409 {
+ public Class409(){
+
+ }
+}
+class Class410 {
+ public Class410(){
+
+ }
+}
+class Class411 {
+ public Class411(){
+
+ }
+}
+class Class412 {
+ public Class412(){
+
+ }
+}
+class Class413 {
+ public Class413(){
+
+ }
+}
+class Class414 {
+ public Class414(){
+
+ }
+}
+class Class415 {
+ public Class415(){
+
+ }
+}
+class Class416 {
+ public Class416(){
+
+ }
+}
+class Class417 {
+ public Class417(){
+
+ }
+}
+class Class418 {
+ public Class418(){
+
+ }
+}
+class Class419 {
+ public Class419(){
+
+ }
+}
+class Class420 {
+ public Class420(){
+
+ }
+}
+class Class421 {
+ public Class421(){
+
+ }
+}
+class Class422 {
+ public Class422(){
+
+ }
+}
+class Class423 {
+ public Class423(){
+
+ }
+}
+class Class424 {
+ public Class424(){
+
+ }
+}
+class Class425 {
+ public Class425(){
+
+ }
+}
+class Class426 {
+ public Class426(){
+
+ }
+}
+class Class427 {
+ public Class427(){
+
+ }
+}
+class Class428 {
+ public Class428(){
+
+ }
+}
+class Class429 {
+ public Class429(){
+
+ }
+}
+class Class430 {
+ public Class430(){
+
+ }
+}
+class Class431 {
+ public Class431(){
+
+ }
+}
+class Class432 {
+ public Class432(){
+
+ }
+}
+class Class433 {
+ public Class433(){
+
+ }
+}
+class Class434 {
+ public Class434(){
+
+ }
+}
+class Class435 {
+ public Class435(){
+
+ }
+}
+class Class436 {
+ public Class436(){
+
+ }
+}
+class Class437 {
+ public Class437(){
+
+ }
+}
+class Class438 {
+ public Class438(){
+
+ }
+}
+class Class439 {
+ public Class439(){
+
+ }
+}
+class Class440 {
+ public Class440(){
+
+ }
+}
+class Class441 {
+ public Class441(){
+
+ }
+}
+class Class442 {
+ public Class442(){
+
+ }
+}
+class Class443 {
+ public Class443(){
+
+ }
+}
+class Class444 {
+ public Class444(){
+
+ }
+}
+class Class445 {
+ public Class445(){
+
+ }
+}
+class Class446 {
+ public Class446(){
+
+ }
+}
+class Class447 {
+ public Class447(){
+
+ }
+}
+class Class448 {
+ public Class448(){
+
+ }
+}
+class Class449 {
+ public Class449(){
+
+ }
+}
+class Class450 {
+ public Class450(){
+
+ }
+}
+class Class451 {
+ public Class451(){
+
+ }
+}
+class Class452 {
+ public Class452(){
+
+ }
+}
+class Class453 {
+ public Class453(){
+
+ }
+}
+class Class454 {
+ public Class454(){
+
+ }
+}
+class Class455 {
+ public Class455(){
+
+ }
+}
+class Class456 {
+ public Class456(){
+
+ }
+}
+class Class457 {
+ public Class457(){
+
+ }
+}
+class Class458 {
+ public Class458(){
+
+ }
+}
+class Class459 {
+ public Class459(){
+
+ }
+}
+class Class460 {
+ public Class460(){
+
+ }
+}
+class Class461 {
+ public Class461(){
+
+ }
+}
+class Class462 {
+ public Class462(){
+
+ }
+}
+class Class463 {
+ public Class463(){
+
+ }
+}
+class Class464 {
+ public Class464(){
+
+ }
+}
+class Class465 {
+ public Class465(){
+
+ }
+}
+class Class466 {
+ public Class466(){
+
+ }
+}
+class Class467 {
+ public Class467(){
+
+ }
+}
+class Class468 {
+ public Class468(){
+
+ }
+}
+class Class469 {
+ public Class469(){
+
+ }
+}
+class Class470 {
+ public Class470(){
+
+ }
+}
+class Class471 {
+ public Class471(){
+
+ }
+}
+class Class472 {
+ public Class472(){
+
+ }
+}
+class Class473 {
+ public Class473(){
+
+ }
+}
+class Class474 {
+ public Class474(){
+
+ }
+}
+class Class475 {
+ public Class475(){
+
+ }
+}
+class Class476 {
+ public Class476(){
+
+ }
+}
+class Class477 {
+ public Class477(){
+
+ }
+}
+class Class478 {
+ public Class478(){
+
+ }
+}
+class Class479 {
+ public Class479(){
+
+ }
+}
+class Class480 {
+ public Class480(){
+
+ }
+}
+class Class481 {
+ public Class481(){
+
+ }
+}
+class Class482 {
+ public Class482(){
+
+ }
+}
+class Class483 {
+ public Class483(){
+
+ }
+}
+class Class484 {
+ public Class484(){
+
+ }
+}
+class Class485 {
+ public Class485(){
+
+ }
+}
+class Class486 {
+ public Class486(){
+
+ }
+}
+class Class487 {
+ public Class487(){
+
+ }
+}
+class Class488 {
+ public Class488(){
+
+ }
+}
+class Class489 {
+ public Class489(){
+
+ }
+}
+class Class490 {
+ public Class490(){
+
+ }
+}
+class Class491 {
+ public Class491(){
+
+ }
+}
+class Class492 {
+ public Class492(){
+
+ }
+}
+class Class493 {
+ public Class493(){
+
+ }
+}
+class Class494 {
+ public Class494(){
+
+ }
+}
+class Class495 {
+ public Class495(){
+
+ }
+}
+class Class496 {
+ public Class496(){
+
+ }
+}
+class Class497 {
+ public Class497(){
+
+ }
+}
+class Class498 {
+ public Class498(){
+
+ }
+}
+class Class499 {
+ public Class499(){
+
+ }
+}
+class Class500 {
+ public Class500(){
+
+ }
+}
+class Class501 {
+ public Class501(){
+
+ }
+}
+class Class502 {
+ public Class502(){
+
+ }
+}
+class Class503 {
+ public Class503(){
+
+ }
+}
+class Class504 {
+ public Class504(){
+
+ }
+}
+class Class505 {
+ public Class505(){
+
+ }
+}
+class Class506 {
+ public Class506(){
+
+ }
+}
+class Class507 {
+ public Class507(){
+
+ }
+}
+class Class508 {
+ public Class508(){
+
+ }
+}
+class Class509 {
+ public Class509(){
+
+ }
+}
+class Class510 {
+ public Class510(){
+
+ }
+}
+class Class511 {
+ public Class511(){
+
+ }
+}
+class Class512 {
+ public Class512(){
+
+ }
+}
+class Class513 {
+ public Class513(){
+
+ }
+}
+class Class514 {
+ public Class514(){
+
+ }
+}
+class Class515 {
+ public Class515(){
+
+ }
+}
+class Class516 {
+ public Class516(){
+
+ }
+}
+class Class517 {
+ public Class517(){
+
+ }
+}
+class Class518 {
+ public Class518(){
+
+ }
+}
+class Class519 {
+ public Class519(){
+
+ }
+}
+class Class520 {
+ public Class520(){
+
+ }
+}
+class Class521 {
+ public Class521(){
+
+ }
+}
+class Class522 {
+ public Class522(){
+
+ }
+}
+class Class523 {
+ public Class523(){
+
+ }
+}
+class Class524 {
+ public Class524(){
+
+ }
+}
+class Class525 {
+ public Class525(){
+
+ }
+}
+class Class526 {
+ public Class526(){
+
+ }
+}
+class Class527 {
+ public Class527(){
+
+ }
+}
+class Class528 {
+ public Class528(){
+
+ }
+}
+class Class529 {
+ public Class529(){
+
+ }
+}
+class Class530 {
+ public Class530(){
+
+ }
+}
+class Class531 {
+ public Class531(){
+
+ }
+}
+class Class532 {
+ public Class532(){
+
+ }
+}
+class Class533 {
+ public Class533(){
+
+ }
+}
+class Class534 {
+ public Class534(){
+
+ }
+}
+class Class535 {
+ public Class535(){
+
+ }
+}
+class Class536 {
+ public Class536(){
+
+ }
+}
+class Class537 {
+ public Class537(){
+
+ }
+}
+class Class538 {
+ public Class538(){
+
+ }
+}
+class Class539 {
+ public Class539(){
+
+ }
+}
+class Class540 {
+ public Class540(){
+
+ }
+}
+class Class541 {
+ public Class541(){
+
+ }
+}
+class Class542 {
+ public Class542(){
+
+ }
+}
+class Class543 {
+ public Class543(){
+
+ }
+}
+class Class544 {
+ public Class544(){
+
+ }
+}
+class Class545 {
+ public Class545(){
+
+ }
+}
+class Class546 {
+ public Class546(){
+
+ }
+}
+class Class547 {
+ public Class547(){
+
+ }
+}
+class Class548 {
+ public Class548(){
+
+ }
+}
+class Class549 {
+ public Class549(){
+
+ }
+}
+class Class550 {
+ public Class550(){
+
+ }
+}
+class Class551 {
+ public Class551(){
+
+ }
+}
+class Class552 {
+ public Class552(){
+
+ }
+}
+class Class553 {
+ public Class553(){
+
+ }
+}
+class Class554 {
+ public Class554(){
+
+ }
+}
+class Class555 {
+ public Class555(){
+
+ }
+}
+class Class556 {
+ public Class556(){
+
+ }
+}
+class Class557 {
+ public Class557(){
+
+ }
+}
+class Class558 {
+ public Class558(){
+
+ }
+}
+class Class559 {
+ public Class559(){
+
+ }
+}
+class Class560 {
+ public Class560(){
+
+ }
+}
+class Class561 {
+ public Class561(){
+
+ }
+}
+class Class562 {
+ public Class562(){
+
+ }
+}
+class Class563 {
+ public Class563(){
+
+ }
+}
+class Class564 {
+ public Class564(){
+
+ }
+}
+class Class565 {
+ public Class565(){
+
+ }
+}
+class Class566 {
+ public Class566(){
+
+ }
+}
+class Class567 {
+ public Class567(){
+
+ }
+}
+class Class568 {
+ public Class568(){
+
+ }
+}
+class Class569 {
+ public Class569(){
+
+ }
+}
+class Class570 {
+ public Class570(){
+
+ }
+}
+class Class571 {
+ public Class571(){
+
+ }
+}
+class Class572 {
+ public Class572(){
+
+ }
+}
+class Class573 {
+ public Class573(){
+
+ }
+}
+class Class574 {
+ public Class574(){
+
+ }
+}
+class Class575 {
+ public Class575(){
+
+ }
+}
+class Class576 {
+ public Class576(){
+
+ }
+}
+class Class577 {
+ public Class577(){
+
+ }
+}
+class Class578 {
+ public Class578(){
+
+ }
+}
+class Class579 {
+ public Class579(){
+
+ }
+}
+class Class580 {
+ public Class580(){
+
+ }
+}
+class Class581 {
+ public Class581(){
+
+ }
+}
+class Class582 {
+ public Class582(){
+
+ }
+}
+class Class583 {
+ public Class583(){
+
+ }
+}
+class Class584 {
+ public Class584(){
+
+ }
+}
+class Class585 {
+ public Class585(){
+
+ }
+}
+class Class586 {
+ public Class586(){
+
+ }
+}
+class Class587 {
+ public Class587(){
+
+ }
+}
+class Class588 {
+ public Class588(){
+
+ }
+}
+class Class589 {
+ public Class589(){
+
+ }
+}
+class Class590 {
+ public Class590(){
+
+ }
+}
+class Class591 {
+ public Class591(){
+
+ }
+}
+class Class592 {
+ public Class592(){
+
+ }
+}
+class Class593 {
+ public Class593(){
+
+ }
+}
+class Class594 {
+ public Class594(){
+
+ }
+}
+class Class595 {
+ public Class595(){
+
+ }
+}
+class Class596 {
+ public Class596(){
+
+ }
+}
+class Class597 {
+ public Class597(){
+
+ }
+}
+class Class598 {
+ public Class598(){
+
+ }
+}
+class Class599 {
+ public Class599(){
+
+ }
+}
+class Class600 {
+ public Class600(){
+
+ }
+}
+class Class601 {
+ public Class601(){
+
+ }
+}
+class Class602 {
+ public Class602(){
+
+ }
+}
+class Class603 {
+ public Class603(){
+
+ }
+}
+class Class604 {
+ public Class604(){
+
+ }
+}
+class Class605 {
+ public Class605(){
+
+ }
+}
+class Class606 {
+ public Class606(){
+
+ }
+}
+class Class607 {
+ public Class607(){
+
+ }
+}
+class Class608 {
+ public Class608(){
+
+ }
+}
+class Class609 {
+ public Class609(){
+
+ }
+}
+class Class610 {
+ public Class610(){
+
+ }
+}
+class Class611 {
+ public Class611(){
+
+ }
+}
+class Class612 {
+ public Class612(){
+
+ }
+}
+class Class613 {
+ public Class613(){
+
+ }
+}
+class Class614 {
+ public Class614(){
+
+ }
+}
+class Class615 {
+ public Class615(){
+
+ }
+}
+class Class616 {
+ public Class616(){
+
+ }
+}
+class Class617 {
+ public Class617(){
+
+ }
+}
+class Class618 {
+ public Class618(){
+
+ }
+}
+class Class619 {
+ public Class619(){
+
+ }
+}
+class Class620 {
+ public Class620(){
+
+ }
+}
+class Class621 {
+ public Class621(){
+
+ }
+}
+class Class622 {
+ public Class622(){
+
+ }
+}
+class Class623 {
+ public Class623(){
+
+ }
+}
+class Class624 {
+ public Class624(){
+
+ }
+}
+class Class625 {
+ public Class625(){
+
+ }
+}
+class Class626 {
+ public Class626(){
+
+ }
+}
+class Class627 {
+ public Class627(){
+
+ }
+}
+class Class628 {
+ public Class628(){
+
+ }
+}
+class Class629 {
+ public Class629(){
+
+ }
+}
+class Class630 {
+ public Class630(){
+
+ }
+}
+class Class631 {
+ public Class631(){
+
+ }
+}
+class Class632 {
+ public Class632(){
+
+ }
+}
+class Class633 {
+ public Class633(){
+
+ }
+}
+class Class634 {
+ public Class634(){
+
+ }
+}
+class Class635 {
+ public Class635(){
+
+ }
+}
+class Class636 {
+ public Class636(){
+
+ }
+}
+class Class637 {
+ public Class637(){
+
+ }
+}
+class Class638 {
+ public Class638(){
+
+ }
+}
+class Class639 {
+ public Class639(){
+
+ }
+}
+class Class640 {
+ public Class640(){
+
+ }
+}
+class Class641 {
+ public Class641(){
+
+ }
+}
+class Class642 {
+ public Class642(){
+
+ }
+}
+class Class643 {
+ public Class643(){
+
+ }
+}
+class Class644 {
+ public Class644(){
+
+ }
+}
+class Class645 {
+ public Class645(){
+
+ }
+}
+class Class646 {
+ public Class646(){
+
+ }
+}
+class Class647 {
+ public Class647(){
+
+ }
+}
+class Class648 {
+ public Class648(){
+
+ }
+}
+class Class649 {
+ public Class649(){
+
+ }
+}
+class Class650 {
+ public Class650(){
+
+ }
+}
+class Class651 {
+ public Class651(){
+
+ }
+}
+class Class652 {
+ public Class652(){
+
+ }
+}
+class Class653 {
+ public Class653(){
+
+ }
+}
+class Class654 {
+ public Class654(){
+
+ }
+}
+class Class655 {
+ public Class655(){
+
+ }
+}
+class Class656 {
+ public Class656(){
+
+ }
+}
+class Class657 {
+ public Class657(){
+
+ }
+}
+class Class658 {
+ public Class658(){
+
+ }
+}
+class Class659 {
+ public Class659(){
+
+ }
+}
+class Class660 {
+ public Class660(){
+
+ }
+}
+class Class661 {
+ public Class661(){
+
+ }
+}
+class Class662 {
+ public Class662(){
+
+ }
+}
+class Class663 {
+ public Class663(){
+
+ }
+}
+class Class664 {
+ public Class664(){
+
+ }
+}
+class Class665 {
+ public Class665(){
+
+ }
+}
+class Class666 {
+ public Class666(){
+
+ }
+}
+class Class667 {
+ public Class667(){
+
+ }
+}
+class Class668 {
+ public Class668(){
+
+ }
+}
+class Class669 {
+ public Class669(){
+
+ }
+}
+class Class670 {
+ public Class670(){
+
+ }
+}
+class Class671 {
+ public Class671(){
+
+ }
+}
+class Class672 {
+ public Class672(){
+
+ }
+}
+class Class673 {
+ public Class673(){
+
+ }
+}
+class Class674 {
+ public Class674(){
+
+ }
+}
+class Class675 {
+ public Class675(){
+
+ }
+}
+class Class676 {
+ public Class676(){
+
+ }
+}
+class Class677 {
+ public Class677(){
+
+ }
+}
+class Class678 {
+ public Class678(){
+
+ }
+}
+class Class679 {
+ public Class679(){
+
+ }
+}
+class Class680 {
+ public Class680(){
+
+ }
+}
+class Class681 {
+ public Class681(){
+
+ }
+}
+class Class682 {
+ public Class682(){
+
+ }
+}
+class Class683 {
+ public Class683(){
+
+ }
+}
+class Class684 {
+ public Class684(){
+
+ }
+}
+class Class685 {
+ public Class685(){
+
+ }
+}
+class Class686 {
+ public Class686(){
+
+ }
+}
+class Class687 {
+ public Class687(){
+
+ }
+}
+class Class688 {
+ public Class688(){
+
+ }
+}
+class Class689 {
+ public Class689(){
+
+ }
+}
+class Class690 {
+ public Class690(){
+
+ }
+}
+class Class691 {
+ public Class691(){
+
+ }
+}
+class Class692 {
+ public Class692(){
+
+ }
+}
+class Class693 {
+ public Class693(){
+
+ }
+}
+class Class694 {
+ public Class694(){
+
+ }
+}
+class Class695 {
+ public Class695(){
+
+ }
+}
+class Class696 {
+ public Class696(){
+
+ }
+}
+class Class697 {
+ public Class697(){
+
+ }
+}
+class Class698 {
+ public Class698(){
+
+ }
+}
+class Class699 {
+ public Class699(){
+
+ }
+}
+class Class700 {
+ public Class700(){
+
+ }
+}
+class Class701 {
+ public Class701(){
+
+ }
+}
+class Class702 {
+ public Class702(){
+
+ }
+}
+class Class703 {
+ public Class703(){
+
+ }
+}
+class Class704 {
+ public Class704(){
+
+ }
+}
+class Class705 {
+ public Class705(){
+
+ }
+}
+class Class706 {
+ public Class706(){
+
+ }
+}
+class Class707 {
+ public Class707(){
+
+ }
+}
+class Class708 {
+ public Class708(){
+
+ }
+}
+class Class709 {
+ public Class709(){
+
+ }
+}
+class Class710 {
+ public Class710(){
+
+ }
+}
+class Class711 {
+ public Class711(){
+
+ }
+}
+class Class712 {
+ public Class712(){
+
+ }
+}
+class Class713 {
+ public Class713(){
+
+ }
+}
+class Class714 {
+ public Class714(){
+
+ }
+}
+class Class715 {
+ public Class715(){
+
+ }
+}
+class Class716 {
+ public Class716(){
+
+ }
+}
+class Class717 {
+ public Class717(){
+
+ }
+}
+class Class718 {
+ public Class718(){
+
+ }
+}
+class Class719 {
+ public Class719(){
+
+ }
+}
+class Class720 {
+ public Class720(){
+
+ }
+}
+class Class721 {
+ public Class721(){
+
+ }
+}
+class Class722 {
+ public Class722(){
+
+ }
+}
+class Class723 {
+ public Class723(){
+
+ }
+}
+class Class724 {
+ public Class724(){
+
+ }
+}
+class Class725 {
+ public Class725(){
+
+ }
+}
+class Class726 {
+ public Class726(){
+
+ }
+}
+class Class727 {
+ public Class727(){
+
+ }
+}
+class Class728 {
+ public Class728(){
+
+ }
+}
+class Class729 {
+ public Class729(){
+
+ }
+}
+class Class730 {
+ public Class730(){
+
+ }
+}
+class Class731 {
+ public Class731(){
+
+ }
+}
+class Class732 {
+ public Class732(){
+
+ }
+}
+class Class733 {
+ public Class733(){
+
+ }
+}
+class Class734 {
+ public Class734(){
+
+ }
+}
+class Class735 {
+ public Class735(){
+
+ }
+}
+class Class736 {
+ public Class736(){
+
+ }
+}
+class Class737 {
+ public Class737(){
+
+ }
+}
+class Class738 {
+ public Class738(){
+
+ }
+}
+class Class739 {
+ public Class739(){
+
+ }
+}
+class Class740 {
+ public Class740(){
+
+ }
+}
+class Class741 {
+ public Class741(){
+
+ }
+}
+class Class742 {
+ public Class742(){
+
+ }
+}
+class Class743 {
+ public Class743(){
+
+ }
+}
+class Class744 {
+ public Class744(){
+
+ }
+}
+class Class745 {
+ public Class745(){
+
+ }
+}
+class Class746 {
+ public Class746(){
+
+ }
+}
+class Class747 {
+ public Class747(){
+
+ }
+}
+class Class748 {
+ public Class748(){
+
+ }
+}
+class Class749 {
+ public Class749(){
+
+ }
+}
+class Class750 {
+ public Class750(){
+
+ }
+}
+class Class751 {
+ public Class751(){
+
+ }
+}
+class Class752 {
+ public Class752(){
+
+ }
+}
+class Class753 {
+ public Class753(){
+
+ }
+}
+class Class754 {
+ public Class754(){
+
+ }
+}
+class Class755 {
+ public Class755(){
+
+ }
+}
+class Class756 {
+ public Class756(){
+
+ }
+}
+class Class757 {
+ public Class757(){
+
+ }
+}
+class Class758 {
+ public Class758(){
+
+ }
+}
+class Class759 {
+ public Class759(){
+
+ }
+}
+class Class760 {
+ public Class760(){
+
+ }
+}
+class Class761 {
+ public Class761(){
+
+ }
+}
+class Class762 {
+ public Class762(){
+
+ }
+}
+class Class763 {
+ public Class763(){
+
+ }
+}
+class Class764 {
+ public Class764(){
+
+ }
+}
+class Class765 {
+ public Class765(){
+
+ }
+}
+class Class766 {
+ public Class766(){
+
+ }
+}
+class Class767 {
+ public Class767(){
+
+ }
+}
+class Class768 {
+ public Class768(){
+
+ }
+}
+class Class769 {
+ public Class769(){
+
+ }
+}
+class Class770 {
+ public Class770(){
+
+ }
+}
+class Class771 {
+ public Class771(){
+
+ }
+}
+class Class772 {
+ public Class772(){
+
+ }
+}
+class Class773 {
+ public Class773(){
+
+ }
+}
+class Class774 {
+ public Class774(){
+
+ }
+}
+class Class775 {
+ public Class775(){
+
+ }
+}
+class Class776 {
+ public Class776(){
+
+ }
+}
+class Class777 {
+ public Class777(){
+
+ }
+}
+class Class778 {
+ public Class778(){
+
+ }
+}
+class Class779 {
+ public Class779(){
+
+ }
+}
+class Class780 {
+ public Class780(){
+
+ }
+}
+class Class781 {
+ public Class781(){
+
+ }
+}
+class Class782 {
+ public Class782(){
+
+ }
+}
+class Class783 {
+ public Class783(){
+
+ }
+}
+class Class784 {
+ public Class784(){
+
+ }
+}
+class Class785 {
+ public Class785(){
+
+ }
+}
+class Class786 {
+ public Class786(){
+
+ }
+}
+class Class787 {
+ public Class787(){
+
+ }
+}
+class Class788 {
+ public Class788(){
+
+ }
+}
+class Class789 {
+ public Class789(){
+
+ }
+}
+class Class790 {
+ public Class790(){
+
+ }
+}
+class Class791 {
+ public Class791(){
+
+ }
+}
+class Class792 {
+ public Class792(){
+
+ }
+}
+class Class793 {
+ public Class793(){
+
+ }
+}
+class Class794 {
+ public Class794(){
+
+ }
+}
+class Class795 {
+ public Class795(){
+
+ }
+}
+class Class796 {
+ public Class796(){
+
+ }
+}
+class Class797 {
+ public Class797(){
+
+ }
+}
+class Class798 {
+ public Class798(){
+
+ }
+}
+class Class799 {
+ public Class799(){
+
+ }
+}
+class Class800 {
+ public Class800(){
+
+ }
+}
+class Class801 {
+ public Class801(){
+
+ }
+}
+class Class802 {
+ public Class802(){
+
+ }
+}
+class Class803 {
+ public Class803(){
+
+ }
+}
+class Class804 {
+ public Class804(){
+
+ }
+}
+class Class805 {
+ public Class805(){
+
+ }
+}
+class Class806 {
+ public Class806(){
+
+ }
+}
+class Class807 {
+ public Class807(){
+
+ }
+}
+class Class808 {
+ public Class808(){
+
+ }
+}
+class Class809 {
+ public Class809(){
+
+ }
+}
+class Class810 {
+ public Class810(){
+
+ }
+}
+class Class811 {
+ public Class811(){
+
+ }
+}
+class Class812 {
+ public Class812(){
+
+ }
+}
+class Class813 {
+ public Class813(){
+
+ }
+}
+class Class814 {
+ public Class814(){
+
+ }
+}
+class Class815 {
+ public Class815(){
+
+ }
+}
+class Class816 {
+ public Class816(){
+
+ }
+}
+class Class817 {
+ public Class817(){
+
+ }
+}
+class Class818 {
+ public Class818(){
+
+ }
+}
+class Class819 {
+ public Class819(){
+
+ }
+}
+class Class820 {
+ public Class820(){
+
+ }
+}
+class Class821 {
+ public Class821(){
+
+ }
+}
+class Class822 {
+ public Class822(){
+
+ }
+}
+class Class823 {
+ public Class823(){
+
+ }
+}
+class Class824 {
+ public Class824(){
+
+ }
+}
+class Class825 {
+ public Class825(){
+
+ }
+}
+class Class826 {
+ public Class826(){
+
+ }
+}
+class Class827 {
+ public Class827(){
+
+ }
+}
+class Class828 {
+ public Class828(){
+
+ }
+}
+class Class829 {
+ public Class829(){
+
+ }
+}
+class Class830 {
+ public Class830(){
+
+ }
+}
+class Class831 {
+ public Class831(){
+
+ }
+}
+class Class832 {
+ public Class832(){
+
+ }
+}
+class Class833 {
+ public Class833(){
+
+ }
+}
+class Class834 {
+ public Class834(){
+
+ }
+}
+class Class835 {
+ public Class835(){
+
+ }
+}
+class Class836 {
+ public Class836(){
+
+ }
+}
+class Class837 {
+ public Class837(){
+
+ }
+}
+class Class838 {
+ public Class838(){
+
+ }
+}
+class Class839 {
+ public Class839(){
+
+ }
+}
+class Class840 {
+ public Class840(){
+
+ }
+}
+class Class841 {
+ public Class841(){
+
+ }
+}
+class Class842 {
+ public Class842(){
+
+ }
+}
+class Class843 {
+ public Class843(){
+
+ }
+}
+class Class844 {
+ public Class844(){
+
+ }
+}
+class Class845 {
+ public Class845(){
+
+ }
+}
+class Class846 {
+ public Class846(){
+
+ }
+}
+class Class847 {
+ public Class847(){
+
+ }
+}
+class Class848 {
+ public Class848(){
+
+ }
+}
+class Class849 {
+ public Class849(){
+
+ }
+}
+class Class850 {
+ public Class850(){
+
+ }
+}
+class Class851 {
+ public Class851(){
+
+ }
+}
+class Class852 {
+ public Class852(){
+
+ }
+}
+class Class853 {
+ public Class853(){
+
+ }
+}
+class Class854 {
+ public Class854(){
+
+ }
+}
+class Class855 {
+ public Class855(){
+
+ }
+}
+class Class856 {
+ public Class856(){
+
+ }
+}
+class Class857 {
+ public Class857(){
+
+ }
+}
+class Class858 {
+ public Class858(){
+
+ }
+}
+class Class859 {
+ public Class859(){
+
+ }
+}
+class Class860 {
+ public Class860(){
+
+ }
+}
+class Class861 {
+ public Class861(){
+
+ }
+}
+class Class862 {
+ public Class862(){
+
+ }
+}
+class Class863 {
+ public Class863(){
+
+ }
+}
+class Class864 {
+ public Class864(){
+
+ }
+}
+class Class865 {
+ public Class865(){
+
+ }
+}
+class Class866 {
+ public Class866(){
+
+ }
+}
+class Class867 {
+ public Class867(){
+
+ }
+}
+class Class868 {
+ public Class868(){
+
+ }
+}
+class Class869 {
+ public Class869(){
+
+ }
+}
+class Class870 {
+ public Class870(){
+
+ }
+}
+class Class871 {
+ public Class871(){
+
+ }
+}
+class Class872 {
+ public Class872(){
+
+ }
+}
+class Class873 {
+ public Class873(){
+
+ }
+}
+class Class874 {
+ public Class874(){
+
+ }
+}
+class Class875 {
+ public Class875(){
+
+ }
+}
+class Class876 {
+ public Class876(){
+
+ }
+}
+class Class877 {
+ public Class877(){
+
+ }
+}
+class Class878 {
+ public Class878(){
+
+ }
+}
+class Class879 {
+ public Class879(){
+
+ }
+}
+class Class880 {
+ public Class880(){
+
+ }
+}
+class Class881 {
+ public Class881(){
+
+ }
+}
+class Class882 {
+ public Class882(){
+
+ }
+}
+class Class883 {
+ public Class883(){
+
+ }
+}
+class Class884 {
+ public Class884(){
+
+ }
+}
+class Class885 {
+ public Class885(){
+
+ }
+}
+class Class886 {
+ public Class886(){
+
+ }
+}
+class Class887 {
+ public Class887(){
+
+ }
+}
+class Class888 {
+ public Class888(){
+
+ }
+}
+class Class889 {
+ public Class889(){
+
+ }
+}
+class Class890 {
+ public Class890(){
+
+ }
+}
+class Class891 {
+ public Class891(){
+
+ }
+}
+class Class892 {
+ public Class892(){
+
+ }
+}
+class Class893 {
+ public Class893(){
+
+ }
+}
+class Class894 {
+ public Class894(){
+
+ }
+}
+class Class895 {
+ public Class895(){
+
+ }
+}
+class Class896 {
+ public Class896(){
+
+ }
+}
+class Class897 {
+ public Class897(){
+
+ }
+}
+class Class898 {
+ public Class898(){
+
+ }
+}
+class Class899 {
+ public Class899(){
+
+ }
+}
+class Class900 {
+ public Class900(){
+
+ }
+}
+class Class901 {
+ public Class901(){
+
+ }
+}
+class Class902 {
+ public Class902(){
+
+ }
+}
+class Class903 {
+ public Class903(){
+
+ }
+}
+class Class904 {
+ public Class904(){
+
+ }
+}
+class Class905 {
+ public Class905(){
+
+ }
+}
+class Class906 {
+ public Class906(){
+
+ }
+}
+class Class907 {
+ public Class907(){
+
+ }
+}
+class Class908 {
+ public Class908(){
+
+ }
+}
+class Class909 {
+ public Class909(){
+
+ }
+}
+class Class910 {
+ public Class910(){
+
+ }
+}
+class Class911 {
+ public Class911(){
+
+ }
+}
+class Class912 {
+ public Class912(){
+
+ }
+}
+class Class913 {
+ public Class913(){
+
+ }
+}
+class Class914 {
+ public Class914(){
+
+ }
+}
+class Class915 {
+ public Class915(){
+
+ }
+}
+class Class916 {
+ public Class916(){
+
+ }
+}
+class Class917 {
+ public Class917(){
+
+ }
+}
+class Class918 {
+ public Class918(){
+
+ }
+}
+class Class919 {
+ public Class919(){
+
+ }
+}
+class Class920 {
+ public Class920(){
+
+ }
+}
+class Class921 {
+ public Class921(){
+
+ }
+}
+class Class922 {
+ public Class922(){
+
+ }
+}
+class Class923 {
+ public Class923(){
+
+ }
+}
+class Class924 {
+ public Class924(){
+
+ }
+}
+class Class925 {
+ public Class925(){
+
+ }
+}
+class Class926 {
+ public Class926(){
+
+ }
+}
+class Class927 {
+ public Class927(){
+
+ }
+}
+class Class928 {
+ public Class928(){
+
+ }
+}
+class Class929 {
+ public Class929(){
+
+ }
+}
+class Class930 {
+ public Class930(){
+
+ }
+}
+class Class931 {
+ public Class931(){
+
+ }
+}
+class Class932 {
+ public Class932(){
+
+ }
+}
+class Class933 {
+ public Class933(){
+
+ }
+}
+class Class934 {
+ public Class934(){
+
+ }
+}
+class Class935 {
+ public Class935(){
+
+ }
+}
+class Class936 {
+ public Class936(){
+
+ }
+}
+class Class937 {
+ public Class937(){
+
+ }
+}
+class Class938 {
+ public Class938(){
+
+ }
+}
+class Class939 {
+ public Class939(){
+
+ }
+}
+class Class940 {
+ public Class940(){
+
+ }
+}
+class Class941 {
+ public Class941(){
+
+ }
+}
+class Class942 {
+ public Class942(){
+
+ }
+}
+class Class943 {
+ public Class943(){
+
+ }
+}
+class Class944 {
+ public Class944(){
+
+ }
+}
+class Class945 {
+ public Class945(){
+
+ }
+}
+class Class946 {
+ public Class946(){
+
+ }
+}
+class Class947 {
+ public Class947(){
+
+ }
+}
+class Class948 {
+ public Class948(){
+
+ }
+}
+class Class949 {
+ public Class949(){
+
+ }
+}
+class Class950 {
+ public Class950(){
+
+ }
+}
+class Class951 {
+ public Class951(){
+
+ }
+}
+class Class952 {
+ public Class952(){
+
+ }
+}
+class Class953 {
+ public Class953(){
+
+ }
+}
+class Class954 {
+ public Class954(){
+
+ }
+}
+class Class955 {
+ public Class955(){
+
+ }
+}
+class Class956 {
+ public Class956(){
+
+ }
+}
+class Class957 {
+ public Class957(){
+
+ }
+}
+class Class958 {
+ public Class958(){
+
+ }
+}
+class Class959 {
+ public Class959(){
+
+ }
+}
+class Class960 {
+ public Class960(){
+
+ }
+}
+class Class961 {
+ public Class961(){
+
+ }
+}
+class Class962 {
+ public Class962(){
+
+ }
+}
+class Class963 {
+ public Class963(){
+
+ }
+}
+class Class964 {
+ public Class964(){
+
+ }
+}
+class Class965 {
+ public Class965(){
+
+ }
+}
+class Class966 {
+ public Class966(){
+
+ }
+}
+class Class967 {
+ public Class967(){
+
+ }
+}
+class Class968 {
+ public Class968(){
+
+ }
+}
+class Class969 {
+ public Class969(){
+
+ }
+}
+class Class970 {
+ public Class970(){
+
+ }
+}
+class Class971 {
+ public Class971(){
+
+ }
+}
+class Class972 {
+ public Class972(){
+
+ }
+}
+class Class973 {
+ public Class973(){
+
+ }
+}
+class Class974 {
+ public Class974(){
+
+ }
+}
+class Class975 {
+ public Class975(){
+
+ }
+}
+class Class976 {
+ public Class976(){
+
+ }
+}
+class Class977 {
+ public Class977(){
+
+ }
+}
+class Class978 {
+ public Class978(){
+
+ }
+}
+class Class979 {
+ public Class979(){
+
+ }
+}
+class Class980 {
+ public Class980(){
+
+ }
+}
+class Class981 {
+ public Class981(){
+
+ }
+}
+class Class982 {
+ public Class982(){
+
+ }
+}
+class Class983 {
+ public Class983(){
+
+ }
+}
+class Class984 {
+ public Class984(){
+
+ }
+}
+class Class985 {
+ public Class985(){
+
+ }
+}
+class Class986 {
+ public Class986(){
+
+ }
+}
+class Class987 {
+ public Class987(){
+
+ }
+}
+class Class988 {
+ public Class988(){
+
+ }
+}
+class Class989 {
+ public Class989(){
+
+ }
+}
+class Class990 {
+ public Class990(){
+
+ }
+}
+class Class991 {
+ public Class991(){
+
+ }
+}
+class Class992 {
+ public Class992(){
+
+ }
+}
+class Class993 {
+ public Class993(){
+
+ }
+}
+class Class994 {
+ public Class994(){
+
+ }
+}
+class Class995 {
+ public Class995(){
+
+ }
+}
+class Class996 {
+ public Class996(){
+
+ }
+}
+class Class997 {
+ public Class997(){
+
+ }
+}
+class Class998 {
+ public Class998(){
+
+ }
+}
+class Class999 {
+ public Class999(){
+
+ }
+}
+class Class1000 {
+ public Class1000(){
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Garbage producer that uses another garbage producer
+ * to implement it's functionality.
+ */
+public abstract class DerivedProducer<T, P> implements GarbageProducer<T> {
+ private GarbageProducer<P> parent;
+
+ public DerivedProducer(GarbageProducer<P> parent) {
+ setParent(parent);
+ }
+
+ protected P createParent(long memory) {
+ return parent.create(memory);
+ }
+
+ protected void validateParent(P obj) {
+ parent.validate(obj);
+ }
+
+ public final GarbageProducer<P> getParent() {
+ return parent;
+ }
+
+ public final void setParent(GarbageProducer<P> parent) {
+ this.parent = parent;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/DerivedStrategyProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Derived garbage producer that uses a memory strategy.
+ */
+public abstract class DerivedStrategyProducer<T, P> extends DerivedProducer<T, P> {
+ protected MemoryStrategy memoryStrategy;
+
+ public DerivedStrategyProducer(GarbageProducer<P> parent, MemoryStrategy memoryStrategy) {
+ super(parent);
+ }
+
+ public final void setMemoryStrategy(MemoryStrategy memoryStrategy) {
+ this.memoryStrategy = memoryStrategy;
+ }
+
+ public final MemoryStrategy getMemoryStrategy() {
+ return memoryStrategy;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Interface that defines a way to produce garbage.
+ */
+public interface GarbageProducer<T> {
+ /**
+ * Produce garbage of given size.
+ *
+ * @param memory size in bytes
+ * @return produced garbage
+ */
+ public T create(long memory);
+
+ /**
+ * Validate earlier produced object.
+ *
+ * @param obj earlier produced garbage
+ * @throws TestFailure if validation fails
+ */
+ public void validate(T obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducer1Aware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Marker interface for getting GarbageProducer.
+ */
+public interface GarbageProducer1Aware {
+ public void setGarbageProducer1(GarbageProducer gp);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducerAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Marker interface for getting GarbageProducer.
+ */
+public interface GarbageProducerAware {
+ public void setGarbageProducer(GarbageProducer gp);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageProducers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+import java.util.List;
+import java.util.ArrayList;
+import nsk.share.gc.gp.array.*;
+import nsk.share.gc.gp.string.*;
+
+/**
+ * Factory for garbage producers
+ */
+public class GarbageProducers {
+ private List<GarbageProducer> primitiveArrayProducers;
+ private List<GarbageProducer> arrayProducers;
+ private List<GarbageProducer<String>> stringProducers;
+ private List<GarbageProducer> allProducers;
+
+ /**
+ * Get all primitive array producers.
+ */
+ public List<GarbageProducer> getPrimitiveArrayProducers() {
+ if (primitiveArrayProducers == null) {
+ primitiveArrayProducers = new ArrayList<GarbageProducer>();
+ primitiveArrayProducers.add(new ByteArrayProducer());
+ primitiveArrayProducers.add(new BooleanArrayProducer());
+ primitiveArrayProducers.add(new ShortArrayProducer());
+ primitiveArrayProducers.add(new CharArrayProducer());
+ primitiveArrayProducers.add(new IntArrayProducer());
+ primitiveArrayProducers.add(new LongArrayProducer());
+ primitiveArrayProducers.add(new FloatArrayProducer());
+ primitiveArrayProducers.add(new DoubleArrayProducer());
+ }
+ return primitiveArrayProducers;
+ }
+
+ /**
+ * Get all array producers.
+ */
+ public List<GarbageProducer> getArrayProducers() {
+ if (arrayProducers == null) {
+ arrayProducers = new ArrayList<GarbageProducer>();
+ arrayProducers.addAll(getPrimitiveArrayProducers());
+ arrayProducers.add(new ObjectArrayProducer());
+ }
+ return arrayProducers;
+ }
+
+ /**
+ * Get all string producers.
+ */
+ public List<GarbageProducer<String>> getStringProducers() {
+ if (stringProducers == null) {
+ stringProducers = new ArrayList<GarbageProducer<String>>();
+ stringProducers.add(new RandomStringProducer());
+ stringProducers.add(new InternedStringProducer());
+ }
+ return stringProducers;
+ }
+
+ public List<GarbageProducer> getAllProducers() {
+ if (allProducers == null) {
+ allProducers = new ArrayList<GarbageProducer>();
+ allProducers.addAll(getArrayProducers());
+ allProducers.addAll(getStringProducers());
+ }
+ return allProducers;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.*;
+import nsk.share.gc.gp.array.*;
+import nsk.share.gc.gp.string.*;
+import nsk.share.gc.gp.list.*;
+import nsk.share.gc.gp.tree.*;
+import nsk.share.gc.gp.misc.*;
+import nsk.share.gc.gp.classload.*;
+import nsk.share.gc.Memory;
+import nsk.share.TestBug;
+import nsk.share.test.*;
+
+/**
+ * Utility methods for garbage producers.
+ */
+public final class GarbageUtils {
+ private static final int ALLOCATION_LIMIT = 50000000; //50 Mb
+ private static GarbageProducers garbageProducers;
+ private static List<GarbageProducer> primitiveArrayProducers;
+ private static List<GarbageProducer> arrayProducers;
+ private static final GarbageProducer byteArrayProducer = new ByteArrayProducer();
+ public static enum OOM_TYPE {
+ ANY (),
+ HEAP("Java heap space"),
+ METASPACE("Metaspace", "Compressed class space");
+
+ private final String[] expectedStrings;
+ OOM_TYPE(String... expectedStrings) {
+ this.expectedStrings = expectedStrings;
+ }
+
+ /**
+ * Returns true if the given error message matches
+ * one of expected strings.
+ */
+ public boolean accept(String errorMessage) {
+ if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) {
+ return true;
+ }
+ for (String s: expectedStrings) {
+ if (errorMessage.indexOf(s) != -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ // Force loading of OOM_TYPE and calling of enum contrusctors when loading GarbageUtils class.
+ public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE };
+
+ // Force early loading of classes that might otherwise unexpectedly fail
+ // class loading during testing due to high memory pressure.
+ public static final StringWriter preloadStringWriter = new StringWriter(1);
+ public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter);
+
+ private GarbageUtils() {
+ }
+
+ /**
+ * Eat memory using execution controller that waits for 2 minutes.
+ * @return number of OOME occured
+ */
+ public static int eatMemory() {
+ return eatMemory(2 * 60 * 1000);
+ }
+
+ /**
+ * Eat memory using execution controller that waits for timeout.
+ * @return number of OOME occured
+ */
+ public static int eatMemory(final long timeout) {
+ return eatMemory(new ExecutionController() {
+ final long initialTime = System.currentTimeMillis();
+
+ @Override
+ public void start(long stdIterations) {}
+
+ @Override
+ public boolean iteration() {return false;}
+
+ @Override
+ public boolean continueExecution() {
+ return System.currentTimeMillis() - initialTime < timeout;
+ }
+
+ @Override
+ public long getIteration() {return 0;}
+
+ @Override
+ public void finish() {}
+ });
+ }
+
+
+ /**
+ * Eat memory using given execution controller and garbage producer.
+ *
+ * @param stresser execution controller
+ * @param gp garbage producer
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser) {
+ return eatMemory(stresser, byteArrayProducer, 50, 100, 2, OOM_TYPE.ANY);
+ }
+
+ /**
+ * Eat memory using given execution controller and garbage producer.
+ *
+ * @param stresser execution controller
+ * @param gp garbage producer
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser, GarbageProducer gp) {
+ return eatMemory(stresser, gp, 50, 100, 2, OOM_TYPE.ANY);
+ }
+
+ /**
+ * Eat memory using given garbage producer and given factor.
+ *
+ * @param gp garbage producer
+ * @param factor factor to divide the array size by
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long factor) {
+ return eatMemory(stresser, gp, 50, 100, factor, OOM_TYPE.ANY);
+ }
+
+ /**
+ * Eat memory using default(byte[]) garbage producer.
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * @param stresser stresser
+ * @param initialFactor determines which portion of initial memory initial chunk will be
+ * @param minMemoryChunk determines when to stop
+ * @param factor factor to divide the array size by
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser,long initialFactor, long minMemoryChunk, long factor) {
+ return eatMemory(stresser, byteArrayProducer, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);
+ }
+
+ /**
+ * Eat memory using given garbage producer.
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * @param stresser stresser to use
+ * @param gp garbage producer
+ * @param initialFactor determines which portion of initial memory initial chunk will be
+ * @param minMemoryChunk determines when to stop
+ * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME
+ * @param type of OutOfMemory Exception: Java heap space or Metadata space
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) {
+ return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);
+ }
+
+ /**
+ * Eat memory using given garbage producer.
+ *
+ * Note that this method can throw Failure if any exception
+ * is thrown while eating memory. To avoid OOM while allocating
+ * exception we preallocate it before the lunch starts. It means
+ * that exception stack trace does not correspond to the place
+ * where exception is thrown, but points at start of the method.
+ *
+ * @param stresser stresser to use
+ * @param gp garbage producer
+ * @param initialFactor determines which portion of initial memory initial chunk will be
+ * @param minMemoryChunk determines when to stop
+ * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME
+ * @param type of OutOfMemory Exception: Java heap space or Metadata space
+ * @return number of OOME occured
+ */
+ public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) {
+ int numberOfOOMEs = 0;
+ try {
+ StringWriter sw = new StringWriter(10000);
+ PrintWriter pw = new PrintWriter(sw);
+ byte[] someMemory = new byte[200000]; //200 Kb
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ long maxMemory = runtime.maxMemory();
+ long maxMemoryChunk = maxMemory / initialFactor;
+ long chunk = maxMemoryChunk;
+ chunk = chunk > ALLOCATION_LIMIT ? ALLOCATION_LIMIT : chunk;
+ int allocations = 0;
+ List<Object> storage = new ArrayList<Object>();
+
+ while (chunk > minMemoryChunk && stresser.continueExecution()) {
+ try {
+ storage.add(gp.create(chunk));
+ if (Thread.currentThread().isInterrupted()) {
+ return numberOfOOMEs;
+ }
+ // if we are able to eat chunk*factor let
+ // try to increase size of chunk
+ if (chunk * factor < maxMemoryChunk
+ && factor != 0 && allocations++ == factor + 1) {
+ chunk = chunk * factor;
+ allocations = 0;
+ }
+ } catch (OutOfMemoryError e) {
+ someMemory = null;
+ if (type != OOM_TYPE.ANY) {
+ e.printStackTrace(pw);
+ pw.close();
+ if (type.accept(sw.toString())) {
+ numberOfOOMEs++;
+ } else {
+ // Trying to catch situation when Java generates OOM different type that test trying to catch
+ throw new TestBug("Test throw OOM of unexpected type." + sw.toString());
+ }
+ } else {
+ numberOfOOMEs++;
+ }
+ allocations = 0;
+ if (factor == 0) {
+ return numberOfOOMEs;
+ } else {
+ chunk = chunk / factor;
+ }
+ }
+ }
+ } catch (OutOfMemoryError e) {
+ someMemory = null;
+ if (type != OOM_TYPE.ANY) {
+ e.printStackTrace(pw);
+ pw.close();
+ if (type.accept(sw.toString())) {
+ numberOfOOMEs++;
+ } else {
+ // Trying to catch situation when Java generates OOM different type that test trying to catch
+ throw new TestBug("Test throw OOM of unexpected type." + sw.toString());
+ }
+ } else {
+ numberOfOOMEs++;
+ }
+ // all memory is eaten now even before we start, just return
+ }
+ } catch (OutOfMemoryError e) {
+ numberOfOOMEs++;
+ }
+ return numberOfOOMEs;
+ }
+
+ /**
+ * Get all primitive array producers.
+ */
+ public static List<GarbageProducer> getPrimitiveArrayProducers() {
+ return getGarbageProducers().getPrimitiveArrayProducers();
+ }
+
+ /**
+ * Get all array producers.
+ */
+ public static List<GarbageProducer> getArrayProducers() {
+ return getGarbageProducers().getArrayProducers();
+ }
+
+ /**
+ * Determine size of each object in array which will occupy given
+ * memory with distribution determined by given memory strategy.
+ */
+ public static long getArraySize(long memory, MemoryStrategy memoryStrategy) {
+ return memoryStrategy.getSize(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());
+ }
+
+ /**
+ * Determine object count in array which will occupy given
+ * memory with distribution determined by given memory strategy.
+ */
+ public static int getArrayCount(long memory, MemoryStrategy memoryStrategy) {
+ return memoryStrategy.getCount(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());
+ }
+
+ /**
+ * Get garbage producer by identifier.
+ *
+ * @param id identifier
+ * @return garbage producer for this identifier
+ */
+ public static GarbageProducer getGarbageProducer(String id) {
+ if (id == null || id.equals("byteArr"))
+ return new ByteArrayProducer();
+ else if (id.equals("booleanArr"))
+ return new BooleanArrayProducer();
+ else if (id.equals("shortArr"))
+ return new ShortArrayProducer();
+ else if (id.equals("charArr"))
+ return new CharArrayProducer();
+ else if (id.equals("intArr"))
+ return new IntArrayProducer();
+ else if (id.equals("longArr"))
+ return new LongArrayProducer();
+ else if (id.equals("floatArr"))
+ return new FloatArrayProducer();
+ else if (id.equals("doubleArr"))
+ return new DoubleArrayProducer();
+ else if (id.equals("objectArr"))
+ return new ObjectArrayProducer();
+ else if (id.equals("randomString"))
+ return new RandomStringProducer();
+ else if (id.equals("simpleString"))
+ return new SimpleStringProducer();
+ else if (id.startsWith("interned("))
+ return new InternedStringProducer(getGarbageProducer(getInBrackets(id)));
+ else if (id.startsWith("linearList("))
+ return new LinearListProducer(MemoryStrategy.fromString(getInBrackets(id)));
+ else if (id.startsWith("circularList("))
+ return new CircularListProducer(MemoryStrategy.fromString(getInBrackets(id)));
+ else if (id.startsWith("nonbranchyTree("))
+ return new NonbranchyTreeProducer(MemoryStrategy.fromString(getInBrackets(id)));
+ else if (id.equals("class"))
+ return new GeneratedClassProducer();
+ else if (id.startsWith("hashed("))
+ return new HashedGarbageProducer(getGarbageProducer(getInBrackets(id)));
+ else if (id.startsWith("random("))
+ return new RandomProducer(getGarbageProducerList(getInBrackets(id)));
+ else if (id.startsWith("twofields("))
+ return new TwoFieldsObjectProducer(getGarbageProducer(getInBrackets(id)));
+ else if (id.startsWith("arrayof("))
+ return new ArrayOfProducer(getGarbageProducer(getInBrackets(id)));
+ else if (id.startsWith("trace("))
+ return new TraceProducer(getGarbageProducer(getInBrackets(id)));
+ else
+ throw new TestBug("Invalid garbage producer identifier: " + id);
+ }
+
+ private static String getInBrackets(String s) {
+ int n1 = s.indexOf('(');
+ if (n1 == -1)
+ throw new TestBug("Opening bracket not found: " + s);
+ int n2 = s.lastIndexOf(')');
+ if (n2 == -1)
+ throw new TestBug("Closing bracket not found: " + s);
+ return s.substring(n1 + 1, n2);
+ }
+
+ private static List<GarbageProducer> getGarbageProducerList(String s) {
+ if (s.equals("primitiveArrays"))
+ return getPrimitiveArrayProducers();
+ else if (s.equals("arrays"))
+ return getArrayProducers();
+ else {
+ String[] ids = s.split(",");
+ List<GarbageProducer> garbageProducers = new ArrayList<GarbageProducer>(ids.length);
+ for (int i = 0; i < ids.length; ++i)
+ garbageProducers.add(getGarbageProducer(ids[i]));
+ return garbageProducers;
+ //throw new TestBug("Invalid id for list of garbage producers: " + id);
+ }
+ }
+
+ public static GarbageProducers getGarbageProducers() {
+ if (garbageProducers == null)
+ garbageProducers = new GarbageProducers();
+ return garbageProducers;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategy.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+import nsk.share.TestBug;
+
+/**
+ * This class encapsulates notions like "many objects of small size",
+ * "small number of objects of big size".
+ */
+public abstract class MemoryStrategy {
+ private static int smallNumber = 100;
+ public abstract long getSize(long memory);
+ public abstract long getSize(long memory, long objectExtra);
+ public abstract int getCount(long memory);
+ public abstract int getCount(long memory, long objectExtra);
+
+ protected MemoryStrategy() {
+ }
+
+ /**
+ * Small object size, big number of objects.
+ */
+ public static final MemoryStrategy LOW = new MemoryStrategy() {
+ public long getSize(long memory) {
+ return getSize(memory, 0);
+ }
+
+ public long getSize(long memory, long objectExtra) {
+ return smallNumber;
+ }
+
+ public int getCount(long memory) {
+ return getCount(memory, 0);
+ }
+
+ public int getCount(long memory, long objectExtra) {
+ return (int) Math.min(Integer.MAX_VALUE, memory / (getSize(memory) + objectExtra));
+ }
+
+ public String toString() {
+ return "low";
+ }
+ };
+
+ /**
+ * Medium object size, medium number of objects.
+ */
+ public static final MemoryStrategy MEDIUM = new MemoryStrategy() {
+ public long getSize(long memory) {
+ return getSize(memory, 0);
+ }
+
+ public long getSize(long memory, long objectExtra) {
+ return Math.round(Math.floor(Math.sqrt(memory)));
+ }
+
+ public int getCount(long memory) {
+ return getCount(memory, 0);
+ }
+
+ public int getCount(long memory, long objectExtra) {
+ return (int) Math.min(Integer.MAX_VALUE, memory / (getSize(memory) + objectExtra));
+ }
+
+ public String toString() {
+ return "medium";
+ }
+ };
+
+ /**
+ * Big object size, small number of objects.
+ */
+ public static final MemoryStrategy HIGH = new MemoryStrategy() {
+ public long getSize(long memory) {
+ return getSize(memory, 0);
+ }
+
+ public long getSize(long memory, long objectExtra) {
+ return memory / getCount(memory, objectExtra);
+ }
+
+ public int getCount(long memory) {
+ return getCount(memory, 0);
+ }
+
+ public int getCount(long memory, long objectExtra) {
+ return smallNumber;
+ }
+
+ public String toString() {
+ return "high";
+ }
+ };
+
+ /**
+ * Get memory strategy by identifier.
+ *
+ * @param id identifier
+ * @return memory strategy for this identifier
+ * @throws TestBug if id is invalid
+ */
+ public static MemoryStrategy fromString(String id) {
+ if (id.equalsIgnoreCase("low"))
+ return LOW;
+ else if (id.equalsIgnoreCase("medium"))
+ return MEDIUM;
+ else if (id.equalsIgnoreCase("high"))
+ return HIGH;
+ else
+ throw new TestBug("Unknown memory strategy identifier: " + id);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/MemoryStrategyAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+/**
+ * Marker interface for getting MemoryStrategy.
+ */
+public interface MemoryStrategyAware {
+ public void setMemoryStrategy(MemoryStrategy memoryStrategy);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/RandomProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp;
+
+import java.util.List;
+import nsk.share.test.LocalRandom;
+
+/**
+ * Garbage producer that randomly creates objects using
+ * one garbage producer from the list.
+ */
+public class RandomProducer<T> implements GarbageProducer<T> {
+ private List<GarbageProducer<T>> producers;
+
+ public RandomProducer(List<GarbageProducer<T>> producers) {
+ this.producers = producers;
+ }
+
+ public T create(long memory) {
+ return producers.get(LocalRandom.nextInt(producers.size())).create(memory);
+ }
+
+ public void validate(T obj) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayOfProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.DerivedProducer;
+import nsk.share.gc.gp.GarbageUtils;
+import nsk.share.gc.gp.MemoryStrategy;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces arrays of objects
+ * determined by parent garbage producer. A memory strategy is
+ * used to determine how memory is distributed between array size
+ * and size of each object in array.
+ */
+public class ArrayOfProducer<T> extends DerivedProducer<Object[], T> {
+ private int n;
+
+ public ArrayOfProducer(GarbageProducer<T> parent, int n) {
+ super(parent);
+ this.n = n;
+ }
+
+ public ArrayOfProducer(GarbageProducer<T> parent) {
+ this(parent, 2);
+ }
+
+ public Object[] create(long memory) {
+ Object[] array = new Object[n];
+ long objectSize = (memory - Memory.getArrayExtraSize() - Memory.getReferenceSize() * n) / n;
+ for (int i = 0; i < n; ++i)
+ array[i] = createParent(objectSize);
+ return array;
+ }
+
+ public void validate(Object[] obj) {
+ for (int i = 0; i < obj.length; ++i)
+ validateParent((T) obj[i]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.DerivedStrategyProducer;
+import nsk.share.gc.gp.GarbageUtils;
+import nsk.share.gc.gp.MemoryStrategy;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces arrays of objects
+ * determined by parent garbage producer. A memory strategy is
+ * used to determine how memory is distributed between array size
+ * and size of each object in array.
+ */
+public class ArrayProducer<T> extends DerivedStrategyProducer<Object[], T> {
+ public ArrayProducer(GarbageProducer<T> parent, MemoryStrategy memoryStrategy) {
+ super(parent, memoryStrategy);
+ }
+
+ public Object[] create(long memory) {
+ long objectSize = GarbageUtils.getArraySize(memory, memoryStrategy);
+ int objectCount = GarbageUtils.getArrayCount(memory, memoryStrategy);
+ Object[] array = new Object[objectCount];
+ for (int i = 0; i < objectCount; ++i)
+ array[i] = createParent(objectSize);
+ return array;
+ }
+
+ public void validate(Object[] obj) {
+ for (int i = 0; i < obj.length; ++i)
+ validateParent((T) obj[i]);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/BooleanArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces byte arrays.
+ */
+public class BooleanArrayProducer implements GarbageProducer<boolean[]> {
+ public boolean[] create(long memory) {
+ boolean[] arr = new boolean[Memory.getArrayLength(memory, Memory.getBooleanSize())];
+ LocalRandom.nextBooleans(arr);
+ return arr;
+ }
+
+ public void validate(boolean[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ByteArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces byte arrays.
+ */
+public class ByteArrayProducer implements GarbageProducer<byte[]> {
+ public byte[] create(long memory) {
+ byte[] arr = new byte[Memory.getArrayLength(memory, 1)];
+ LocalRandom.nextBytes(arr);
+ return arr;
+ }
+
+ public void validate(byte[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/CharArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces int arrays.
+ */
+public class CharArrayProducer implements GarbageProducer<char[]> {
+ public char[] create(long memory) {
+ char[] arr = new char[Memory.getArrayLength(memory, Memory.getCharSize())];
+ LocalRandom.nextChars(arr);
+ return arr;
+ }
+
+ public void validate(char[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/DoubleArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+
+/**
+ * GarbageProducer implementation that produces double arrays.
+ */
+public class DoubleArrayProducer implements GarbageProducer<double[]> {
+ public double[] create(long memory) {
+ double[] arr = new double[Memory.getArrayLength(memory, Memory.getDoubleSize())];
+ LocalRandom.nextDoubles(arr);
+ return arr;
+ }
+
+ public void validate(double[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/FloatArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+
+/**
+ * GarbageProducer implementation that produces float arrays.
+ */
+public class FloatArrayProducer implements GarbageProducer<float[]> {
+ public float[] create(long memory) {
+ float[] arr = new float[Memory.getArrayLength(memory, Memory.getFloatSize())];
+ LocalRandom.nextFloats(arr);
+ return arr;
+ }
+
+ public void validate(float[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/IntArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces int arrays.
+ */
+public class IntArrayProducer implements GarbageProducer<int[]> {
+ public int[] create(long memory) {
+ int[] arr = new int[Memory.getArrayLength(memory, Memory.getIntSize())];
+ LocalRandom.nextInts(arr);
+ return arr;
+ }
+
+ public void validate(int[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/LongArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces long arrays.
+ */
+public class LongArrayProducer implements GarbageProducer<long[]> {
+ public long[] create(long memory) {
+ long[] arr = new long[Memory.getArrayLength(memory, Memory.getLongSize())];
+ LocalRandom.nextLongs(arr);
+ return arr;
+ }
+
+ public void validate(long[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ObjectArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+
+/**
+ * GarbageProducer implementation that produces object arrays.
+ */
+public class ObjectArrayProducer implements GarbageProducer<Object[]> {
+ public Object[] create(long memory) {
+ return new Object[Memory.getArrayLength(memory, Memory.getObjectExtraSize())];
+ }
+
+ public void validate(Object[] arr) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/array/ShortArrayProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.array;
+
+import nsk.share.test.LocalRandom;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.Memory;
+import nsk.share.TestFailure;
+
+/**
+ * GarbageProducer implementation that produces short arrays.
+ */
+public class ShortArrayProducer implements GarbageProducer<short[]> {
+ public short[] create(long memory) {
+ short[] arr = new short[Memory.getArrayLength(memory, Memory.getShortSize())];
+ LocalRandom.nextShorts(arr);
+ return arr;
+ }
+
+ public void validate(short[] arr) {
+ LocalRandom.validate(arr);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/classload/GeneratedClassProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.classload;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.classload.GeneratingClassLoader;
+import nsk.share.classload.GeneratingClassLoader;
+import nsk.share.gc.gp.GarbageUtils;
+import nsk.share.test.LocalRandom;
+
+/**
+ * Garbage producer that creates classes loaded with GeneratingClassLoader.
+ *
+ * Note: this class is not thread-safe.
+ */
+public class GeneratedClassProducer implements GarbageProducer<Class> {
+ private int number;
+ private String className;
+ private StringBuilder sb = new StringBuilder();
+ private int minPerClassLoader = 50;
+ private int maxPerClassLoader = 150;
+ private int count;
+ private GeneratingClassLoader loader = new GeneratingClassLoader();
+
+ public GeneratedClassProducer() {
+ this(GeneratingClassLoader.DEFAULT_CLASSNAME);
+ }
+
+ public GeneratedClassProducer(String className) {
+ this.className = className;
+ }
+
+ private String getNewName() {
+ sb.delete(0, sb.length());
+ sb.append("Class");
+ sb.append(number);
+ int n = loader.getNameLength() - sb.length();
+ for (int i = 0; i < n; ++i)
+ sb.append('_');
+ return sb.toString();
+ }
+
+ public Class create(long memory) {
+ try {
+ if (number++ > maxPerClassLoader || loader == null) {
+ loader = new GeneratingClassLoader(className);
+ count = LocalRandom.nextInt(minPerClassLoader, maxPerClassLoader);
+ number = 0;
+ }
+ return loader.loadClass(getNewName());
+ } catch (ClassNotFoundException e) {
+ throw convertException(e);
+ }
+ }
+
+ public void validate(Class cl) {
+ }
+
+ protected RuntimeException convertException(Exception e) {
+ return new RuntimeException(e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/CircularListProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.list;
+
+import nsk.share.gc.LinkedMemoryObject;
+import nsk.share.gc.Memory;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.MemoryStrategy;
+
+/**
+ * Garbage producer that produces circular linked lists.
+ */
+public class CircularListProducer implements GarbageProducer<LinkedMemoryObject> {
+ private MemoryStrategy memoryStrategy;
+
+ public CircularListProducer(MemoryStrategy memoryStrategy) {
+ this.memoryStrategy = memoryStrategy;
+ }
+
+ public LinkedMemoryObject create(long memory) {
+ long objectSize = memoryStrategy.getSize(memory);
+ int objectCount = memoryStrategy.getCount(memory);
+ return Memory.makeCircularList(objectCount, (int) objectSize);
+ }
+
+ public void validate(LinkedMemoryObject obj) {
+ LinkedMemoryObject o = obj;
+ while (o != null && o != obj)
+ o = o.getNext();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/list/LinearListProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.list;
+
+import nsk.share.gc.LinkedMemoryObject;
+import nsk.share.gc.Memory;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.MemoryStrategy;
+
+/**
+ * Garbage producer that produces linear linked lists.
+ */
+public class LinearListProducer implements GarbageProducer<LinkedMemoryObject> {
+ private MemoryStrategy memoryStrategy;
+
+ public LinearListProducer(MemoryStrategy memoryStrategy) {
+ this.memoryStrategy = memoryStrategy;
+ }
+
+ public LinkedMemoryObject create(long memory) {
+ long objectSize = memoryStrategy.getSize(memory);
+ int objectCount = memoryStrategy.getCount(memory);
+ return Memory.makeLinearList(objectCount, (int) objectSize);
+ }
+
+ public void validate(LinkedMemoryObject obj) {
+ LinkedMemoryObject o = obj;
+ while (o != null && o != obj)
+ o = o.getNext();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/HashedGarbageProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.misc;
+
+import nsk.share.gc.gp.DerivedProducer;
+import nsk.share.gc.gp.GarbageProducer;
+
+/*
+ * Garbage producer that also calls {@link java.lang.System#identityHashCode(java.lang.Object)} on produced object.
+ */
+
+/*
+ The description is misleading. I looked at some old email, and the
+ goal is to stress the code that deals with displaced mark words, so
+ the description should be more like "Stress tests for displaced mark
+ words." In hotspot, each object has a mark word that stores several
+ things about the object including its hash code (if it has one) and
+ lock state. Most objects never have a hash code and are never locked,
+ so the mark word is empty.
+
+ Most of our garbage collectors use the mark word temporarily during GC
+ to store a 'forwarding pointer.' It's not important what that is, but
+ it means that objects that have a hash code or that are locked have to
+ have the mark word saved during GC and then restored at the end of GC.
+ We want to exercise this saving/restoring code. So a test case should
+ have a large percentage (40-50%) of objects that either have a hash
+ code or are locked.
+
+ */
+public class HashedGarbageProducer<T> extends DerivedProducer<T, T> {
+ public HashedGarbageProducer(GarbageProducer<T> parent) {
+ super(parent);
+ }
+
+ public T create(long memory) {
+ T obj = createParent(memory);
+ System.identityHashCode(obj);
+ return obj;
+ }
+
+ public void validate(T obj) {
+ validateParent(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TraceProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.misc;
+
+import nsk.share.gc.gp.DerivedProducer;
+import nsk.share.gc.gp.GarbageProducer;
+
+/*
+ * GarbageProducer that traces the production.
+ */
+public class TraceProducer<T> extends DerivedProducer<T, T> {
+ private String prid;
+
+ public TraceProducer(GarbageProducer<T> parent) {
+ super(parent);
+ prid = "Create (" + parent + "): ";
+ }
+
+ public T create(long memory) {
+ T obj = createParent(memory);
+ System.out.println(prid + memory);
+ return obj;
+ }
+
+ public void validate(T obj) {
+ validateParent(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/misc/TwoFieldsObjectProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.gc.gp.misc;
+
+import nsk.share.gc.Memory;
+import nsk.share.gc.*;
+import nsk.share.gc.gp.*;
+
+/**
+ * GarbageProducer that produces object with two fields which
+ * reference objects producer by parent garbage producer.
+ */
+public class TwoFieldsObjectProducer<T> extends DerivedProducer<TwoFieldsObject<T>, T> {
+ public TwoFieldsObjectProducer(GarbageProducer<T> parent) {
+ super(parent);
+ }
+
+ public TwoFieldsObject<T> create(long memory) {
+ long memoryT = (memory - Memory.getObjectExtraSize() - 2 * Memory.getReferenceSize()) / 2;
+ return new TwoFieldsObject<T>(createParent(memoryT), createParent(memoryT));
+ }
+
+ public void validate(TwoFieldsObject<T> obj) {
+ validateParent(obj.getLeft());
+ validateParent(obj.getRight());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/AllMemoryObjectProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.obj;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.AllMemoryObject;
+
+public class AllMemoryObjectProducer implements GarbageProducer<AllMemoryObject> {
+ public AllMemoryObject create(long memory) {
+ return new AllMemoryObject((int) memory);
+ }
+
+ public void validate(AllMemoryObject obj) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObject1Producer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.obj;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.FinMemoryObject1;
+
+public class FinMemoryObject1Producer implements GarbageProducer<FinMemoryObject1> {
+ public FinMemoryObject1 create(long memory) {
+ return new FinMemoryObject1((int) memory);
+ }
+
+ public void validate(FinMemoryObject1 obj) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/FinMemoryObjectProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.obj;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.FinMemoryObject;
+
+public class FinMemoryObjectProducer implements GarbageProducer<FinMemoryObject> {
+ public FinMemoryObject create(long memory) {
+ return new FinMemoryObject((int) memory);
+ }
+
+ public void validate(FinMemoryObject obj) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/obj/MemoryObjectProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.obj;
+
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.MemoryObject;
+
+public class MemoryObjectProducer implements GarbageProducer<MemoryObject> {
+ public MemoryObject create(long memory) {
+ return new MemoryObject((int) memory);
+ }
+
+ public void validate(MemoryObject obj) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/InternedStringProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.string;
+
+import nsk.share.gc.gp.DerivedProducer;
+import nsk.share.gc.gp.GarbageProducer;
+
+/**
+ * Garbage producer that creates interned strings.
+ */
+public class InternedStringProducer extends DerivedProducer<String, String> {
+ public InternedStringProducer() {
+ this(new RandomStringProducer());
+ }
+
+ public InternedStringProducer(GarbageProducer<String> parent) {
+ super(parent);
+ }
+
+ public String create(long memory) {
+ return createParent(memory).intern();
+ }
+
+ public void validate(String s) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/RandomStringProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.gc.gp.string;
+
+import nsk.share.test.*;
+import nsk.share.gc.Memory;
+import nsk.share.gc.gp.GarbageProducer;
+
+/**
+ * Garbage producer that creates random strings.
+ */
+public class RandomStringProducer implements GarbageProducer<String> {
+
+ private int stringLengthLowerBound = 10;
+
+ public RandomStringProducer() {
+ }
+
+ public RandomStringProducer(int stringLengthLowerBound) {
+ this.stringLengthLowerBound = stringLengthLowerBound;
+ }
+
+ public String create(long memory) {
+ int stringLengthUpperBound = (int) Math.min(memory / 2 - Memory.getObjectExtraSize(), Integer.MAX_VALUE);
+ if (stringLengthUpperBound < stringLengthLowerBound) {
+ stringLengthLowerBound = stringLengthUpperBound;
+ }
+ int length = stringLengthLowerBound + LocalRandom.nextInt(stringLengthUpperBound - stringLengthLowerBound);
+ char[] arr = new char[length];
+ for (int i = 0; i < length; ++i) {
+ arr[i] = (char) LocalRandom.nextInt();
+ }
+ return new String(arr);
+ }
+
+ public void setStringLengthLowerBound(int stringLengthLowerBound) {
+ this.stringLengthLowerBound = stringLengthLowerBound;
+ }
+
+ public void validate(String s) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/string/SimpleStringProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.string;
+
+import nsk.share.test.*;
+import nsk.share.gc.gp.GarbageProducer;
+
+/**
+ * Garbage producer that creates simple strings.
+ */
+public class SimpleStringProducer implements GarbageProducer<String> {
+
+
+ public String create(long memory) {
+ long length = memory/8;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < length; ++i)
+ sb.append((char) LocalRandom.nextInt());
+ return sb.toString();
+ }
+
+
+ public void validate(String s) {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/tree/NonbranchyTreeProducer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.gp.tree;
+
+import nsk.share.gc.*;
+import nsk.share.gc.gp.*;
+import nsk.share.gc.Memory;
+
+public class NonbranchyTreeProducer implements GarbageProducer<LinkedMemoryObject>, MemoryStrategyAware {
+ private MemoryStrategy memoryStrategy;
+ private float branchiness;
+
+ public NonbranchyTreeProducer(MemoryStrategy memoryStrategy) {
+ this(memoryStrategy, 0.75f);
+ }
+
+ public NonbranchyTreeProducer(MemoryStrategy memoryStrategy, float branchiness) {
+ setMemoryStrategy(memoryStrategy);
+ setBranchiness(branchiness);
+ }
+
+ public LinkedMemoryObject create(long memory) {
+ long objectSize = memoryStrategy.getSize(memory);
+ int objectCount = memoryStrategy.getCount(memory);
+ return Memory.makeNonbranchyTree(objectCount, branchiness, (int) objectSize);
+ }
+
+ public void validate(LinkedMemoryObject obj) {
+ }
+
+ public final void setMemoryStrategy(MemoryStrategy memoryStrategy) {
+ this.memoryStrategy = memoryStrategy;
+ }
+
+ public final void setBranchiness(float branchiness) {
+ this.branchiness = branchiness;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Locker;
+
+/**
+ * CriticalSectionLocker represents a way to lock a resource
+ * by entering some critical section.
+ */
+public abstract class CriticalSectionLocker<T> implements Locker<T> {
+ private transient boolean enabled = false;
+ private transient boolean locked = false;
+ private Object sync = new Object();
+ private Thread thread;
+ private Throwable exception;
+
+ private final Runnable runnable = new Runnable() {
+ public void run() {
+ //System.out.println("Running");
+ try {
+ do {
+ synchronized (sync) {
+ while (enabled && !locked) {
+ try {
+ sync.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ if (!enabled)
+ break;
+ }
+ do {
+ criticalSection();
+ } while (locked);
+ } while (enabled);
+ // System.out.println("Exiting");
+ } catch (RuntimeException t) {
+ t.printStackTrace();
+ exception = t;
+ throw t;
+ }
+ }
+ };
+
+ public CriticalSectionLocker() {
+ }
+
+ /**
+ * Enter critical section.
+ *
+ */
+ protected abstract void criticalSection();
+
+ public void enable() {
+ synchronized (sync) {
+ if (enabled)
+ throw new TestBug("Locker already enabled.");
+// System.out.println("Enabling " + this);
+ enabled = true;
+ thread = new Thread(runnable, "Locker: " + runnable);
+ thread.setDaemon(true);
+ thread.start();
+ }
+ }
+
+ public void lock() {
+ synchronized (sync) {
+ if (locked)
+ throw new TestBug("Locker already locked.");
+// System.out.println("Locking " + this);
+ locked = true;
+ sync.notifyAll();
+ }
+ }
+
+ public void unlock() {
+ synchronized (sync) {
+ if (!locked)
+ throw new TestBug("Locker not locked.");
+// System.out.println("Unocking " + this);
+ locked = false;
+ sync.notifyAll();
+ }
+ }
+
+ public void disable() {
+ synchronized (sync) {
+ if (!enabled)
+ throw new TestBug("Locker not enabled.");
+// System.out.println("Disabling " + this);
+ enabled = false;
+ sync.notifyAll();
+ }
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ throw new TestBug(e);
+ }
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionObjectLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.TestBug;
+import nsk.share.gc.gp.GarbageProducer;
+import nsk.share.gc.gp.DerivedProducer;
+
+/**
+ * CriticalSectionLocker represents a way to lock
+ * a resource by entering some critical section of
+ * code.
+ */
+public abstract class CriticalSectionObjectLocker<T> extends CriticalSectionTimedLocker<T> implements Locker<T> {
+ public T obj;
+
+ public CriticalSectionObjectLocker(T obj) {
+ this.obj = obj;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/CriticalSectionTimedLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Locker;
+
+/**
+ * CriticalSectionTimedLocker represents a way to lock a resource
+ * by entering some critical section for some time.
+ */
+public abstract class CriticalSectionTimedLocker<T> extends CriticalSectionLocker<T> {
+ private long enterTime;
+ private long sleepTime;
+
+ public CriticalSectionTimedLocker() {
+ this(5000, 10);
+ }
+
+ public CriticalSectionTimedLocker(long enterTime, long sleepTime) {
+ setEnterTime(enterTime);
+ setSleepTime(sleepTime);
+ }
+
+ protected final void criticalSection() {
+ criticalSection(enterTime, sleepTime);
+ }
+
+ /**
+ * Enter critical section for enterTime.
+ *
+ * Usually, something is done in a loop inside this critical section.
+ * In this case, sleepTime is time to sleep after each iteration.
+ */
+ protected abstract void criticalSection(long enterTime, long sleepTime);
+
+ public final void setEnterTime(long enterTime) {
+ this.enterTime = enterTime;
+ }
+
+ public final void setSleepTime(long sleepTime) {
+ this.sleepTime = sleepTime;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Locker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.gc.gp.GarbageProducer;
+
+/**
+ * Locker represents a way to lock a resource
+ * which may be critical for GC to work.
+ */
+public interface Locker<T> {
+ /**
+ * Enable this locker and make necessary preparations.
+ */
+ public void enable();
+
+ /**
+ * Lock an object.
+ *
+ * There can be multiple calls to this, but to lock
+ * again, one must first unlock.
+ */
+ public void lock();
+
+ /**
+ * Unlock an object.
+ *
+ */
+ public void unlock();
+
+ /**
+ * Get any exceptions that occured.
+ *
+ * @return exception or null if there none
+ */
+ public Throwable getException();
+
+ /**
+ * Disable this locker and make necessary cleanups.
+ */
+ public void disable();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockerUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.jni.JNILockers;
+import nsk.share.gc.lock.malloc.MallocLockers;
+import nsk.share.gc.lock.jvmti.JVMTIAllocLockers;
+import nsk.share.gc.lock.jniref.*;
+
+/**
+ * Utility methods for lockers.
+ */
+public class LockerUtils {
+ private LockerUtils() {
+ }
+
+ /**
+ * Obtain Lockers by id.
+ *
+ * @param id identifier of Lockers
+ */
+ public static Lockers getLockers(String id) {
+ if (id == null || id.equals("jni"))
+ return new JNILockers();
+ else if (id.equals("jniGlobalRef"))
+ return new JNIGlobalRefLockers();
+ else if (id.equals("jniLocalRef"))
+ return new JNILocalRefLockers();
+ else if (id.equals("jniRef"))
+ return new JNIRefLockers();
+ else if (id.equals("jniWeakGlobalRef"))
+ return new JNIWeakGlobalRefLockers();
+ else if (id.equals("malloc"))
+ return new MallocLockers();
+ else if (id.equals("jvmtiAlloc"))
+ return new JVMTIAllocLockers();
+ else
+ throw new TestBug("Invalid lockers id: " + id);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/Lockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import nsk.share.gc.gp.GarbageProducer;
+
+public interface Lockers<T> {
+ public Locker<T> createLocker(T obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/LockersAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+/**
+ * Marker interface for getting Locker.
+ */
+public interface LockersAware<T> {
+ public void setLockers(Lockers<T> locker);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/MultiLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * MultiLocker is just a locker that uses several lockers.
+ */
+public class MultiLocker<T> implements Locker<T> {
+ private List<Locker<T>> lockers;
+
+ public MultiLocker() {
+ this(new ArrayList<Locker<T>>());
+ }
+
+ public MultiLocker(List<Locker<T>> lockers) {
+ this.lockers = lockers;
+ }
+
+ public void enable() {
+ for (Locker locker : lockers)
+ locker.enable();
+ }
+
+ public void lock() {
+ for (Locker locker : lockers)
+ locker.lock();
+ }
+
+ public void unlock() {
+ for (Locker locker : lockers)
+ locker.unlock();
+ }
+
+ public Throwable getException() {
+ return null;
+ }
+
+ public void disable() {
+ for (Locker locker : lockers)
+ locker.disable();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_BooleanArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_nsk_share_gc_lock_jni_BooleanArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jbooleanArray arr;
+ jboolean *pa;
+ jboolean hash = JNI_TRUE;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return JNI_FALSE;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return JNI_FALSE;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = JNI_FALSE;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/BooleanArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class BooleanArrayCriticalLocker extends CriticalSectionObjectLocker<boolean[]> {
+ private native boolean criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("BooleanArrayCriticalLocker");
+ }
+
+ public BooleanArrayCriticalLocker(boolean[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ boolean javaHash = hashValue(obj);
+ boolean nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private boolean hashValue(boolean[] obj) {
+ boolean hash = true;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_ByteArrayCriticalLocker
+ * Method: criticalNative
+ */
+JNIEXPORT jbyte JNICALL Java_nsk_share_gc_lock_jni_ByteArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jbyteArray arr;
+ jbyte *pa;
+ jbyte hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return 0;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ByteArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class ByteArrayCriticalLocker extends CriticalSectionObjectLocker<byte[]> {
+ private native byte criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("ByteArrayCriticalLocker");
+ }
+
+ public ByteArrayCriticalLocker(byte[] obj) {
+ super(obj);
+ }
+ protected void criticalSection(long enterTime, long sleepTime) {
+ byte javaHash = hashValue(obj);
+ byte nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+
+ private byte hashValue(byte[] obj) {
+ byte hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_CharArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jchar JNICALL Java_nsk_share_gc_lock_jni_CharArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jcharArray arr;
+ jchar *pa;
+ jchar hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ current_time = 0;
+ enterTime /= 1000;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/CharArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class CharArrayCriticalLocker extends CriticalSectionObjectLocker<char[]> {
+ private native char criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("CharArrayCriticalLocker");
+ }
+
+ public CharArrayCriticalLocker(char[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ char javaHash = hashValue(obj);
+ char nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private char hashValue(char[] obj) {
+ char hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_DoubleArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jdouble JNICALL Java_nsk_share_gc_lock_jni_DoubleArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jdoubleArray arr;
+ jdouble *pa;
+ jdouble hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash += pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/DoubleArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class DoubleArrayCriticalLocker extends CriticalSectionObjectLocker<double[]> {
+ private native double criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("DoubleArrayCriticalLocker");
+ }
+
+ public DoubleArrayCriticalLocker(double[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ double javaHash = hashValue(obj);
+ double nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private double hashValue(double[] obj) {
+ double hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash += obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_FloatArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jfloat JNICALL Java_nsk_share_gc_lock_jni_FloatArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jfloatArray arr;
+ jfloat *pa;
+ jfloat hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash += pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/FloatArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class FloatArrayCriticalLocker extends CriticalSectionObjectLocker<float[]> {
+ private native float criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("FloatArrayCriticalLocker");
+ }
+
+ public FloatArrayCriticalLocker(float[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ float javaHash = hashValue(obj);
+ float nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private float hashValue(float[] obj) {
+ float hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash += obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_IntArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jint JNICALL Java_nsk_share_gc_lock_jni_IntArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jintArray arr;
+ jint *pa;
+ jint hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/IntArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class IntArrayCriticalLocker extends CriticalSectionObjectLocker<int[]> {
+ private native int criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("IntArrayCriticalLocker");
+ }
+
+ public IntArrayCriticalLocker(int[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ int javaHash = hashValue(obj);
+ int nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private int hashValue(int[] obj) {
+ int hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/JNILockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JNILockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ if (obj instanceof String)
+ return new StringCriticalLocker((String) obj);
+ if (obj instanceof boolean[])
+ return new BooleanArrayCriticalLocker((boolean[]) obj);
+ if (obj instanceof byte[])
+ return new ByteArrayCriticalLocker((byte[]) obj);
+ if (obj instanceof char[])
+ return new CharArrayCriticalLocker((char[]) obj);
+ if (obj instanceof double[])
+ return new DoubleArrayCriticalLocker((double[]) obj);
+ if (obj instanceof float[])
+ return new FloatArrayCriticalLocker((float[]) obj);
+ if (obj instanceof int[])
+ return new IntArrayCriticalLocker((int[]) obj);
+ if (obj instanceof long[])
+ return new LongArrayCriticalLocker((long[]) obj);
+ if (obj instanceof short[])
+ return new ShortArrayCriticalLocker((short[]) obj);
+ throw new TestBug("Cannot create locker for: " + obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_LongArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jlong JNICALL Java_nsk_share_gc_lock_jni_LongArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jlongArray arr;
+ jlong *pa;
+ jlong hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/LongArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class LongArrayCriticalLocker extends CriticalSectionObjectLocker<long[]> {
+ private native long criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("LongArrayCriticalLocker");
+ }
+
+ public LongArrayCriticalLocker(long[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ long javaHash = hashValue(obj);
+ long nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private long hashValue(long[] obj) {
+ long hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_ShortArrayCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jshort JNICALL Java_nsk_share_gc_lock_jni_ShortArrayCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jshortArray arr;
+ jshort *pa;
+ jshort hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return 0;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return 0;
+ }
+ }
+ arr = (*env)->GetObjectField(env, this, objFieldId);
+ if (arr == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetArrayLength(env, arr);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = 0;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, pa, 0);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, arr);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/ShortArrayCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+public class ShortArrayCriticalLocker extends CriticalSectionObjectLocker<short[]> {
+ private native short criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("ShortArrayCriticalLocker");
+ }
+
+ public ShortArrayCriticalLocker(short[] obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ short javaHash = hashValue(obj);
+ short nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+ throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ }
+
+ private short hashValue(short[] obj) {
+ short hash = 0;
+ for (int i = 0; i < obj.length; ++i)
+ hash ^= obj[i];
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jni_StringCriticalLocker
+ * Method: criticalNative
+ * Signature: ([Z)Z
+ */
+JNIEXPORT jchar JNICALL Java_nsk_share_gc_lock_jni_StringCriticalLocker_criticalNative
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jsize size, i;
+ jstring str;
+ const jchar *pa;
+ jchar hash = 0;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return JNI_FALSE;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return JNI_FALSE;
+ }
+ }
+ str = (*env)->GetObjectField(env, this, objFieldId);
+ if (str == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return JNI_FALSE;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ size = (*env)->GetStringLength(env, str);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ pa = (*env)->GetStringCritical(env, str, NULL);
+ if (pa != NULL) {
+ for (i = 0; i < size; ++i)
+ hash ^= pa[i];
+ } else {
+ hash = JNI_FALSE;
+ }
+ mssleep((long) sleepTime);
+ (*env)->ReleaseStringCritical(env, str, pa);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, str);
+ return hash;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jni/StringCriticalLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jni;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.gc.gp.string.RandomStringProducer;
+import nsk.share.TestFailure;
+
+public class StringCriticalLocker extends CriticalSectionObjectLocker<String> {
+ private native char criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("StringCriticalLocker");
+ }
+
+ public StringCriticalLocker(String obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+// System.out.println("Lock: " + s);
+ char javaHash = hashValue(obj);
+ char nativeHash = criticalNative(enterTime, sleepTime);
+ if (nativeHash != 0 && nativeHash != javaHash)
+// throw new TestFailure("Native hash: " + nativeHash + " != Java hash: " + javaHash);
+ throw new TestFailure("Native hash differs from java hash");
+ }
+
+ private char hashValue(String s) {
+ char hash = 0;
+ for (int i = 0; i < s.length(); ++i)
+ hash ^= s.charAt(i);
+ return hash;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jniref_JNIGlobalRefLocker
+ * Method: criticalNative
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIGlobalRefLocker_criticalNative
+ (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jobject obj;
+ jobject gref;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return;
+ }
+ }
+ obj = (*env)->GetObjectField(env, this, objFieldId);
+ if (obj == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ gref = (*env)->NewGlobalRef(env, obj);
+ mssleep((long) sleepTime);
+ (*env)->DeleteGlobalRef(env, gref);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+/**
+ * Locker that uses JNI function NewGlobalRef.
+ */
+public class JNIGlobalRefLocker extends CriticalSectionObjectLocker {
+ private native void criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("JNIGlobalRefLocker");
+ }
+
+ public JNIGlobalRefLocker(Object obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ criticalNative(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIGlobalRefLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JNIGlobalRefLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new JNIGlobalRefLocker(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jniref_JNILocalRefLocker
+ * Method: criticalNative
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNILocalRefLocker_criticalNative
+ (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jobject obj;
+ jobject gref;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return;
+ }
+ }
+ obj = (*env)->GetObjectField(env, this, objFieldId);
+ if (obj == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ gref = (*env)->NewLocalRef(env, obj);
+ mssleep((long) sleepTime);
+ (*env)->DeleteLocalRef(env, gref);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+/**
+ * Locker that uses JNI function NewLocalRef.
+ */
+public class JNILocalRefLocker extends CriticalSectionObjectLocker {
+ private native void criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("JNILocalRefLocker");
+ }
+
+ public JNILocalRefLocker(Object obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ criticalNative(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNILocalRefLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JNILocalRefLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new JNILocalRefLocker(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jniref_JNIRefLocker
+ * Method: criticalNative
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIRefLocker_criticalNative
+ (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jobject obj;
+ jobject gref, lref, gwref;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return;
+ }
+ }
+ obj = (*env)->GetObjectField(env, this, objFieldId);
+ if (obj == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ gref = (*env)->NewGlobalRef(env, obj);
+ lref = (*env)->NewLocalRef(env, obj);
+ gwref = (*env)->NewWeakGlobalRef(env, obj);
+ mssleep((long) sleepTime);
+ (*env)->DeleteGlobalRef(env, gref);
+ (*env)->DeleteLocalRef(env, lref);
+ (*env)->DeleteWeakGlobalRef(env, gwref);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+/**
+ * JNIRefLocker locks objects using JNI functions
+ * NewGlobalRef, NewLocalRef, NewWeakGlobalRef
+ */
+public class JNIRefLocker extends CriticalSectionObjectLocker {
+ private native void criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("JNIRefLocker");
+ }
+
+ public JNIRefLocker(Object obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ criticalNative(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIRefLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JNIRefLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new JNIRefLocker(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <time.h>
+#include "jni_tools.h"
+
+static jfieldID objFieldId = NULL;
+
+/*
+ * Class: nsk_share_gc_lock_jniref_JNIWeakGlobalRefLocker
+ * Method: criticalNative
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jniref_JNIWeakGlobalRefLocker_criticalNative
+ (JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ jobject obj;
+ jobject gref;
+ time_t start_time, current_time;
+
+ if (objFieldId == NULL) {
+ jclass class = (*env)->GetObjectClass(env, this);
+ if (class == NULL) {
+ printf("Error: GetObjectClass returned NULL\n");
+ return;
+ }
+ objFieldId = (*env)->GetFieldID(env, class, "obj", "Ljava/lang/Object;");
+ if (objFieldId == NULL) {
+ printf("Error: GetFieldID returned NULL\n");
+ return;
+ }
+ }
+ obj = (*env)->GetObjectField(env, this, objFieldId);
+ if (obj == NULL) {
+ printf("Error: GetObjectField returned NULL\n");
+ return;
+ }
+ (*env)->SetObjectField(env, this, objFieldId, NULL);
+ start_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - start_time < enterTime) {
+ gref = (*env)->NewWeakGlobalRef(env, obj);
+ mssleep((long) sleepTime);
+ (*env)->DeleteWeakGlobalRef(env, gref);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+ (*env)->SetObjectField(env, this, objFieldId, obj);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.gc.lock.CriticalSectionObjectLocker;
+import nsk.share.TestFailure;
+
+/**
+ * Locker that uses JNI function NewWeakGlobalRef.
+ */
+public class JNIWeakGlobalRefLocker extends CriticalSectionObjectLocker {
+ private native void criticalNative(long enterTime, long sleepTime);
+
+ static {
+ System.loadLibrary("JNIWeakGlobalRefLocker");
+ }
+
+ public JNIWeakGlobalRefLocker(Object obj) {
+ super(obj);
+ }
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ criticalNative(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jniref/JNIWeakGlobalRefLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jniref;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JNIWeakGlobalRefLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new JNIWeakGlobalRefLocker(obj);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <jvmti.h>
+#include <time.h>
+#include <stdlib.h>
+#include "jni_tools.h"
+
+static jvmtiEnv *jvmti = NULL;
+static jvmtiCapabilities caps;
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ jint res;
+
+ res = (*jvm)->GetEnv(jvm, (void **) &jvmti, JVMTI_VERSION_1_0);
+ if (res != JNI_OK || jvmti == NULL) {
+ printf("Wrong result of a valid call to GetEnv!\n");
+ return JNI_ERR;
+ }
+ return JNI_OK;
+}
+
+/*
+ * Class: nsk_share_gc_lock_jvmti_JVMTIAllocLocker
+ * Method: jVMTIAllocSection
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_jvmti_JVMTIAllocLocker_jVMTIAllocSection
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ unsigned char *ptr;
+ time_t current_time, old_time;
+ jvmtiError err;
+ old_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - old_time < enterTime) {
+ err = (*jvmti)->Allocate(jvmti, 1, &ptr);
+ mssleep((long) sleepTime);
+ err = (*jvmti)->Deallocate(jvmti, ptr);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jvmti;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Locker;
+import nsk.share.gc.lock.CriticalSectionTimedLocker;
+
+/**
+ * Malloc locker tries to hold malloc lock (if there is any)
+ * by calling malloc() and free() in a loop.
+ */
+public class JVMTIAllocLocker extends CriticalSectionTimedLocker {
+ static {
+ System.loadLibrary("JVMTIAllocLocker");
+ }
+
+ public JVMTIAllocLocker() {
+ }
+
+ public JVMTIAllocLocker(long enterTime, long sleepTime) {
+ super(enterTime, sleepTime);
+ setSleepTime(sleepTime);
+ }
+
+ /**
+ * This native method does Allocate() / Deallocate() in a loop
+ * while java field locked is set to true, sleeping
+ * for sleepTime between Allocate() and Deallocate() and after
+ * Deallocate().
+ */
+ private native void jVMTIAllocSection(long enterTime, long sleepTime);
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ jVMTIAllocSection(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/jvmti/JVMTIAllocLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.jvmti;
+
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class JVMTIAllocLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new JVMTIAllocLocker();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include <jni.h>
+#include <time.h>
+#include <stdlib.h>
+#include "jni_tools.h"
+
+/*
+ * Class: nsk_share_gc_lock_malloc_MallocLocker
+ * Method: mallocSection
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_nsk_share_gc_lock_malloc_MallocLocker_mallocSection
+(JNIEnv *env, jobject this, jlong enterTime, jlong sleepTime) {
+ char *ptr;
+ time_t current_time, old_time;
+ old_time = time(NULL);
+ enterTime /= 1000;
+ current_time = 0;
+ while (current_time - old_time < enterTime) {
+ ptr = malloc(1);
+ mssleep((long) sleepTime);
+ free(ptr);
+ mssleep((long) sleepTime);
+ current_time = time(NULL);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.malloc;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Locker;
+import nsk.share.gc.lock.CriticalSectionTimedLocker;
+
+/**
+ * Malloc locker tries to hold malloc lock (if there is any)
+ * by calling malloc() and free() in a loop.
+ */
+public class MallocLocker extends CriticalSectionTimedLocker {
+ static {
+ System.loadLibrary("MallocLocker");
+ }
+
+ public MallocLocker() {
+ }
+
+ public MallocLocker(long enterTime, long sleepTime) {
+ super(enterTime, sleepTime);
+ }
+
+ /**
+ * This native method does malloc() / free() in a loop
+ * while java field locked is set to true, sleeping
+ * for sleepTime between malloc() and free() and after
+ * free().
+ */
+ private native void mallocSection(long enterTime, long sleepTime);
+
+ protected void criticalSection(long enterTime, long sleepTime) {
+ mallocSection(enterTime, sleepTime);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/lock/malloc/MallocLockers.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.lock.malloc;
+
+import nsk.share.TestBug;
+import nsk.share.gc.lock.Lockers;
+import nsk.share.gc.lock.Locker;
+
+public class MallocLockers implements Lockers {
+ public Locker createLocker(Object obj) {
+ return new MallocLocker();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/Tree.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.tree;
+
+public class Tree {
+ private final long nodeSize;
+ private TreeNode root;
+
+ public Tree(long nodeSize) {
+ this.nodeSize = nodeSize;
+ root = new TreeNode(nodeSize);
+ }
+
+ public Tree(TreeNode root) {
+ this.nodeSize = root.getSize();
+ setRoot(root);
+ }
+
+ public TreeNode follow(int path, int depth) {
+ return root.follow(path, depth);
+ }
+
+ public int getHeight() {
+ return root.getHeight();
+ }
+
+ public TreeNode newNode() {
+ return new TreeNode(nodeSize);
+ }
+
+ public final TreeNode getRoot() {
+ return root;
+ }
+
+ public final void setRoot(TreeNode root) {
+ this.root = root;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/tree/TreeNode.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.gc.tree;
+
+import nsk.share.gc.Memory;
+import nsk.share.gc.gp.GarbageProducer;
+
+/**
+ * A node of binary tree.
+ *
+ * A height of subtree defined by this node is kept in the node.
+ * Additionaly, a byte array is used to control how much memory
+ * this node will occupy.
+ */
+public final class TreeNode {
+ private TreeNode left, right;
+ // The height of the tree
+ private int height;
+ private int size;
+ private Object storage;
+
+
+ /**
+ * Create a tree node that will occupy approximately given memory.
+ *
+ * @param memory memory
+ */
+ public TreeNode(long memory) {
+ int length = (int) (memory - (4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize()));
+ if (length > 0)
+ storage = new byte[length];
+ size = length;
+ }
+
+ /**
+ * Create a tree node that will occupy approximately given memory.
+ *
+ * @param memory memory
+ */
+ public TreeNode(long size, GarbageProducer gp) {
+ int length = (int) (size - (4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize()));
+ if (length > 0)
+ storage = gp.create(length);
+ size = length;
+ }
+ /**
+ * Create a tree node that will occupy approximately given memory
+ * with given left and right children.
+ *
+ * @param memory memory
+ * @param left left child
+ * @param right right child
+ */
+ public TreeNode(long memory, TreeNode left, TreeNode right) {
+ this(memory);
+ setLeft(left);
+ setRight(right);
+ setHeight(1 + Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight()));
+ }
+
+ /**
+ * Create a tree node that will occupy approximately given memory
+ * with given left and right children.
+ *
+ * @param memory memory
+ * @param left left child
+ * @param right right child
+ */
+ public TreeNode(long memory, GarbageProducer gp, TreeNode left, TreeNode right) {
+ this(memory, gp);
+ setLeft(left);
+ setRight(right);
+ setHeight(1 + Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight()));
+ }
+
+ /**
+ * Get memory that this node occupies.
+ *
+ * @return memory size
+ */
+ public long getSize() {
+ int length = storage == null ? 0 : size;
+ return length + 4 * 2 + 2 * Memory.getReferenceSize() + Memory.getObjectExtraSize();
+ }
+
+ /**
+ * Get memory that this subtree occupies.
+ *
+ * @return memory size
+ */
+ public long getTotalSize() {
+ long memory = getSize();
+ if (left != null)
+ memory += left.getSize();
+ if (right != null)
+ memory += right.getSize();
+ return memory;
+ }
+
+ /**
+ * Follow path determined by bits given integer and depth.
+ *
+ * @param path path encoded in integer
+ * @param depth depth to follow
+ * @return end of the path
+ */
+ public TreeNode follow(int path, int depth) {
+ if (depth == 0)
+ return this;
+ TreeNode current = this;
+ TreeNode prev = null;
+ for (int i = 0; i < depth; ++i) {
+ prev = current;
+ if ((path & 1) == 0)
+ current = current.left;
+ else
+ current = current.right;
+ path >>= 1;
+ }
+ return prev;
+ }
+
+ /**
+ * Swap left child of this node with left child of another node.
+ *
+ * @param another another node
+ */
+ public void swapLeft(TreeNode another) {
+ TreeNode tmp = another.left;
+ another.left = left;
+ left = tmp;
+ }
+ /**
+ * Swap right child of this node with right child of another node.
+ *
+ * @param another another node
+ */
+ public void swapRight(TreeNode another) {
+ TreeNode tmp = another.right;
+ another.right = right;
+ right = tmp;
+ }
+
+ public final TreeNode getLeft() {
+ return left;
+ }
+
+ public final void setLeft(TreeNode left) {
+ this.left = left;
+ }
+
+ public final TreeNode getRight() {
+ return right;
+ }
+
+ public final void setRight(TreeNode right) {
+ this.right = right;
+ }
+
+ public final int getHeight() {
+ return height;
+ }
+
+ public boolean hasLeft() {
+ return left != null;
+ }
+
+ public boolean hasRight() {
+ return right != null;
+ }
+
+ /**
+ * Get actual height of the tree.
+ */
+ public int getActualHeight() {
+ return 1 + Math.max(left == null ? 0 : left.getActualHeight(), right == null ? 0 : right.getActualHeight());
+ }
+
+ /**
+ * Get lenght of shortest path from root to leaf in the tree.
+ */
+ public int getShortestPath() {
+ return 1 + Math.min(left == null ? 0 : left.getActualHeight(), right == null ? 0 : right.getActualHeight());
+ }
+
+ public final void setHeight(int value) {
+ this.height = value;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/AbstractJDIDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import nsk.share.jpda.*;
+
+public class AbstractJDIDebuggee extends AbstractDebuggeeTest {
+
+ /*
+ * Create argument handler handling options specific for JDI tests
+ */
+ protected DebugeeArgumentHandler createArgumentHandler(String args[]) {
+ return new ArgumentHandler(args);
+ }
+
+ public static void main(String args[]) {
+ AbstractJDIDebuggee debuggee = new AbstractJDIDebuggee();
+ debuggee.init(args);
+ debuggee.doTest();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ArgumentHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import nsk.share.*;
+import nsk.share.jpda.*;
+
+import com.sun.jdi.VirtualMachine;
+
+/**
+ * Parser for JDI test's specific command-line arguments.
+ * <p>
+ * <code>ArgumentHandler</code> handles JDI test's specific
+ * arguments related to launching debugee VM using JDI features
+ * in addition to general arguments recognized by
+ * <code>DebugeeArgumentHandler</code> and <code>ArgumentParser</code>.
+ * <p>
+ * Following is the list of specific options recognized by
+ * <code>AgrumentHandler</code>:
+ * <ul>
+ * <li> <code>-connector=[launching|attaching|listening|default]</code> -
+ * JDI connector type
+ * <li> <code>-transport=[socket|shmem|default]</code> -
+ * JDWP transport kind
+ * <li> <code>-jdi.trace=[none|all|events|sends|receives|reftypes|objrefs]</code> -
+ * JDI trace mode for debugee VM
+ * </ul>
+ * <p>
+ * See also list of arguments recognized by the base <code>DebugeeArgumentHandler</code>
+ * and <code>ArgumentParser</code> classes.
+ * <p>
+ * See also description of <code>ArgumentParser</code> how to work with
+ * command line arguments and options.
+ *
+ * @see ArgumentParser
+ * @see DebugeeArgumentHandler
+ */
+public class ArgumentHandler extends DebugeeArgumentHandler {
+
+ static private String JDI_CONNECTOR_NAME_PREFIX = "com.sun.jdi.";
+
+ /**
+ * Keep a copy of raw command-line arguments and parse them;
+ * but throw an exception on parsing error.
+ *
+ * @param args Array of the raw command-line arguments.
+ *
+ * @throws NullPointerException If <code>args==null</code>.
+ * @throws IllegalArgumentException If Binder or Log options
+ * are set incorrectly.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public ArgumentHandler(String args[]) {
+ super(args);
+// parseArguments();
+ }
+
+ /**
+ * Overriden method returns transport type for JDWP connection, specified by
+ * <code>-transport</code> command line option, or <i>"default"</i> value
+ * by default.
+ *
+ * @see #getTransportName()
+ * @see #isSocketTransport()
+ * @see #isShmemTransport()
+ * @see #isDefaultTransport()
+ * @see #setRawArguments(String[])
+ */
+ public String getTransportType() {
+ return options.getProperty("transport", "default");
+ }
+
+ /**
+ * Overriden method returns <i>true</i> if <code>socket</code> transport
+ * is used either as specified or as a platform default transport.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isSocketTransport() {
+ String transport = getTransportType();
+ if (transport.equals("socket"))
+ return true;
+ if (transport.equals("shmem"))
+ return false;
+ if (transport.equals("default")) {
+ String arch = getArch();
+ if (arch == null)
+ if (System.getProperty("os.arch").equals("windows-i586"))
+ return false;
+ else
+ return true;
+ else if (arch.equals("windows-i586"))
+ return false;
+ else
+ return true;
+ }
+ throw new TestBug("Bad value of argument transport: " + transport);
+ }
+
+ /**
+ * Overriden method returns <i>true</i> if <code>shmem</code> transport is used
+ * either as specified or as a platform default transport.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isShmemTransport() {
+ return ! isSocketTransport();
+ }
+
+ /**
+ * Overriden method returns <i>true</i> if transport type is <code>default</code>.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isDefaultTransport() {
+ String transport = getTransportType();
+ return transport.equals("default");
+ }
+
+ /**
+ * Overriden methos returns JDI connector type, specified by
+ * <code>-connector</code>. or <i>"default"</i> value by default.
+ *
+ * @see #getConnectorName()
+ * @see #isLaunchingConnector()
+ * @see #isAttachingConnector()
+ * @see #isListeningConnector()
+ * @see #isDefaultConnector()
+ * @see #setRawArguments(String[])
+ */
+ public String getConnectorType() {
+ return options.getProperty("connector", "default");
+ }
+
+ /**
+ * Overriden method returns full connector name corresponding to
+ * the used connector and transport types.
+ *
+ * @see #getConnectorType()
+ * @see #getTransportType()
+ */
+ public String getConnectorName() {
+ if (isLaunchingConnector()) {
+ if (isRawLaunchingConnector())
+ return JDI_CONNECTOR_NAME_PREFIX + "RawCommandLineLaunch";
+ return JDI_CONNECTOR_NAME_PREFIX + "CommandLineLaunch";
+ }
+ if (isAttachingConnector()) {
+ if (isSocketTransport())
+ return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach";
+ if (isShmemTransport())
+ return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryAttach";
+ return JDI_CONNECTOR_NAME_PREFIX + "SocketAttach";
+ }
+ if (isListeningConnector()) {
+ if (isSocketTransport())
+ return JDI_CONNECTOR_NAME_PREFIX + "SocketListen";
+ if (isShmemTransport())
+ return JDI_CONNECTOR_NAME_PREFIX + "SharedMemoryListen";
+ return JDI_CONNECTOR_NAME_PREFIX + "SocketListen";
+ }
+ throw new Failure("Unable to find full name of connector \"" + getConnectorType()
+ + "\" for transport \"" + getTransportType() + "\"");
+ }
+
+ /**
+ * Overriden method returns <i>true</i> if connector type is <code>default</code>.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isDefaultConnector() {
+ return getConnectorType().equals("default");
+ }
+
+ /**
+ * Return <i>true</i> if connector type is <code>launching</code>
+ * <code>rawlaunching<code> or <code>default</code>.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isLaunchingConnector() {
+ return getConnectorType().equals("launching")
+ || getConnectorType().equals("rawlaunching")
+ || getConnectorType().equals("default");
+ }
+
+ /**
+ * Return <i>true</i> if connector type is <code>rawlaunching</code>.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isRawLaunchingConnector() {
+ return getConnectorType().equals("rawlaunching");
+ }
+
+ /**
+ * Return string representation of debug trace mode, specified by
+ * <code>-jdi.trace</code> command line option, or <i>"none"</i>
+ * value by default.
+ * <p>
+ * Possible values for this option are the same as symbolic constants names
+ * in <code>com.sun.jdi.VirtualMachine</code> interface:
+ * <br> <code>"all"</code>, or
+ * <br> <code>"events"</code>, or
+ * <br> <code>"none"</code>, or
+ * <br> <code>"objrefs"</code>, or
+ * <br> <code>"receives"</code>, or
+ * <br> <code>"reftypes"</code>, or
+ * <br> <code>"sends"</code>.
+ *
+ * @see #getTraceMode()
+ * @see #setRawArguments(String[])
+ */
+ public String getTraceModeString() {
+ return options.getProperty("jdi.trace", "none");
+ }
+
+ /**
+ * Return integer code corresponding to debug trace mode, specified by
+ * <code>-jdi.trace</code> command line option, or <i>VirtualMachine.TRACE_NONE</i>
+ * value by default.
+ * <p>
+ * Possible values are the same as symbolic constant values
+ * in <code>com.sun.jdi.VirtualMachine</code> interface:
+ * <ul>
+ * <li><code>VirtualMachine.TRACE_ALL</code>
+ * <li><code>VirtualMachine.TRACE_EVENTS</code>
+ * <li><code>VirtualMachine.TRACE_NONE</code>
+ * <li><code>VirtualMachine.TRACE_OBJREFS</code>
+ * <li><code>VirtualMachine.TRACE_RECEIVES</code>
+ * <li><code>VirtualMachine.TRACE_REFTYPES</code>
+ * <li><code>VirtualMachine.TRACE_SENDS</code>
+ * </ul>
+ *
+ * @see #getTraceModeString()
+ * @see #setRawArguments(String[])
+ */
+ public int getTraceMode() {
+ String val = getTraceModeString();
+ if (val == null)
+ return VirtualMachine.TRACE_NONE;
+ if (val.equals("none"))
+ return VirtualMachine.TRACE_NONE;
+ if (val.equals("all"))
+ return VirtualMachine.TRACE_ALL;
+ if (val.equals("events"))
+ return VirtualMachine.TRACE_EVENTS;
+ if (val.equals("objrefs"))
+ return VirtualMachine.TRACE_OBJREFS;
+ if (val.equals("receives"))
+ return VirtualMachine.TRACE_RECEIVES;
+ if (val.equals("reftypes"))
+ return VirtualMachine.TRACE_REFTYPES;
+ if (val.equals("sends"))
+ return VirtualMachine.TRACE_SENDS;
+ throw new TestBug("Unknown JDI trace mode string: " + val);
+ }
+
+ // delay between connection attempts, used in connectors tests
+ public int getConnectionDelay() {
+ String value = options.getProperty("connectionDelay", "4000");
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not integer value of \"connectionDelay\" argument: " + value);
+ }
+ }
+
+
+ /**
+ * Return <i>true</i> if the test should pass in any case i.e.
+ * an entity specified by the arguments <code>entry[]</code> is
+ * not implemented on the tested platform. Name of the tested
+ * platform is resolved from the "<code>-arch</code>" option.
+ *
+ * @param entry Array with the arguments which are specifing
+ * the entity.
+ *
+ * @throws Oddity If test parameter<code>-arch</code>
+ * has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean shouldPass(String entry[]) {
+ String arch;
+ boolean found = false;
+
+ if ((arch=getArch()) == null)
+ throw new Oddity("Test parameter -arch should be set");
+
+ for (int i=0; i < CheckedFeatures.notImplemented.length; i++) {
+ if (CheckedFeatures.notImplemented[i][0].equals(arch) &&
+ CheckedFeatures.notImplemented[i].length == (entry.length+1)) {
+ for (int j=1; j < (entry.length+1); j++) {
+ if (CheckedFeatures.notImplemented[i][j].equals(entry[j-1]))
+ found = true;
+ else {
+ found = false;
+ break;
+ }
+ }
+ if (found) return true; // the entry[] is not implemented
+ }
+ }
+
+ return false; // the entry[] is implemented
+ }
+
+ /**
+ * Return <i>true</i> if the test should pass in any case i.e.
+ * an entity specified by the argument <code>entry</code> is
+ * not implemented on the tested platform. Name of the tested
+ * platform is resolved from the "<code>-arch</code>" option.
+ *
+ * @param entry String with the argument which is specifing
+ * the entity.
+ *
+ * @throws Oddity If test parameter<code>-arch</code>
+ * has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean shouldPass(String entry) {
+ return (shouldPass(new String[] {entry}));
+ }
+
+ /**
+ * Return <i>true</i> if the test should pass in any case i.e.
+ * an entity specified by the arguments <code>entry1</code> and
+ * <code>entry2</code> is not implemented on the tested platform.
+ * The entry is considered to be not implemented if exact entry
+ * "entry1, entry2" or its main entry "entry1" is not implemented.
+ *
+ * Name of the tested platform is resolved from the "<code>-arch</code>"
+ * option.
+ *
+ * @param entry1 String with the argument 1 which is specifing
+ * the entity.
+ *
+ * @param entry2 String with the argument 2 which is specifing
+ * the entity.
+ *
+ * @throws Oddity If test parameter<code>-arch</code>
+ * has not been set.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean shouldPass(String entry1, String entry2) {
+ return ( shouldPass(new String[] {entry1, entry2}) ||
+ shouldPass(new String[] {entry1}) );
+ }
+
+ /**
+ * Check if an option is admissible and has proper value.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @param option option name
+ * @param value string representation of value (could be an empty string)
+ * null if this option has no value
+ * @return <i>true</i> if option is admissible and has proper value
+ * <i>false</i> if otion is not admissible
+ *
+ * @throws <i>BadOption</i> if option has illegal value
+ *
+ * @see #parseArguments()
+ */
+ protected boolean checkOption(String option, String value) {
+
+ // check options with enumerated values
+
+ if (option.equals("connectionDelay")) {
+ try {
+ int number = Integer.parseInt(value);
+ if (number <= 0) {
+ throw new BadOption(option + ": must be a positive integer");
+ }
+ } catch (NumberFormatException e) {
+ throw new BadOption(option + ": must be an integer");
+ }
+
+ return true;
+ }
+
+ if (option.equals("connector")) {
+ if ((!value.equals("launching"))
+ && (!value.equals("rawlaunching"))
+ && (!value.equals("attaching"))
+ && (!value.equals("listening"))
+ && (!value.equals("default"))) {
+ throw new BadOption(option + ": value must be one of: "
+ + "launching, attaching, listening, default");
+ }
+ return true;
+ }
+
+ if (option.equals("transport")) {
+ if ((!value.equals("socket"))
+ && (!value.equals("shmem"))
+ && (!value.equals("default"))) {
+ throw new BadOption(option + ": must be one of: "
+ + "socket, shmem, default");
+ }
+ return true;
+ }
+
+ if (option.equals("jdi.trace")) {
+ if ((!value.equals("all"))
+ && (!value.equals("none"))
+ && (!value.equals("events"))
+ && (!value.equals("receives"))
+ && (!value.equals("sends"))
+ && (!value.equals("reftypes"))
+ && (!value.equals("objrefs"))) {
+ throw new BadOption(option + ": value must be one of: "
+ + "none, all, events, receives, sends, reftypes, objrefs");
+ }
+ return true;
+ }
+
+ return super.checkOption(option, value);
+ }
+
+ /**
+ * Check options against inconcistence.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @see #parseArguments()
+ */
+ protected void checkOptions() {
+/*
+ if (isTransportAddressDynamic() &&
+ (!isDefaultConnector() && isRawLaunchingConnector())) {
+ throw new BadOption("-transport.address=dynamic should NOT be used with"
+ + " -connector=rawlaunching");
+ }
+ */
+
+ if (! isLaunchedLocally() && ! isDefaultDebugeeSuspendMode()) {
+ throw new BadOption("inconsistent options: "
+ + "-debugee.launch=" + getLaunchMode()
+ + " and -debugee.suspend=" + getDebugeeSuspendMode());
+ }
+
+ if (! isLaunchedLocally() && isLaunchingConnector()) {
+ throw new BadOption("inconsistent options: "
+ + "-debugee.launch=" + getLaunchMode()
+ + " and -connector=" + getConnectorType());
+ }
+
+ if (isLaunchingConnector() && ! isDefaultTransport()) {
+ throw new BadOption("inconsistent options: "
+ + "-connector=" + getConnectorType()
+ + " and -transport=" + getTransportType());
+ }
+
+ if (! isLaunchingConnector() && isDefaultTransport()) {
+ throw new BadOption("inconsistent options: "
+ + "-connector=" + getConnectorType()
+ + " and -transport=" + getTransportType());
+ }
+
+ if (! isDefaultJVMDIStrictMode()) {
+ throw new BadOption("unsupported options: "
+ + "jvmdi.strict: non default JVMDI strict mode is not supported now" + getJVMDIStrictMode());
+ }
+
+/*
+ if (! isLaunchedLocally() && ! isDefaultJVMDIStrictMode()) {
+ throw new BadOption("inconsistent options: "
+ + "-launch.mode=" + getLaunchMode()
+ + " and -jvmdi.strict=" + getJVMDIStrictMode());
+ }
+ */
+
+ super.checkOptions();
+ }
+}
+
+/**
+ * This is an auxiliary class intended for <code>ArgumentHandler</code>.
+ * The following information is used by the <code>ArgumentHandler</code>
+ * for resolving features (i.e., JDI connectors and transport names)
+ * which are not implemented on given platform (the first column).
+ * This list is actual for JDK 1.3.x, 1.4.x, 1.5.0, 1.6.0.
+ *
+ * @see ArgumentHandler
+ */
+class CheckedFeatures {
+
+ static final String[][] notImplemented = {
+
+ // attaching connectors
+ /*
+ * From docs/technotes/guides/jpda/conninv.html:
+ * "
+ * This connector can be used by a debugger application to attach to
+ * a currently running target VM through the shared memory transport. It is
+ * available only on the Microsoft Windows platform.
+ * "
+ */
+ {"solaris-sparc", "com.sun.jdi.SharedMemoryAttach"},
+ {"solaris-sparcv9", "com.sun.jdi.SharedMemoryAttach"},
+ {"solaris-i586", "com.sun.jdi.SharedMemoryAttach"},
+ {"solaris-amd64", "com.sun.jdi.SharedMemoryAttach"},
+ {"solaris-x64", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-i586", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-ia64", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-amd64", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-x64", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-sparc", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-sparcv9", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-aarch64", "com.sun.jdi.SharedMemoryAttach"},
+ {"linux-arm", "com.sun.jdi.SharedMemoryAttach"},
+ {"macosx-amd64", "com.sun.jdi.SharedMemoryAttach"},
+ {"mac-x64", "com.sun.jdi.SharedMemoryAttach"},
+
+ // listening connectors
+ /*
+ * From docs/technotes/guides/jpda/conninv.html:
+ * "
+ * This connector can be used by a debugger application to accept a
+ * connection from a separately invoked target VM through the shared memory
+ * transport.
+ * It is available only on the Microsoft Windows platform.
+ * "
+ */
+ {"solaris-sparc", "com.sun.jdi.SharedMemoryListen"},
+ {"solaris-sparcv9", "com.sun.jdi.SharedMemoryListen"},
+ {"solaris-i586", "com.sun.jdi.SharedMemoryListen"},
+ {"solaris-amd64", "com.sun.jdi.SharedMemoryListen"},
+ {"solaris-x64", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-i586", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-ia64", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-amd64", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-x64", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-sparc", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-sparcv9", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-aarch64", "com.sun.jdi.SharedMemoryListen"},
+ {"linux-arm", "com.sun.jdi.SharedMemoryListen"},
+ {"macosx-amd64", "com.sun.jdi.SharedMemoryListen"},
+ {"mac-x64", "com.sun.jdi.SharedMemoryListen"},
+
+ // launching connectors
+ /*
+ * From docs/technotes/guides/jpda/conninv.html:
+ * "
+ * Sun Command Line Launching Connector
+ * This connector can be used by a debugger application to launch a
+ * Sun VM or any other VM which supports the same invocation options with
+ * respect to debugging. The details of launching the VM and specifying the
+ * necessary debug options are handled by the connector. The underlying
+ * transport used by this connector depends on the platform. On Microsoft
+ * Windows, the shared memory transport is used. On Solaris and Linux the
+ * socket transport is used.
+ * "
+ */
+ {"solaris-sparc", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"solaris-sparc", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"solaris-sparcv9", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"solaris-sparcv9", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"solaris-i586", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"solaris-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"solaris-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"solaris-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"solaris-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"solaris-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-i586", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-ia64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-sparc", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-sparc", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-sparcv9", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-sparcv9", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-aarch64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-aarch64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"linux-arm", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"linux-arm", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"windows-i586", "com.sun.jdi.CommandLineLaunch", "dt_socket"},
+ {"windows-i586", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"},
+
+ {"windows-ia64", "com.sun.jdi.CommandLineLaunch", "dt_socket"},
+ {"windows-ia64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"},
+
+ {"windows-amd64", "com.sun.jdi.CommandLineLaunch", "dt_socket"},
+ {"windows-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"},
+
+ {"windows-x64", "com.sun.jdi.CommandLineLaunch", "dt_socket"},
+ {"windows-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_socket"},
+
+ {"macosx-amd64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"macosx-amd64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ {"mac-x64", "com.sun.jdi.CommandLineLaunch", "dt_shmem"},
+ {"mac-x64", "com.sun.jdi.RawCommandLineLaunch", "dt_shmem"},
+
+ // shared memory transport is implemented only on windows platform
+ {"solaris-sparc", "dt_shmem"},
+ {"solaris-sparcv9", "dt_shmem"},
+ {"solaris-i586", "dt_shmem"},
+ {"solaris-amd64", "dt_shmem"},
+ {"solaris-x64", "dt_shmem"},
+ {"linux-i586", "dt_shmem"},
+ {"linux-ia64", "dt_shmem"},
+ {"linux-amd64", "dt_shmem"},
+ {"linux-x64", "dt_shmem"},
+ {"linux-sparc", "dt_shmem"},
+ {"linux-sparcv9", "dt_shmem"},
+ {"linux-aarch64", "dt_shmem"},
+ {"linux-arm", "dt_shmem"},
+ {"macosx-amd64", "dt_shmem"},
+ {"mac-x64", "dt_shmem"},
+ };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Binder.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1273 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import nsk.share.*;
+import nsk.share.jpda.*;
+
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+
+import com.sun.jdi.connect.Connector.Argument;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * This class provides debugger with connection to debugee VM
+ * using JDI connectors.
+ *<p>
+ * This class provides abilities to launch and bind to debugee VM
+ * as described for base <code>DebugeeBinder</code> class,
+ * using JDI connectors and <code>com.sun.VirtualMachine</code> mirror.
+ * <p>
+ * When <code>Binder</code> is asked to bind to debugee by invoking
+ * <code>bindToBebugee()</code> method it uses
+ * <code>com.sun.jdi.Connector</code> object corresponding to
+ * value of command line options <code>-connector</code> and
+ * <code>-transport</code> to launch and connect to debugee VM.
+ * After debugee is launched and connection is established
+ * <code>Binder</code> uses <code>com.sun.jdi.VirtualMachine</code>
+ * object to construct <code>Debugee</code> object, that
+ * provides abilities to interact with debugee VM.
+ *
+ * @see Debugee
+ * @see DebugeeBinder
+ */
+public class Binder extends DebugeeBinder {
+
+ /**
+ * Default message prefix for <code>Binder</code> object.
+ */
+ public static final String LOG_PREFIX = "binder> ";
+
+ /**
+ * Get version string.
+ */
+ public static String getVersion () {
+ return "@(#)Binder.java 1.14 03/10/08";
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Handler of command line arguments.
+ */
+ private ArgumentHandler argumentHandler = null;
+
+ /**
+ * Return <code>argumentHandler</code> of this binder.
+ */
+ public ArgumentHandler getArgumentHandler() {
+ return argumentHandler;
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Make <code>Binder</code> object and pass raw command line arguments.
+ *
+ * @deprecated Use newer
+ * <code>Binder(ArgumentHandler,Log)</code>
+ * constructor.
+ */
+ public Binder (String args[]) {
+ this(args, new Log(System.err));
+ }
+
+ /**
+ * Make <code>Binder</code> object for raw command line arguments
+ * and specified <code>log</code> object.
+ *
+ * @deprecated Use newer
+ * <code>Binder(ArgumentHandler,Log)</code>
+ * constructor.
+ */
+ public Binder (String args[], Log log) {
+ this(new ArgumentHandler(args), log);
+ }
+
+ /**
+ * Make <code>Binder</code> object for specified command line arguments
+ * and <code>log</code> object.
+ */
+ public Binder (ArgumentHandler argumentHandler, Log log) {
+ super(argumentHandler, log);
+ this.argumentHandler = argumentHandler;
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Make initial <code>Debugee</code> object for local debuggee process
+ * started with launching connector.
+ */
+ public Debugee makeLocalDebugee(Process process) {
+ LocalLaunchedDebugee debugee = new LocalLaunchedDebugee(process, this);
+
+ Finalizer finalizer = new Finalizer(debugee);
+ finalizer.activate();
+
+ return debugee;
+ }
+
+ /**
+ * Launch local debuggee process with specified command line
+ * and make initial <code>Debugee</code> object.
+ */
+ public Debugee startLocalDebugee(String cmd) {
+ Process process = null;
+
+ try {
+ process = launchProcess(cmd);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching local debuggee VM process:\n\t"
+ + e);
+ }
+
+ return makeLocalDebugee(process);
+ }
+
+ /**
+ * Make debuggee wrapper for already launched debuggee VM.
+ * After enwraping debugee's output is redirected to Binder's log,
+ * VMStartEvent is received and debuggee is initialized.
+ */
+ public Debugee enwrapDebugee(VirtualMachine vm, Process proc) {
+ Debugee debugee = makeLocalDebugee(proc);
+
+ display("Redirecting VM output");
+ debugee.redirectOutput(log);
+ debugee.setupVM(vm);
+
+ long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds
+
+ display("Waiting for VM initialized");
+ debugee.waitForVMInit(timeout);
+
+ return debugee;
+ }
+
+ /**
+ * Launch debugee VM and establish connection to it without waiting for VMStartEvent.
+ * After launching debugee's output is redirected to Binder's log,
+ * but VMStartEvent is not received and so debuggee is not fully initialized.
+ *
+ * @see #bindToDebugee(String)
+ */
+ public Debugee bindToDebugeeNoWait(String classToExecute) {
+
+ VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
+ display("VirtualMachineManager: version "
+ + vmm.majorInterfaceVersion() + "."
+ + vmm.minorInterfaceVersion());
+
+ Debugee debugee = null;
+
+ String classPath = null;
+// classPath = System.getProperty("java.class.path");
+
+ prepareForPipeConnection(argumentHandler);
+
+ if (argumentHandler.isLaunchedLocally()) {
+
+ if (argumentHandler.isDefaultConnector()) {
+ debugee = localDefaultLaunchDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isRawLaunchingConnector()) {
+ debugee = localRawLaunchDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isLaunchingConnector()) {
+ debugee = localLaunchDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isAttachingConnector()) {
+ debugee = localLaunchAndAttachDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isLaunchingConnector()) {
+ debugee = localLaunchDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isListeningConnector()) {
+ debugee = localLaunchAndListenDebugee(vmm, classToExecute, classPath);
+ } else {
+ throw new TestBug("Unexpected connector type for local debugee launch mode"
+ + argumentHandler.getConnectorType());
+ }
+
+ } else if (argumentHandler.isLaunchedRemotely()) {
+
+ connectToBindServer(classToExecute);
+
+ if (argumentHandler.isAttachingConnector()) {
+ debugee = remoteLaunchAndAttachDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isListeningConnector()) {
+ debugee = remoteLaunchAndListenDebugee(vmm, classToExecute, classPath);
+ } else {
+ throw new TestBug("Unexpected connector type for remote debugee launch mode"
+ + argumentHandler.getConnectorType());
+ }
+
+ } else if (argumentHandler.isLaunchedManually()) {
+
+ if (argumentHandler.isAttachingConnector()) {
+ debugee = manualLaunchAndAttachDebugee(vmm, classToExecute, classPath);
+ } else if (argumentHandler.isListeningConnector()) {
+ debugee = manualLaunchAndListenDebugee(vmm, classToExecute, classPath);
+ } else {
+ throw new TestBug("Unexpected connector type for manual debugee launch mode"
+ + argumentHandler.getConnectorType());
+ }
+
+ } else {
+ throw new Failure("Unexpected debugee launching mode: " + argumentHandler.getLaunchMode());
+ }
+
+ return debugee;
+ }
+
+ /**
+ * Launch debugee VM and establish JDI connection.
+ * After launching debugee's output is redirected to Binder's log,
+ * VMStart event is received and debuggee is initialized.
+ *
+ * @see #bindToDebugeeNoWait(String)
+ */
+ public Debugee bindToDebugee(String classToExecute) {
+ Debugee debugee = bindToDebugeeNoWait(classToExecute);
+
+ if(argumentHandler.getOptions().getProperty("traceAll") != null)
+ debugee.VM().setDebugTraceMode(VirtualMachine.TRACE_ALL);
+
+ long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds
+
+ display("Waiting for VM initialized");
+ debugee.waitForVMInit(timeout);
+
+ return debugee;
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Launch debugee locally via the default LaunchingConnector.
+ */
+ private Debugee localDefaultLaunchDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + "default" );
+ LaunchingConnector connector = vmm.defaultConnector();
+ Map<String,? extends Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);
+
+ VirtualMachine vm;
+ try {
+ display("Launching debugee");
+ vm = connector.launch(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
+ } catch (VMStartException e) {
+ e.printStackTrace(log.getOutStream());
+ String msg = readVMStartExceptionOutput(e, log.getOutStream());
+ throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\n" + msg);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
+ };
+
+ Process process = vm.process();
+ Debugee debugee = makeLocalDebugee(process);
+ debugee.redirectOutput(log);
+ debugee.setupVM(vm);
+
+ return debugee;
+ }
+
+
+ /**
+ * Launch debugee locally via the default LaunchingConnector.
+ */
+ private Debugee localLaunchDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ LaunchingConnector connector =
+ (LaunchingConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.launchingConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupLaunchingConnector(connector, classToExecute, classPath);
+
+ VirtualMachine vm;
+ try {
+ display("Launching debugee");
+ vm = connector.launch(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
+ } catch (VMStartException e) {
+ e.printStackTrace(log.getOutStream());
+ String msg = readVMStartExceptionOutput(e, log.getOutStream());
+ throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
+ };
+
+ Process process = vm.process();
+ Debugee debugee = makeLocalDebugee(process);
+ debugee.redirectOutput(log);
+ debugee.setupVM(vm);
+
+ return debugee;
+ }
+
+ /**
+ * Launch debugee locally via the RawLaunchingConnector.
+ */
+ private Debugee localRawLaunchDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ LaunchingConnector connector =
+ (LaunchingConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.launchingConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupRawLaunchingConnector(connector, classToExecute, classPath);
+
+ VirtualMachine vm;
+ try {
+ display("Launching debugee");
+ vm = connector.launch(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to launch debuggee VM:\n\t" + e);
+ } catch (VMStartException e) {
+ e.printStackTrace(log.getOutStream());
+ String msg = readVMStartExceptionOutput(e, log.getOutStream());
+ throw new Failure("Caught exception while starting debugee VM:\n\t" + e + "\nProcess output:\n\t" + msg);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching debugee VM:\n\t" + e);
+ };
+
+ Process process = vm.process();
+ Debugee debugee = makeLocalDebugee(process);
+ debugee.redirectOutput(log);
+ debugee.setupVM(vm);
+
+ return debugee;
+ }
+
+ /**
+ * Launch debugee VM locally as a local process and connect to it using
+ * <code>AttachingConnector</code>.
+ */
+ private Debugee localLaunchAndAttachDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("FindingConnector: " + argumentHandler.getConnectorName() );
+ AttachingConnector connector =
+ (AttachingConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.attachingConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
+
+ String address = makeTransportAddress();
+ String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+
+ display("Starting java process:\n\t" + javaCmdLine);
+ Debugee debugee = startLocalDebugee(cmdLineArgs);
+ debugee.redirectOutput(log);
+
+ display("Attaching to debugee");
+ VirtualMachine vm = null;
+ IOException ioe = null;
+ for (int i = 0; i < CONNECT_TRIES; i++) {
+ try {
+ vm = connector.attach(arguments);
+ display("Debugee attached");
+ debugee.setupVM(vm);
+ return debugee;
+ } catch (IOException e) {
+ display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);
+ ioe = e;
+ if (debugee.terminated()) {
+ throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
+ }
+ try {
+ Thread.currentThread().sleep(CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ + ie);
+ }
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
+ }
+ }
+ throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ + " tries:\n\t" + ioe);
+ }
+
+ /**
+ * Launch debugee VM locally as a local process and connect to it using
+ * <code>ListeningConnector</code>.
+ */
+ private Debugee localLaunchAndListenDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ ListeningConnector connector =
+ (ListeningConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.listeningConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
+
+ String address = null;
+ try {
+ display("Listening for connection from debugee");
+ address = connector.startListening(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);
+ };
+
+ String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+
+ display("Starting java process:\n\t" + javaCmdLine);
+ Debugee debugee = startLocalDebugee(cmdLineArgs);
+ debugee.redirectOutput(log);
+
+ display("Waiting for connection from debugee");
+ VirtualMachine vm = null;
+ IOException ioe = null;
+ for (int i = 0; i < CONNECT_TRIES; i++) {
+ try {
+ vm = connector.accept(arguments);
+ connector.stopListening(arguments);
+ display("Debugee attached");
+ debugee.setupVM(vm);
+ return debugee;
+ } catch (IOException e) {
+ display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);
+ ioe = e;
+ if (debugee.terminated()) {
+ throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
+ }
+ try {
+ Thread.currentThread().sleep(CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ + ie);
+ }
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
+ }
+ }
+ throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ + " tries:\n\t" + ioe);
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Launch debugee VM remotely via <code>BindServer</code> and connect to it using
+ * <code>AttachingConnector</code>.
+ */
+ private Debugee remoteLaunchAndAttachDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ AttachingConnector connector =
+ (AttachingConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.attachingConnectors());
+
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
+
+ String address = makeTransportAddress();
+ String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+
+ display("Starting remote java process:\n\t" + javaCmdLine);
+ Debugee debugee = startRemoteDebugee(cmdLineArgs);
+
+ display("Attaching to debugee");
+ VirtualMachine vm;
+ IOException ioe = null;
+ for (int i = 0; i < CONNECT_TRIES; i++) {
+ try {
+ vm = connector.attach(arguments);
+ display("Debugee attached");
+ debugee.setupVM(vm);
+ return debugee;
+ } catch (IOException e) {
+ display("Attempt #" + i + " to connect to debugee VM failed:\n\t" + e);
+ ioe = e;
+ if (debugee.terminated()) {
+ throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
+ }
+ try {
+ Thread.currentThread().sleep(CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ + ie);
+ }
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
+ }
+ }
+ throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ + " tries:\n\t" + ioe);
+ }
+
+ /**
+ * Launch debugee VM remotely via <code>BindServer</code> and connect to it using
+ * <code>ListeningConnector</code>.
+ */
+ private Debugee remoteLaunchAndListenDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ ListeningConnector connector =
+ (ListeningConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.listeningConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
+
+ String address = null;
+ try {
+ display("Listening for connection from debugee");
+ address = connector.startListening(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while starting listening debugee VM:\n\t" + e);
+ };
+
+ String[] cmdLineArgs = makeCommandLineArgs(classToExecute, address);
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+
+ display("Starting remote java process:\n\t" + javaCmdLine);
+ Debugee debugee = startRemoteDebugee(cmdLineArgs);
+
+ display("Waiting for connection from debugee");
+ VirtualMachine vm;
+ IOException ioe = null;
+ for (int i = 0; i < CONNECT_TRIES; i++) {
+ try {
+ vm = connector.accept(arguments);
+ connector.stopListening(arguments);
+ display("Debugee attached");
+ debugee.setupVM(vm);
+ return debugee;
+ } catch (IOException e) {
+ display("Attempt #" + i + " to listen debugee VM failed:\n\t" + e);
+ ioe = e;
+ if (debugee.terminated()) {
+ throw new Failure("Unable to connect to debuggee VM: VM process is terminated");
+ }
+ try {
+ Thread.currentThread().sleep(CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Thread interrupted while pausing connection attempts:\n\t"
+ + ie);
+ }
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
+ }
+ }
+ throw new Failure("Unable to connect to debugee VM after " + CONNECT_TRIES
+ + " tries:\n\t" + ioe);
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Prompt to manually launch debugee VM and connect to it using
+ * <code>AttachingConnector</code>.
+ */
+ private Debugee manualLaunchAndAttachDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ AttachingConnector connector =
+ (AttachingConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.attachingConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupAttachingConnector(connector, classToExecute, classPath);
+
+ String address = makeTransportAddress();
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+
+ display("Starting manual java process:\n\t" + javaCmdLine);
+ ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);
+
+ VirtualMachine vm;
+ try {
+ display("Attaching to debugee");
+ vm = connector.attach(arguments);
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to attach to debuggee VM:\n\t" + e);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while attaching to debugee VM:\n\t" + e);
+ };
+ display("Debugee attached");
+
+ debugee.setupVM(vm);
+ return debugee;
+ }
+
+ /**
+ * Prompt to manually launch debugee VM and connect to it using
+ * <code>ListeningConnector</code>.
+ */
+ private Debugee manualLaunchAndListenDebugee (VirtualMachineManager vmm,
+ String classToExecute,
+ String classPath) {
+ display("Finding connector: " + argumentHandler.getConnectorName() );
+ ListeningConnector connector =
+ (ListeningConnector) findConnector(argumentHandler.getConnectorName(),
+ vmm.listeningConnectors());
+ Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = setupListeningConnector(connector, classToExecute, classPath);
+
+ VirtualMachine vm;
+ try {
+ display("Listening for connection from debugee");
+ String address = connector.startListening(arguments);
+ String javaCmdLine = makeCommandLineString(classToExecute, address, "\"");
+ display("Starting manual java process:\n\t" + javaCmdLine);
+ ManualLaunchedDebugee debugee = startManualDebugee(javaCmdLine);
+ display("Waiting for connection from debugee");
+ vm = connector.accept(arguments);
+ display("Debugee attached");
+ connector.stopListening(arguments);
+ debugee.setupVM(vm);
+ return debugee;
+ } catch (IllegalConnectorArgumentsException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Wrong connector arguments used to listen debuggee VM:\n\t" + e);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while listening to debugee VM:\n\t" + e);
+ }
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Make proper arguments for LaunchingConnector.
+ */
+ private Map<String,? extends Argument> setupLaunchingConnector(LaunchingConnector connector,
+ String classToExecute,
+ String classPath) {
+ display("LaunchingConnector:");
+ display(" name: " + connector.name());
+ display(" description: " + connector.description());
+ display(" transport: " + connector.transport());
+
+ Hashtable<String,? extends Argument> arguments = new Hashtable<String,Argument>(connector.defaultArguments());
+
+ Connector.Argument arg;
+
+ arg = (Connector.StringArgument) arguments.get("quote");
+ String quote = arg.value();
+
+ String cmdline = classToExecute + " " +
+ ArgumentHandler.joinArguments(argumentHandler.getRawArguments(), quote);
+
+ arg = (Connector.StringArgument) arguments.get("main");
+ arg.setValue(cmdline);
+
+ if (! argumentHandler.willDebugeeSuspended()) {
+ Connector.BooleanArgument barg = (Connector.BooleanArgument) arguments.get("suspend");
+ barg.setValue(true);
+ }
+
+/*
+ if (! argumentHandler.isJVMDIStrictMode()) {
+ arg = (Connector.StringArgument) arguments.get("options");
+ arg.setValue("strict=y");
+ }
+ */
+
+ if (! argumentHandler.isDefaultDebugeeJavaHome()) {
+ arg = (Connector.StringArgument) arguments.get("home");
+ arg.setValue(argumentHandler.getDebugeeJavaHome());
+ }
+
+ if (! argumentHandler.isDefaultLaunchExecName()) {
+ arg = (Connector.StringArgument) arguments.get("vmexec");
+ arg.setValue(argumentHandler.getLaunchExecName());
+ }
+
+ String vmArgs = "";
+
+ String vmUserArgs = argumentHandler.getLaunchOptions();
+
+ if (vmUserArgs != null) {
+ vmArgs = vmUserArgs;
+ }
+
+/*
+ if (classPath != null) {
+ vmArgs += " -classpath " + quote + classPath + quote;
+ }
+ */
+
+ if (vmArgs.length() > 0) {
+ arg = (Connector.StringArgument) arguments.get("options");
+ arg.setValue(vmArgs);
+ }
+
+ display("Connector arguments:");
+ Iterator iterator = arguments.values().iterator();
+ while (iterator.hasNext()) {
+ display(" " + iterator.next());
+ }
+ return arguments;
+ }
+
+ /**
+ * Make proper arguments for RawLaunchingConnector.
+ */
+ private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupRawLaunchingConnector(LaunchingConnector connector,
+ String classToExecute,
+ String classPath) {
+ display("RawLaunchingConnector:");
+ display(" name: " + connector.name());
+ display(" description: " + connector.description());
+ display(" transport: " + connector.transport());
+
+ Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String, com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
+
+ String connectorAddress;
+ String vmAddress;
+
+ if (argumentHandler.isSocketTransport()) {
+ connectorAddress = argumentHandler.getTransportPort();
+ vmAddress = argumentHandler.getDebugeeHost()
+ + ":" + argumentHandler.getTransportPort();
+ } else if (argumentHandler.isShmemTransport() ) {
+ connectorAddress = argumentHandler.getTransportSharedName();
+ vmAddress=connectorAddress;
+ } else {
+ throw new TestBug("Undefined transport type for AttachingConnector");
+ }
+
+ Connector.Argument arg;
+
+ arg = (Connector.StringArgument) arguments.get("quote");
+ String quote = arg.value();
+
+ String javaCmdLine = makeCommandLineString(classToExecute, quote);
+
+ arg = (Connector.StringArgument) arguments.get("command");
+ arg.setValue(javaCmdLine);
+
+ arg = (Connector.StringArgument) arguments.get("address");
+ arg.setValue(connectorAddress);
+
+ display("Connector arguments:");
+ Iterator iterator = arguments.values().iterator();
+ while (iterator.hasNext()) {
+ display(" " + iterator.next());
+ }
+ return arguments;
+ }
+
+ /**
+ * Make proper arguments for AttachingConnector.
+ */
+ private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupAttachingConnector(AttachingConnector connector,
+ String classToExecute,
+ String classPath) {
+ display("AttachingConnector:");
+ display(" name: " + connector.name());
+ display(" description: " + connector.description());
+ display(" transport: " + connector.transport());
+
+ Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
+
+ Connector.Argument arg;
+ if (argumentHandler.isSocketTransport()) {
+ arg = (Connector.StringArgument) arguments.get("hostname");
+ arg.setValue(argumentHandler.getDebugeeHost());
+ Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");
+ iarg.setValue(argumentHandler.getTransportPortNumber());
+ } else {
+ arg = (Connector.StringArgument) arguments.get("name");
+ arg.setValue(argumentHandler.getTransportSharedName());
+ }
+
+ display("Connector arguments:");
+ Iterator iterator = arguments.values().iterator();
+ while (iterator.hasNext()) {
+ display(" " + iterator.next());
+ }
+ return arguments;
+ }
+
+ /**
+ * Make proper arguments for ListeningConnector.
+ */
+ private Map<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> setupListeningConnector(ListeningConnector connector,
+ String classToExecute,
+ String classPath) {
+ display("ListeningConnector:");
+ display(" name: " + connector.name());
+ display(" description: " + connector.description());
+ display(" transport: " + connector.transport());
+
+ Hashtable<java.lang.String,? extends com.sun.jdi.connect.Connector.Argument> arguments = new Hashtable<java.lang.String,com.sun.jdi.connect.Connector.Argument>(connector.defaultArguments());
+
+ Connector.Argument arg;
+ if (argumentHandler.isSocketTransport()) {
+ if (!argumentHandler.isTransportAddressDynamic()) {
+ int port = argumentHandler.getTransportPortNumber();
+ Connector.IntegerArgument iarg = (Connector.IntegerArgument) arguments.get("port");
+ iarg.setValue(port);
+ }
+ } else {
+ String sharedName = argumentHandler.getTransportSharedName();
+ arg = (Connector.StringArgument) arguments.get("name");
+ arg.setValue(sharedName);
+ }
+
+ display("Connector arguments:");
+ Iterator iterator = arguments.values().iterator();
+ while (iterator.hasNext()) {
+ display(" " + iterator.next());
+ }
+ return arguments;
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Find connector by name from given connectors list.
+ */
+ private Connector findConnector(String connectorName, List connectors) {
+ Iterator iter = connectors.iterator();
+
+ while (iter.hasNext()) {
+ Connector connector = (Connector) iter.next();
+ if (connector.name().equals(connectorName)) {
+ return connector;
+ }
+ }
+ throw new Failure("JDI connector not found: " + connectorName);
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Launch local debuggee process with specified command line arguments
+ * and make initial <code>Debugee</code> mirror.
+ */
+ protected Debugee startLocalDebugee(String[] cmdArgs) {
+ Process process = null;
+
+ try {
+ process = launchProcess(cmdArgs);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching local debuggee VM process:\n\t"
+ + e);
+ }
+
+ return makeLocalDebugee(process);
+ }
+
+ /**
+ * Launch remote debuggee process with specified command line arguments
+ * and make initial <code>Debugee</code> mirror.
+ */
+ protected RemoteLaunchedDebugee startRemoteDebugee(String[] cmdArgs) {
+ try {
+ launchRemoteProcess(cmdArgs);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while launching remote debuggee VM process:\n\t"
+ + e);
+ }
+
+ RemoteLaunchedDebugee debugee = new RemoteLaunchedDebugee(this);
+
+ Finalizer finalizer = new Finalizer(debugee);
+ finalizer.activate();
+
+ return debugee;
+ }
+
+ /**
+ * Launch manual debuggee process with specified command line arguments
+ * and make initial <code>Debugee</code> mirror.
+ */
+ protected ManualLaunchedDebugee startManualDebugee(String cmd) {
+ ManualLaunchedDebugee debugee = new ManualLaunchedDebugee(this);
+ debugee.launchDebugee(cmd);
+
+ Finalizer finalizer = new Finalizer(debugee);
+ finalizer.activate();
+
+ return debugee;
+ }
+
+ public static String readVMStartExceptionOutput(VMStartException e, PrintStream log) {
+ StringBuffer msg = new StringBuffer();
+ try (InputStream is = e.process().getInputStream()) {
+ msg.append("\tstdout: ").append(new String(readAllBytes(is))).append('\n');
+ } catch (IOException e1) {
+ log.println("Could not read normal output from launched process:" + e1);
+ }
+ try (InputStream is = e.process().getErrorStream()) {
+ msg.append("\tstderr: ").append(new String(readAllBytes(is)));
+ } catch (IOException e1) {
+ log.println("Could not read error output from launched process:" + e1);
+ }
+ return msg.toString();
+ }
+
+ /**
+ * Copied from the JDK 9 implementation in InputStream.java
+ */
+ private static byte[] readAllBytes(InputStream is) throws IOException {
+ final int DEFAULT_BUFFER_SIZE = 8192;
+ final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+ byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
+ int capacity = buf.length;
+ int nread = 0;
+ int n;
+ for (;;) {
+ // read to EOF which may read more or less than initial buffer size
+ while ((n = is.read(buf, nread, capacity - nread)) > 0)
+ nread += n;
+
+ // if the last call to read returned -1, then we're done
+ if (n < 0)
+ break;
+
+ // need to allocate a larger buffer
+ if (capacity <= MAX_BUFFER_SIZE - capacity) {
+ capacity = capacity << 1;
+ } else {
+ if (capacity == MAX_BUFFER_SIZE)
+ throw new OutOfMemoryError("Required array size too large");
+ capacity = MAX_BUFFER_SIZE;
+ }
+ buf = Arrays.copyOf(buf, capacity);
+ }
+ return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+ }
+
+}
+
+
+/**
+ * Mirror of locally launched debugee.
+ */
+final class LocalLaunchedDebugee extends Debugee {
+
+ /** Enwrap the locally started VM process. */
+ public LocalLaunchedDebugee (Process process, Binder binder) {
+ super(binder);
+ this.process = process;
+ checkTermination = true;
+ }
+
+ // ---------------------------------------------- //
+
+ /** Return exit status of the debugee VM. */
+ public int getStatus () {
+ return process.exitValue();
+ }
+
+ /** Check whether the debugee VM has been terminated. */
+ public boolean terminated () {
+ if (process == null)
+ return true;
+
+ try {
+ int value = process.exitValue();
+ return true;
+ } catch (IllegalThreadStateException e) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------- //
+
+ /** Kill the debugee VM. */
+ protected void killDebugee () {
+ super.killDebugee();
+ if (!terminated()) {
+ log.display("Killing debugee VM process");
+ process.destroy();
+ }
+ }
+
+ /** Wait until the debugee VM shutdown or crash. */
+ protected int waitForDebugee () throws InterruptedException {
+ int code = process.waitFor();
+ return code;
+ }
+
+ /** Get a pipe to write to the debugee's stdin stream. */
+ protected OutputStream getInPipe () {
+ return process.getOutputStream();
+ }
+
+ /** Get a pipe to read the debugee's stdout stream. */
+ protected InputStream getOutPipe () {
+ return process.getInputStream();
+ }
+
+ /** Get a pipe to read the debugee's stderr stream. */
+ protected InputStream getErrPipe () {
+ return process.getErrorStream();
+ }
+}
+
+
+/**
+ * Mirror of remotely launched debugee.
+ */
+final class RemoteLaunchedDebugee extends Debugee {
+
+ /** Enwrap the remotely started VM process. */
+ public RemoteLaunchedDebugee (Binder binder) {
+ super(binder);
+ }
+
+ // ---------------------------------------------- //
+
+ /** Return exit status of the debugee VM. */
+ public int getStatus () {
+ return binder.getRemoteProcessStatus();
+ }
+
+ /** Check whether the debugee VM has been terminated. */
+ public boolean terminated () {
+ return binder.isRemoteProcessTerminated();
+ }
+
+ // ---------------------------------------------- //
+
+ /** Kill the debugee VM. */
+ protected void killDebugee () {
+ super.killDebugee();
+ if (!terminated()) {
+ binder.killRemoteProcess();
+ }
+ }
+
+ /** Wait until the debugee VM shutdown or crash. */
+ protected int waitForDebugee () {
+ return binder.waitForRemoteProcess();
+ }
+
+ /** Get a pipe to write to the debugee's stdin stream. */
+ protected OutputStream getInPipe () {
+ return null;
+ }
+
+ /** Get a pipe to read the debugee's stdout stream. */
+ protected InputStream getOutPipe () {
+ return null;
+ }
+
+ /** Get a pipe to read the debugee's stderr stream. */
+ protected InputStream getErrPipe () {
+ return null;
+ }
+
+ public void redirectStdout(OutputStream out) {
+ }
+
+ public void redirectStdout(Log log, String prefix) {
+ }
+
+ public void redirectStderr(OutputStream out) {
+ }
+
+ public void redirectStderr(Log log, String prefix) {
+ }
+}
+
+
+/**
+ * Mirror of manually launched debugee.
+ */
+final class ManualLaunchedDebugee extends Debugee {
+ /** Enwrap the manually started VM process. */
+ public ManualLaunchedDebugee (Binder binder) {
+ super(binder);
+ makeInputReader();
+ }
+
+ // ---------------------------------------------- //
+
+ private int exitCode = 0;
+ private boolean finished = false;
+ private static BufferedReader bin = null;
+
+ public void launchDebugee(String commandLine) {
+ makeInputReader();
+
+ putMessage("Launch target VM using such command line:\n"
+ + commandLine);
+ String answer = askQuestion("Has the VM successfully started? (yes/no)", "yes");
+ for ( ; ; ) {
+ if (answer.equals("yes"))
+ break;
+ if (answer.equals("no"))
+ throw new Failure ("Unable to manually launch debugee VM");
+ answer = askQuestion("Wrong answer. Please type yes or no", "yes");
+ }
+ }
+
+ private static void makeInputReader() {
+ if (bin == null) {
+ bin = new BufferedReader(new InputStreamReader(System.in));
+ }
+ }
+
+ private static void destroyInputReader() {
+ if (bin != null) {
+ try {
+ bin.close();
+ } catch (IOException e) {
+// e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while closing input stream:\n\t" + e);
+ }
+ bin = null;
+ }
+ }
+
+ private static void putMessage(String msg) {
+ System.out.println("\n>>> " + msg);
+ }
+
+ private static String askQuestion(String question, String defaultAnswer) {
+ try {
+ System.out.print("\n>>> " + question);
+ System.out.print(" [" + defaultAnswer + "] ");
+ System.out.flush();
+ String answer = bin.readLine();
+ if (answer.equals(""))
+ return defaultAnswer;
+ return answer;
+ } catch (IOException e) {
+// e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while reading answer:\n\t" + e);
+ }
+ }
+
+ /** Return exit status of the debugee VM. */
+ public int getStatus () {
+ if (! finished) {
+ throw new Failure("Unable to get status of debugee VM: process still alive");
+ }
+ return exitCode;
+ }
+
+ /** Check whether the debugee VM has been terminated. */
+ public boolean terminated () {
+ return finished;
+ }
+
+ // ---------------------------------------------- //
+
+ /** Kill the debugee VM. */
+ protected void killDebugee () {
+ super.killDebugee();
+ if (!terminated()) {
+ putMessage("Kill launched VM");
+ String answer = askQuestion("Has the VM successfully terminated? (yes/no)", "yes");
+ for ( ; ; ) {
+ if (answer.equals("yes")) {
+ finished = true;
+ break;
+ }
+ if (answer.equals("no"))
+ throw new Failure ("Unable to manually kill debugee VM");
+ answer = askQuestion("Wrong answer. Please type yes or no", "yes");
+ }
+ }
+ }
+
+ /** Wait until the debugee VM shutdown or crash. */
+ protected int waitForDebugee () {
+ putMessage("Wait for launched VM to exit.");
+ String answer = askQuestion("What is VM exit code?", "95");
+ for ( ; ; ) {
+ try {
+ exitCode = Integer.parseInt(answer);
+ break;
+ } catch (NumberFormatException e) {
+ answer = askQuestion("Wrong answer. Please type integer value", "95");
+ }
+ }
+ finished = true;
+ return exitCode;
+ }
+
+ /** Get a pipe to write to the debugee's stdin stream. */
+ protected OutputStream getInPipe () {
+ return null;
+ }
+
+ /** Get a pipe to read the debugee's stdout stream. */
+ protected InputStream getOutPipe () {
+ return null;
+ }
+
+ /** Get a pipe to read the debugee's stderr stream. */
+ protected InputStream getErrPipe () {
+ return null;
+ }
+
+ public void redirectStdout(OutputStream out) {
+ }
+
+ public void redirectStdout(Log log, String prefix) {
+ }
+
+ public void redirectStderr(OutputStream out) {
+ }
+
+ public void redirectStderr(Log log, String prefix) {
+ }
+
+ public void close() {
+ destroyInputReader();
+ super.close();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ConnectorTest.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import com.sun.jdi.connect.*;
+import com.sun.jdi.*;
+import java.io.*;
+import java.util.*;
+
+import nsk.share.*;
+import nsk.share.jpda.*;
+
+/*
+ * This class contains several common methods used by connector tests.
+ */
+public abstract class ConnectorTest {
+ protected Log log;
+
+ protected VirtualMachine vm;
+
+ protected int attempts; // attempts to connect to the debuggee VM
+
+ protected int delay; // delay between connection attempts
+
+ protected IORedirector outRedirector;
+
+ protected IORedirector errRedirector;
+
+ protected ArgHandler argHandler;
+
+ protected boolean isTestFailed;
+
+ // set test status 'FAILED'
+ protected void testFailed() {
+ isTestFailed = true;
+ }
+
+ // check if tested functionality implemented on current platform
+ protected boolean shouldPass() {
+ return argHandler.shouldPass(getConnectorName());
+ }
+
+ abstract protected void doTest();
+
+ abstract protected String getConnectorName();
+
+ abstract protected String getDebuggeeClass();
+
+ static public class ArgHandler extends ArgumentHandler {
+ public ArgHandler(String[] args) {
+ super(args);
+
+ }
+
+ protected boolean checkOption(String option, String value) {
+ if (super.checkOption(option, value))
+ return true;
+
+ if (option.equals("testWorkDir"))
+ return true;
+
+ if (option.equals("waitVMStartEvent"))
+ return true;
+
+ return false;
+ }
+
+ public String getTestWorkDir() {
+ String dir = options.getProperty("testWorkDir");
+
+ if (dir.endsWith(File.separator)) {
+ dir = dir.substring(0, dir.length() - 1);
+ }
+
+ return dir;
+ }
+
+ public boolean waitVMStartEvent() {
+ return options.containsKey("waitVMStartEvent");
+ }
+ }
+
+ /*
+ * Subclasses can provide another ArgumentHandlers
+ */
+ protected ArgHandler createArgumentHandler(String[] args) {
+ return new ArgHandler(args);
+ }
+
+ protected void init(String[] args, PrintStream out) {
+ argHandler = createArgumentHandler(args);
+
+ log = new Log(out, argHandler);
+
+ delay = argHandler.getConnectionDelay();
+
+ // calculate number of connection attempts to not exceed WAITTIME
+ long timeout = argHandler.getWaitTime() * 60 * 1000;
+ attempts = (int) (timeout / delay);
+ }
+
+ protected int runIt(String argv[], PrintStream out) {
+ try {
+ init(argv, out);
+
+ if (shouldPass()) {
+ log.display("Tested functionality isn't implemented on this platform. Treat test as passed.");
+ return Consts.TEST_PASSED;
+ }
+
+ doTest();
+
+ if (isTestFailed)
+ return Consts.TEST_FAILED;
+ else
+ return Consts.TEST_PASSED;
+
+ } catch (Throwable t) {
+ out.println("Unexpected exception: " + t);
+ t.printStackTrace(out);
+ return Consts.TEST_FAILED;
+ }
+ }
+
+ protected void waitForVMInit(VirtualMachine vm) {
+ Debugee.waitForVMInit(vm, log, argHandler.getWaitTime() * 60 * 1000);
+ }
+
+ // set connector argument value with given name
+ protected void setConnectorArg(Map<String, Connector.Argument> args, String argName, String value) {
+ for (String key : args.keySet()) {
+ Connector.Argument arg = args.get(key);
+ if (arg.name().equals(argName)) {
+ arg.setValue(value);
+ return;
+ }
+ }
+
+ throw new Error("There is no argument '" + argName + "'");
+ }
+
+ // try attach to target VM using attaching connector
+ protected VirtualMachine tryAttach(AttachingConnector connector, Map<String, Connector.Argument> cArgs) {
+ // make several attempts to connect to the debuggee VM until WAITTIME exceeds
+ for (int i = 0; i < attempts; i++) {
+ try {
+ return connector.attach(cArgs);
+ } catch (IOException e) {
+ // could not connect; sleep a few and make new attempt
+ log.display("Connection attempt #" + i + " failed: " + e);
+ e.printStackTrace(log.getOutStream());
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException ie) {
+ testFailed();
+ log.complain("TEST INCOMPLETE: interrupted sleep: " + ie);
+ ie.printStackTrace(log.getOutStream());
+ }
+ } catch (IllegalConnectorArgumentsException e) {
+ testFailed();
+ log.complain("TEST: Illegal connector arguments: " + e.getMessage());
+ return null;
+ } catch (Exception e) {
+ testFailed();
+ log.complain("TEST: Internal error: " + e.getMessage());
+ e.printStackTrace(log.getOutStream());
+ return null;
+ }
+ }
+
+ testFailed();
+ // return null after all attempts failed
+ log.complain("FAILURE: all attempts to connect to the debuggee VM failed");
+ return null;
+ }
+
+ // try find connector with given name
+ protected Connector findConnector(String connectorName) {
+ List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors();
+ Iterator<Connector> iter = connectors.iterator();
+
+ while (iter.hasNext()) {
+ Connector connector = (Connector) iter.next();
+ if (connector.name().equals(connectorName)) {
+ log.display("Connector name=" + connector.name() + "\n\tdescription=" + connector.description() + "\n\ttransport="
+ + connector.transport().name());
+ return connector;
+ }
+ }
+ throw new Error("No appropriate connector");
+ }
+
+ // wait when debuggee process finishes and check exit code
+ protected void waitDebuggeeExit(Debugee debuggee) {
+ log.display("\nwaiting for debuggee VM exit");
+ int code = debuggee.waitFor();
+ if (code != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) {
+ testFailed();
+ log.complain("Debuggee VM has crashed: exit code=" + code);
+ return;
+ }
+ log.display("debuggee VM: exit code=" + code);
+ }
+
+ // wait 'READY' command from debuggee VM (this method is used by debuggers establishing socket connection with debuggee VM)
+ protected boolean waitReadyCommand(IOPipe pipe) {
+ String command = pipe.readln();
+ log.display("Command: " + command);
+
+ if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) {
+ testFailed();
+ log.complain("Unexpected debuggee answer: " + command + ", expected is " + AbstractDebuggeeTest.COMMAND_READY);
+ return false;
+ }
+
+ return true;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import nsk.share.*;
+import nsk.share.jpda.*;
+
+import com.sun.jdi.*;
+import com.sun.jdi.request.*;
+import com.sun.jdi.event.*;
+
+import java.util.*;
+
+/**
+ * This class is used to interact with debugee VM using JDI features.
+ * <p>
+ * This class is wrapper for debugee VM constructed by <code>Binder</code>
+ * and it uses <code>com.sun.jdi.VirtualMachine</code> to interact with debugee VM.
+ * <p>
+ * In addition to the general abities to control of debugee VM process,
+ * provided by the base class <code>DebugeeProcess</code>, this class
+ * adds also several service methods over the JDI features to simplify interaction
+ * with debugee VM (such as finding classes, setting breakpoints,
+ * handling events, and so on.).
+ *
+ * @see Binder
+ * @see DebugeeProcess
+ */
+abstract public class Debugee extends DebugeeProcess {
+ /**
+ * Mirror of the debugee VM. This must be initialized by every
+ * particular non-abstract class extending Debugee class.
+ */
+ protected VirtualMachine vm = null;
+
+ /** Binder that created this debugee. */
+ protected Binder binder = null;
+
+ /** Argument handler. */
+ protected ArgumentHandler argumentHandler = null;
+
+ /** Create new <code>Debugee</code> object for a given binder. */
+ protected Debugee (Binder binder) {
+ super(binder);
+ this.binder = binder;
+ this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler();
+ }
+
+ /** Setup <code>Debugee</code> object with given VM mirror. */
+ public void setupVM(VirtualMachine vm) {
+ if (this.vm != null) {
+ throw new TestBug("Setting duplicated VM mirror for Debugee object");
+ }
+ this.vm = vm;
+ int traceMode = argumentHandler.getTraceMode();
+ if (traceMode != VirtualMachine.TRACE_NONE) {
+ display("Setting JDI trace mode to: " + argumentHandler.getTraceModeString());
+ setDebugTraceMode(traceMode);
+ }
+ }
+
+ /** Return <code>Binder</code> of the debugee object. */
+ public Binder getBinder() {
+ return binder;
+ }
+
+ /** Return JDI mirror of the debugee VM. */
+ public VirtualMachine VM() {
+ return vm;
+ }
+
+ /** Return <code>EventRequestManager</code> of the debugee object. */
+ public EventRequestManager getEventRequestManager() {
+ return vm.eventRequestManager();
+ }
+
+ // --------------------------------------------------- //
+
+ /** List of the currently running threads. */
+ public ThreadReference[] threads () {
+ List list = vm.allThreads();
+ int size = list.size();
+ ThreadReference array[] = new ThreadReference[size];
+ Iterator iterator = list.iterator();
+ for (int i = 0; i < size; i++)
+ array[i] = (ThreadReference) iterator.next();
+ if (iterator.hasNext())
+ throw new Oddity("extra element in a list?");
+ return array;
+ }
+
+ /** List of all types loaded by the debugee VM. */
+ public ReferenceType[] classes() {
+ return classes(null);
+ }
+
+ /**
+ * List of all classes of the given <code>name</code> loaded by
+ * the debugee VM; or list of all classes, if <code>name</code>
+ * is <code>null</code>.
+ */
+ private ReferenceType[] classes (String name) {
+ List list = (name==null)? vm.allClasses(): vm.classesByName(name);
+ int size = list.size();
+ ReferenceType array[] = new ReferenceType [ size ];
+ Iterator iterator = list.iterator();
+ for (int i=0; i<size; i++)
+ array[i] = (ReferenceType) iterator.next();
+ if (iterator.hasNext())
+ throw new Oddity("extra element in a list?");
+ return array;
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Return mirror for the only class of the given <code>name</code>
+ * loaded by the debugee VM; or throw TestBug exception if there
+ * are more than one such class found. TestFailure exception
+ * will be thrown in case when mirrors for classes with different
+ * names or duplicated mirrors were returned.
+ * Return <code>null</code> if there is no such class loaded.
+ */
+ public ReferenceType classByName (String name) {
+ ReferenceType classes[] = this.classes(name);
+
+ // if on first call debuggee doesn't return needed class try get this class one more time after delay to avoid 6446633
+ if (classes == null || classes.length == 0) {
+ try {
+ Thread.sleep(1000);
+ }
+ catch(InterruptedException e) {
+ throw new TestBug("Unexpected InterruptedException");
+ }
+
+ classes = this.classes(name);
+ }
+
+ if (classes == null || classes.length == 0)
+ return null;
+
+ // analyze returned mirrors and throw appropriate exception
+ if (classes.length > 1) {
+ boolean duplicatesFound = false;
+ boolean differentNamesFound = false;
+ boolean visited[] = new boolean[classes.length];
+ complain("Classes that were found for name \"" + name + "\":");
+ for(ReferenceType klass : classes) {
+ complain("\t" + klass);
+ }
+ for(int c = 0; c < classes.length; c++) {
+ if(visited[c]) {
+ continue;
+ }
+ if(!classes[c].name().equals(name)) {
+ differentNamesFound = true;
+ continue;
+ }
+ for(int i = c + 1; i < classes.length; i++) {
+ if(visited[i]) {
+ continue;
+ } else {
+ visited[i] = true;
+ }
+ if(classes[c].classLoader() == classes[i].classLoader()) {
+ duplicatesFound = true;
+ }
+ }
+ }
+ if(duplicatesFound) {
+ throw new TestFailure("classes with the same name and " +
+ "loaded with the same class loader " +
+ "were found.");
+ } else if(differentNamesFound) {
+ throw new TestFailure("class with name different from '" + name +
+ "' was returned by VirutualMachine.classesByName.");
+ } else {
+ throw new TestBug("found " + classes.length + " such classes: " + name);
+ }
+ }
+ return classes[0];
+ }
+
+ /**
+ * Return mirror for the only method of the given <code>refType</code>
+ * class in the debugee VM; or throw TestBug exception if there
+ * are more than one such method found. Return <code>null</code> if
+ * there is no such method found.
+ */
+ public Method methodByName(ReferenceType refType, String name) {
+ List methods = refType.methodsByName(name);
+ if (methods == null || methods.isEmpty()) return null;
+ if (methods.size() > 1)
+ throw new TestBug(
+ "found " + methods.size() + " such methods: " + name);
+ Method method = (Method)methods.get(0);
+ return method;
+ }
+
+ /**
+ * Return a currently running thread of the given <code>name</code>; or
+ * throw TestBug exception if there are more than one such thread found.
+ * Return <code>null</code> if there is no such thread.
+ */
+ public ThreadReference threadByName (String name) {
+ ThreadReference threads[] = this.threads();
+ int count = 0, index = -1;
+ for (int i = 0; i < threads.length; i++) {
+ if (threads[i].name().compareTo(name)==0) {
+ count++;
+ index = i;
+ }
+ }
+ if (count == 0)
+ return null;
+ if (count > 1)
+ throw new TestBug(
+ "found " + count + " such threads: " + name);
+ return threads[index];
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Returns Location object for given line number in specified method or null
+ * if no location for this line is found.
+ *
+ * @param method method mirror containing given line number
+ * @param line line number to find location
+ */
+ public Location getLineLocation(Method method, int line) {
+ List locs = null;
+ try {
+ locs = method.allLineLocations();
+ } catch(AbsentInformationException e) {
+ throw new TestBug("Unable to find location for line " + line + ": " + e);
+ }
+ Iterator iter = locs.iterator();
+ while (iter.hasNext()) {
+ Location location = (Location)iter.next();
+ if (location.lineNumber() == line) {
+ return location;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns Location object for given line number in specified reference type or null
+ * if no location for this line is found.
+ *
+ * @param refType reference type mirror containing given line number
+ * @param line line number to find location
+ */
+ public Location getLineLocation(ReferenceType refType, int line) {
+ List locs = null;
+ try {
+ locs = refType.allLineLocations();
+ } catch(AbsentInformationException e) {
+ throw new TestBug("Unable to find location for line " + line + ": " + e);
+ }
+ Iterator iter = locs.iterator();
+ while (iter.hasNext()) {
+ Location location = (Location)iter.next();
+ if (location.lineNumber() == line) {
+ return location;
+ }
+ }
+ return null;
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Make disabled breakpoint to given location and return BreakpointRequest.
+ *
+ * @param location location to set breakpoint
+ *
+ * @see #setBreakpoint(Method, int)
+ * @see #setBreakpoint(ReferenceType, String, int)
+ */
+ public BreakpointRequest makeBreakpoint(Location location) {
+ EventRequestManager evm = getEventRequestManager();
+ BreakpointRequest request = evm.createBreakpointRequest(location);
+ display("Breakpoint set:\n\t" + request);
+ return request;
+ }
+
+ /**
+ * Make disabled breakpoint to given line number in specified method
+ * and return BreakpointRequest.
+ *
+ * @param method method mirror to set breakpoint
+ * @param lineNumber line number inside the method
+ *
+ * @throws Failure if no location found for specified line number
+ *
+ * @see #makeBreakpoint(Location)
+ * @see #makeBreakpoint(ReferenceType, String, int)
+ */
+ public BreakpointRequest makeBreakpoint(Method method, int lineNumber) {
+ Location location = getLineLocation(method, lineNumber);
+ if (location == null) {
+ throw new Failure("No location found for setting breakpoint to line " + lineNumber);
+ }
+ return makeBreakpoint(location);
+ }
+
+ /**
+ * Make disabled breakpoint to given line number for specified method name
+ * of the given reference type and return BreakpointRequest.
+ *
+ * @param refType reference type for specified method
+ * @param methodName method name to set breakpoint
+ * @param lineNumber line number inside the method
+ *
+ * @throws Failure if no location found for specified line number
+ *
+ * @see #makeBreakpoint(Method, int)
+ */
+ public BreakpointRequest makeBreakpoint(ReferenceType refType,
+ String methodName, int lineNumber) {
+ Method method = methodByName(refType, methodName);
+ if (method == null) {
+ throw new Failure("No method found for setting breakpoint: " + methodName);
+ }
+ return makeBreakpoint(method, lineNumber);
+ }
+
+ /**
+ * Set and enable breakpoint to given line number for specified method
+ * and return BreakpointRequest.
+ *
+ * @param method method mirror to set breakpoint
+ * @param lineNumber line number inside the method
+ *
+ * @throws Failure if no location found for specified line number
+ *
+ * @see #setBreakpoint(ReferenceType, String, int)
+ */
+ public BreakpointRequest setBreakpoint(Method method, int lineNumber) {
+ BreakpointRequest request = makeBreakpoint(method, lineNumber);
+ request.enable();
+ return request;
+ }
+
+ /**
+ * Set and enable breakpoint to given line number for specified method name
+ * of the given reference type and return BreakpointRequest.
+ *
+ * @param refType reference type for specified method
+ * @param methodName method name to set breakpoint
+ * @param lineNumber line number inside the method
+ *
+ * @throws Failure if no location found for specified line number
+ *
+ * @see #setBreakpoint(Method, int)
+ */
+ public BreakpointRequest setBreakpoint(ReferenceType refType,
+ String methodName, int lineNumber) {
+ BreakpointRequest request = makeBreakpoint(refType, methodName, lineNumber);
+ request.enable();
+ return request;
+ }
+
+ // --------------------------------------------------- //
+
+ /** Suspend the debugee VM. */
+ public void suspend() {
+ vm.suspend();
+ }
+
+ /** Resume the debugee VM. */
+ public void resume() {
+ vm.resume();
+ }
+
+ /** Dispose the debugee VM. */
+ public void dispose() {
+ vm.dispose();
+ }
+
+ /*
+ * Set internal JDI tracing mode.
+ */
+ public void setDebugTraceMode(int traceMode) {
+ vm.setDebugTraceMode(traceMode);
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Wait for the requested event and skip other events.
+ *
+ * @param request non-null value for events generated by this
+ * event request; null value for <code>VMStartEvent</code>.
+ * @param timeout timeout in milliseconds to wait for the requested event.
+ *
+ * @throws InterruptedException if another thread has interrupted this thread
+ */
+ public Event waitingEvent(EventRequest request, long timeout)
+ throws InterruptedException {
+
+ if (request == null) {
+ throw new Failure("Null request specified for waiting events: " + request);
+ }
+
+ long timeToFinish = System.currentTimeMillis() + timeout;
+ long timeLeft = timeout;
+ boolean exit = false;
+
+ display("Waiting for event by request:\n\t" + request);
+
+ EventQueue eventQueue = vm.eventQueue();
+ while (timeLeft > 0 && !exit) {
+
+ EventSet eventSet = eventQueue.remove(timeLeft);
+ if (eventSet == null) {
+ continue;
+ }
+
+ EventIterator eventIterator = eventSet.eventIterator();
+ while (eventIterator.hasNext()) {
+
+ Event event = eventIterator.nextEvent();
+ EventRequest eventRequest = event.request();
+
+ if (request == eventRequest || request.equals(eventRequest)) {
+ display("Got requested event:\n\t" + event);
+ return event;
+ } else if (event instanceof VMDeathEvent) {
+ display("Ignore unexpected VMDeathEvent");
+ } else if (event instanceof VMDisconnectEvent) {
+ display("Got unexpected VMDisconnectEvent");
+ exit = true;
+ break;
+ } else {
+ display("Ignore unexpected event:\n\t" + event);
+ } // if
+
+ } // while
+
+ timeLeft = timeToFinish - System.currentTimeMillis();
+
+ } // while
+
+ return null;
+ }
+
+ /*
+ * Wait for VM to initialize by receiving initial VM_START event for specified timeout.
+ */
+ public void waitForVMInit(long timeout) {
+ waitForVMInit(vm ,log, timeout);
+ }
+
+ /*
+ * This static method is also used by nsk.share.jdi.ConnectorTest
+ */
+ static public void waitForVMInit(VirtualMachine vm, Log log, long timeout) {
+ try {
+ EventSet eventSet = vm.eventQueue().remove(timeout);
+ if (eventSet == null) {
+ throw new Failure("No VMStartEvent received for timeout: " + timeout + " ms");
+ }
+ EventIterator iterator = eventSet.eventIterator();
+ while (iterator.hasNext()) {
+ Event event = iterator.nextEvent();
+ if (event == null) {
+ throw new Failure("Null event received instead of VMStartEvent");
+ }
+ if (event instanceof VMStartEvent) {
+ log.display("Initial VMStartEvent received: " + event);
+ } else {
+ throw new Failure("Unexpected event received instead of VMStartEvent: " + event);
+ }
+ }
+ int suspendPolicy = eventSet.suspendPolicy();
+ if (suspendPolicy != EventRequest.SUSPEND_ALL) {
+ throw new Failure("Suspend policy of VMStartEvent is not SUSPEND_ALL: " + suspendPolicy);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Thread interrupted while waiting for VMStartEvent:\n\t" + e);
+ }
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Bind to debuggee VM using <code>Binder</code> and make initial
+ * synchronization via IOPipe.
+ *
+ * @param argHandler command line arguments handler to make <code>Binder</code> object
+ * @param log <code>Log</code> object to log messages
+ * @param mainClassName main class of debugee
+ *
+ * @throws Failure if there were problems with binding to debuggee VM
+ *
+ * @see Binder#bindToDebugee(String)
+ */
+ public static Debugee prepareDebugee(ArgumentHandler argHandler, Log log,
+ String mainClassName) {
+ Binder binder = new Binder(argHandler, log);
+ Debugee debugee = binder.bindToDebugee(mainClassName);
+
+ debugee.createIOPipe();
+
+ debugee.redirectStderr(log, DEBUGEE_STDERR_LOG_PREFIX);
+ debugee.resume();
+
+ debugee.receiveExpectedSignal("ready");
+
+ return debugee;
+ }
+
+ /**
+ * Send <code>"quit"</code> signal, wait for debugee VM exit and check exit.
+ *
+ * @throws Failure if exit status is not <code>Consts.JCK_STATUS_BASE</code>
+ *
+ * @see #endDebugee()
+ */
+ public void quit() {
+ sendSignal("quit");
+ int status = endDebugee();
+ if ( status != Consts.JCK_STATUS_BASE ) {
+ throw new Failure("Got unexpected debugee VM exit status: " + status
+ + " (not " + Consts.JCK_STATUS_BASE + ")");
+ }
+ display("Got expected debugee VM exit status: " + status);
+ }
+
+ /*
+ * Dispose debuggee VM, wait for it to exit, close all resources and return
+ * exit status code.
+ */
+ public int endDebugee() {
+ if (vm != null) {
+ try {
+ vm.dispose();
+ } catch (VMDisconnectedException ignore) {
+ }
+ vm = null;
+ }
+ return waitFor();
+ }
+
+ /*
+ * Print information about all threads in debuggee VM
+ */
+ protected void printThreadsInfo(VirtualMachine vm) {
+ try {
+ log.display("------------ Try to print debuggee threads before killing process ------------");
+ if (vm == null) {
+ log.display("Can't print threads info because 'vm' is null");
+ return;
+ }
+ List<ThreadReference> threads = vm.allThreads();
+ log.display("Threads: " + threads);
+ log.display("Total threads: " + threads.size());
+ for (ThreadReference thread : threads) {
+ log.display("\nThread: " + thread.name());
+ log.display("Is suspended: " + thread.isSuspended());
+ log.display("Is at breakpoint: " + thread.isAtBreakpoint());
+ boolean wasSuspended = false;
+ try {
+ if (!thread.isSuspended()) {
+ log.display("\n suspend thread to get its stack \n");
+ thread.suspend();
+ wasSuspended = true;
+ }
+ log.display("Stack frame count: " + thread.frameCount());
+ if (thread.frameCount() > 0) {
+ log.display("Frames:");
+ for (StackFrame frame : thread.frames()) {
+ Location location = frame.location();
+ log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber());
+ }
+ }
+ } finally {
+ if (wasSuspended) {
+ log.display("\n resume thread \n");
+ thread.resume();
+ }
+ }
+ }
+ log.display("----------------------------------------------------------------------");
+ } catch (Throwable t) {
+ log.complain("");
+ t.printStackTrace(log.getOutStream());
+ }
+ }
+
+ /**
+ * Force debugge VM to exit using JDI interface if possible.
+ */
+ protected void killDebugee() {
+ try {
+ // print information about debuggee threads to simplify failure analysis
+ printThreadsInfo(vm);
+ } finally {
+ if (vm != null) {
+ try {
+ display("Killing debuggee by forcing target VM to exit");
+ vm.exit(97);
+ display("Debugee VM successfully forced to exit");
+ vm = null;
+ } catch (VMDisconnectedException e) {
+ display("Ignore VMDisconnectedException while forcing debuggee VM to exit:\n\t"
+ + e);
+ }
+ }
+ }
+ }
+
+ public boolean isJFR_active() {
+ String opts = argumentHandler.getLaunchOptions();
+ int unlockPos = opts.indexOf("-XX:+UnlockCommercialFeatures");
+ int jfrPos = opts.indexOf("-XX:+FlightRecorder");
+
+ if (unlockPos >= 0 && jfrPos >= 0 && jfrPos > unlockPos)
+ return true;
+ else
+ return false;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggeeEventData.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+/*
+ * Classes included in this class represent JDI events on debuggee VM's side
+ * All this classes contain information about JDI event which should be generated during test execution
+ */
+public class DebuggeeEventData {
+ // base event data class
+ public static class DebugEventData {
+ }
+
+ /*
+ * debug information about monitor event
+ */
+ public static class DebugMonitorEventData extends DebugEventData {
+ public DebugMonitorEventData(Object monitor, Thread thread, Object eventObject) {
+ this.monitor = monitor;
+ this.thread = thread;
+ this.eventObject = eventObject;
+ }
+
+ public Object monitor;
+
+ public Thread thread;
+
+ public Object eventObject;
+ }
+
+ /*
+ * information about MonitorContendedEnterEvent
+ */
+ public static class DebugMonitorEnterEventData extends DebugMonitorEventData {
+ public DebugMonitorEnterEventData(Object monitor, Thread thread, Object eventObject) {
+ super(monitor, thread, eventObject);
+ }
+ }
+
+ /*
+ * information about MonitorContendedEnteredEvent
+ */
+ public static class DebugMonitorEnteredEventData extends DebugMonitorEventData {
+ public DebugMonitorEnteredEventData(Object monitor, Thread thread, Object eventObject) {
+ super(monitor, thread, eventObject);
+ }
+ }
+
+ /*
+ * information about MonitorWaitEvent
+ */
+ public static class DebugMonitorWaitEventData extends DebugMonitorEventData {
+ public long timeout;
+
+ public DebugMonitorWaitEventData(Object monitor, Thread thread, long timeout, Object eventObject) {
+ super(monitor, thread, eventObject);
+ this.timeout = timeout;
+ }
+ }
+
+ /*
+ * information about MonitorWaitedEvent
+ */
+ public static class DebugMonitorWaitedEventData extends DebugMonitorEventData {
+ public boolean timedout;
+
+ public DebugMonitorWaitedEventData(Object monitor, Thread thread, boolean timedout, Object eventObject) {
+ super(monitor, thread, eventObject);
+ this.timedout = timedout;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/DebuggerEventData.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+
+/*
+ * Classes included in this class represent JDI events on debugger VM's side
+ * All this classes contain information about JDI event which should be generated during test execution,
+ * instances of this classes should be created using instances of corresponding classes from debuggee VM
+ */
+public class DebuggerEventData
+{
+ static abstract class DebugEventData
+ {
+
+ protected Class<?> eventClass;
+ public DebugEventData(Class<?> eventClass) {
+ this.eventClass = eventClass;
+ }
+
+ public boolean shouldCheckEvent(Event event) {
+ return this.eventClass.isAssignableFrom(event.getClass());
+ }
+
+ // is given event's data identical with data stored in this object
+ abstract public boolean checkEvent(Event event);
+ }
+
+ /*
+ * debug information about monitor event
+ */
+ static abstract class DebugMonitorEventData extends DebugEventData {
+ protected ObjectReference monitor;
+
+ protected ThreadReference thread;
+
+ public DebugMonitorEventData(Class<?> eventClass, ObjectReference debuggeeMirror) {
+ super(eventClass);
+
+ this.eventClass = eventClass;
+ monitor = (ObjectReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("monitor"));
+ thread = (ThreadReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("thread"));
+ }
+
+ public String toString() {
+ return eventClass.getName() + " monitor: " + monitor + " thread: " + thread;
+ }
+ }
+
+ /*
+ * information about MonitorContendedEnterEvent
+ */
+ static class DebugMonitorEnterEventData extends DebugMonitorEventData {
+ public DebugMonitorEnterEventData(ObjectReference debuggeeMirror) {
+ super(MonitorContendedEnterEvent.class, debuggeeMirror);
+ }
+
+ public boolean checkEvent(Event event) {
+ MonitorContendedEnterEvent monitorEnterEvent = (MonitorContendedEnterEvent) event;
+
+ return monitorEnterEvent.monitor().equals(monitor) && monitorEnterEvent.thread().equals(thread);
+ }
+ }
+
+ /*
+ * information about MonitorContendedEnteredEvent
+ */
+ static class DebugMonitorEnteredEventData extends DebugMonitorEventData {
+ public DebugMonitorEnteredEventData(ObjectReference debuggeeMirror) {
+ super(MonitorContendedEnteredEvent.class, debuggeeMirror);
+ }
+
+ public boolean checkEvent(Event event) {
+ MonitorContendedEnteredEvent monitorEnterEvent = (MonitorContendedEnteredEvent) event;
+
+ return monitorEnterEvent.monitor().equals(monitor) && monitorEnterEvent.thread().equals(thread);
+ }
+ }
+
+ /*
+ * information about MonitorWaitEvent
+ */
+ static class DebugMonitorWaitEventData extends DebugMonitorEventData {
+ private long timeout;
+
+ public DebugMonitorWaitEventData(ObjectReference debuggeeMirror) {
+ super(MonitorWaitEvent.class, debuggeeMirror);
+
+ timeout = ((LongValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("timeout"))).longValue();
+ }
+
+ public boolean checkEvent(Event event) {
+ MonitorWaitEvent monitorWaitEvent = (MonitorWaitEvent) event;
+
+ return monitorWaitEvent.monitor().equals(monitor) && monitorWaitEvent.thread().equals(thread) && (monitorWaitEvent.timeout() == timeout);
+ }
+
+ public String toString() {
+ return eventClass.getName() + " monitor: " + monitor + " thread: " + thread + " timeout: " + timeout;
+ }
+ }
+
+ /*
+ * information about MonitorWaitedEvent
+ */
+ static class DebugMonitorWaitedEventData extends DebugMonitorEventData {
+ private boolean timedout;
+
+ public DebugMonitorWaitedEventData(ObjectReference debuggeeMirror) {
+ super(MonitorWaitedEvent.class, debuggeeMirror);
+
+ timedout = ((BooleanValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("timedout"))).booleanValue();
+ }
+
+ public boolean checkEvent(Event event) {
+ MonitorWaitedEvent monitorWaitedEvent = (MonitorWaitedEvent) event;
+
+ return monitorWaitedEvent.monitor().equals(monitor) && monitorWaitedEvent.thread().equals(thread)
+ && (monitorWaitedEvent.timedout() == timedout);
+ }
+
+ public String toString() {
+ return eventClass.getName() + " monitor: " + monitor + " thread: " + thread + " timedout: " + timedout;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.lang.reflect.*;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import nsk.share.TestBug;
+
+/*
+ * EventFilters class just contain all filter classes
+ */
+public class EventFilters
+{
+ /*
+ * Class is intended for testing event filters.
+ *
+ * Since different request classes have identical methods for adding filters(e.g. addInstanceFilter(),addClassFilter())
+ * but this classes don't have common superclass reflection is used for filter adding.
+ * Subclasses should implement following methods:
+ * - getMethodName(), provide filter adding method's name
+ * - getParametersTypes(), provide filter adding method's parameters types
+ * - getFilterParameters(), provide parameters to be passed in filter adding method
+ *
+ * Also to check is generated event was really filtered subclasses should implement method 'isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)',
+ * this method should check is event generated by given object in given thread accepted by filter.
+ */
+ public abstract static class DebugEventFilter
+ {
+ // eventObject - object which generate event
+ // eventThread - thread where event was generated
+ abstract public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread);
+
+ // call corresponding request's method to set event filter
+ public void addFilter(EventRequest request)
+ throws Throwable
+ {
+ java.lang.reflect.Method method;
+
+ try
+ {
+ method = request.getClass().getMethod(getMethodName(), getParametersTypes());
+ }
+ catch(Exception e)
+ {
+ throw new TestBug("Can't get method '" + getMethodName() + "'");
+ }
+
+ try
+ {
+ method.setAccessible(true);
+ method.invoke(request, getFilterParameters());
+ }
+ catch(IllegalAccessException e)
+ {
+ TestBug testBug = new TestBug("Can't call method '" + getMethodName() + "'");
+ testBug.initCause(e);
+ throw testBug;
+ }
+ catch(InvocationTargetException e)
+ {
+ throw e.getCause();
+ }
+ }
+
+ public boolean isSupported(VirtualMachine vm)
+ {
+ return true;
+ }
+
+ abstract protected String getMethodName();
+ abstract protected Class[] getParametersTypes();
+ abstract protected Object[] getFilterParameters();
+ }
+
+ /*
+ * Restricts the events to those whose method is in a class whose name matches this
+ * restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported
+ */
+ public static class ClassFilter
+ extends DebugEventFilter
+ {
+ protected String classPattern;
+
+ private String startsWithPattern;
+ private String endsWithPattern;
+
+ public ClassFilter(String classPattern)
+ {
+ this.classPattern = classPattern;
+
+ if(classPattern.startsWith("*"))
+ endsWithPattern = classPattern.substring(1);
+ else
+ if(classPattern.endsWith("*"))
+ startsWithPattern = classPattern.substring(0, classPattern.length() - 1);
+ }
+
+ public String toString()
+ {
+ return "ClassFilter: classes should match pattern: " + classPattern;
+ }
+
+ protected String getMethodName()
+ {
+ return "addClassFilter";
+ }
+
+ protected Class[] getParametersTypes()
+ {
+ return new Class[]{String.class};
+ }
+
+ protected Object[] getFilterParameters()
+ {
+ return new Object[]{classPattern};
+ }
+
+ public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
+ {
+ if(!isNameMatch(eventObject.referenceType().name()))
+ return false;
+ else
+ return true;
+ }
+
+ protected boolean isNameMatch(String className)
+ {
+ if(startsWithPattern != null)
+ return className.startsWith(startsWithPattern);
+ else
+ if(endsWithPattern != null)
+ return className.endsWith(endsWithPattern);
+ else
+ return className.equals(classPattern);
+ }
+ }
+
+ /*
+ * Restricts the events to those whose method is in a class whose name doesn't matches
+ * restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported
+ */
+ public static class ClassExclusionFilter
+ extends ClassFilter
+ {
+ public ClassExclusionFilter(String classPattern)
+ {
+ super(classPattern);
+ }
+
+ public String toString()
+ {
+ return "ClassExclusionFilter: classes match follows pattern should be excluded: " + classPattern;
+ }
+
+ protected String getMethodName()
+ {
+ return "addClassExclusionFilter";
+ }
+
+ public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
+ {
+ if(isNameMatch(eventObject.referenceType().name()))
+ return false;
+ else
+ return true;
+ }
+ }
+
+ /*
+ * Restricts the events to those whose method is in the given reference type or any of its subtypes
+ */
+ public static class ClassReferenceFilter
+ extends DebugEventFilter
+ {
+ private Class<?> filterClass;
+ private ReferenceType referenceType;
+
+ public ClassReferenceFilter(ReferenceType referenceType)
+ {
+ this.referenceType = referenceType;
+ filterClass = findClass(referenceType);
+ }
+
+ public String toString()
+ {
+ return "ClassReferenceFilter: expect only " + filterClass.getName() + " and its subclasses";
+ }
+
+ protected String getMethodName()
+ {
+ return "addClassFilter";
+ }
+
+ protected Class[] getParametersTypes()
+ {
+ return new Class[]{ReferenceType.class};
+ }
+
+ protected Object[] getFilterParameters()
+ {
+ return new Object[]{referenceType};
+ }
+
+ public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
+ {
+ Class<?> eventObjectClass = findClass(eventObject.referenceType());
+
+ if(!filterClass.isAssignableFrom(eventObjectClass))
+ return false;
+ else
+ return true;
+ }
+
+ // find class represented by given referenceType
+ private Class<?> findClass(ReferenceType referenceType)
+ {
+ try
+ {
+ return Class.forName(referenceType.name());
+ }
+ catch(ClassNotFoundException e)
+ {
+ throw new TestBug("Can't find class: " + referenceType.name());
+ }
+ }
+ }
+
+ /*
+ * Restricts the events to those in which the currently executing instance ("this") is the given object
+ */
+ public static class ObjectReferenceFilter
+ extends DebugEventFilter
+ {
+ private ObjectReference objectReference;
+
+ public ObjectReferenceFilter(ObjectReference objectReference)
+ {
+ this.objectReference = objectReference;
+ }
+
+ public String toString()
+ {
+ return "ObjectReferenceFilter: expect only object " + objectReference;
+ }
+
+ protected String getMethodName()
+ {
+ return "addInstanceFilter";
+ }
+
+ protected Class[] getParametersTypes()
+ {
+ return new Class[]{ObjectReference.class};
+ }
+
+ protected Object[] getFilterParameters()
+ {
+ return new Object[]{objectReference};
+ }
+
+ public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
+ {
+ return objectReference.equals(eventObject);
+ }
+
+ public boolean isSupported(VirtualMachine vm)
+ {
+ return vm.canUseInstanceFilters();
+ }
+ }
+
+ /*
+ * Restricts the events to those in the given thread
+ */
+ public static class ThreadFilter
+ extends DebugEventFilter
+ {
+ private ThreadReference threadReference;
+
+ public ThreadFilter(ThreadReference threadReference)
+ {
+ this.threadReference = threadReference;
+ }
+
+ public String toString()
+ {
+ return "ThreadReferenceFilter: expect only thread " + threadReference;
+ }
+
+ protected String getMethodName()
+ {
+ return "addThreadFilter";
+ }
+
+ protected Class[] getParametersTypes()
+ {
+ return new Class[]{ThreadReference.class};
+ }
+
+ protected Object[] getFilterParameters()
+ {
+ return new Object[]{threadReference};
+ }
+
+ public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
+ {
+ return threadReference.equals(eventThread);
+ }
+ }
+
+ public static boolean filtered(Event event) {
+ if (event.toString().contains("VM JFR Buffer Thread"))
+ return true;
+
+ if (event.toString().contains("JFR request timer"))
+ return true;
+
+ return false;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import java.util.*;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import nsk.share.*;
+
+/**
+ * This class provides a separate thread for asynchronous listening
+ * to JDI events. All received events are sequentially passed
+ * to event listeners. If current event listener returns true
+ * then the event is considered be processed and it is not passed
+ * to remaining listeners.
+ * <p>
+ * The <code>EventHandler</code> thread runs until <code>VMDisconnectEvent</code>
+ * is received or <code>VMDisconnectionedException</code> is caught.
+ *
+ * @see EventListener
+ */
+public class EventHandler implements Runnable {
+
+ private Debugee debuggee = null;
+ private Log log = null;
+
+ private VirtualMachine vm;
+ private EventRequestManager requestManager;
+ /**
+ * Container for event listeners
+ */
+ private static List<EventListener> listeners = Collections.synchronizedList(new Vector<EventListener>());
+ private Thread listenThread;
+
+ /**
+ * Exit status of the <code>EventHandler</code> thread
+ */
+ private static volatile int status = -1;
+
+ /**
+ * Return an exit status of the <code>EventHandler</code> thread
+ * were the values are:
+ * <li><i>-1</i> - no value
+ * <li><i>0</i> - normal termination
+ * <li><i>1</i> - the thread is still running
+ * <li><i>2</i> - abnormal termination
+ */
+ public static synchronized int getStatus() {
+ return status;
+ }
+
+ /**
+ * Default ExceptionRequest with SUSPEND_EVENT_THREAD to be able
+ * to catch debuggee exceptions and output a message.
+ */
+ private static ExceptionRequest defaultExceptionRequest = null;
+
+ /**
+ * This flag will be set true if event of uncaught exception has been
+ * received.
+ */
+ private static volatile boolean defaultExceptionCaught = false;
+ public static synchronized boolean getExceptionCaught() {
+ return defaultExceptionCaught;
+ }
+
+ /**
+ * This flag will be set true if any event which does not have specific
+ * listener has been received.
+ */
+ private static volatile boolean unexpectedEventCaught = false;
+ public static synchronized boolean unexpectedEventCaught() {
+ return unexpectedEventCaught;
+ }
+
+ /**
+ * This flag shows if debugged VM is connected to debugger.
+ */
+ private static volatile boolean vmDisconnected = false;
+ public static synchronized boolean isDisconnected() {
+ return vmDisconnected;
+ }
+
+ public EventHandler(Debugee debuggee, Log log) {
+ this.listenThread = new Thread(this);
+ this.listenThread.setDaemon(true);
+
+ this.debuggee = debuggee;
+ this.log = log;
+ this.vm = debuggee.VM();
+ this.requestManager = vm.eventRequestManager();
+ }
+
+ private void display(String str) {
+ log.display("EventHandler> " + str);
+ }
+
+ // is EventHandler was interrupted
+ private volatile boolean wasInterrupted;
+
+ public void stopEventHandler() {
+ wasInterrupted = true;
+
+ listenThread.interrupt();
+
+ try {
+ listenThread.join();
+ }
+ catch(InterruptedException e) {
+ throw new TestBug("Unexpected exception: " + e);
+ }
+ }
+ /**
+ * The <code>EventHandler</code> thread keeps running until a VMDisconnectedEvent occurs
+ * or some exception occurs during event processing.
+ */
+ public void run() {
+ synchronized(EventHandler.this) {
+ status = 1; // running
+ }
+ do {
+ try {
+ EventSet set = vm.eventQueue().remove();
+
+ switch (set.suspendPolicy()) {
+ case EventRequest.SUSPEND_NONE:
+ display("Received event set with policy = SUSPEND_NONE");
+ break;
+ case EventRequest.SUSPEND_ALL:
+ display("Received event set with policy = SUSPEND_ALL");
+ break;
+ case EventRequest.SUSPEND_EVENT_THREAD:
+ display("Received event set with policy = SUSPEND_EVENT_THREAD");
+ break;
+ }
+
+ synchronized (listeners) {
+ synchronized (EventHandler.this) {
+ for (EventListener listener : listeners) {
+ // proloque listener for a event set
+ listener.eventSetReceived(set);
+ }
+
+ for (Event event : set) {
+ // print only event class name here because of Event,toString may cause unexpected exception
+ display("Event: " + event.getClass().getSimpleName()
+ + " req " + event.request());
+ boolean processed = false;
+ for (EventListener listener : listeners) {
+ processed = listener.eventReceived(event);
+
+ if (processed) {
+ if (listener.shouldRemoveListener()) {
+ listener.eventSetComplete(set);
+ removeListener(listener);
+ }
+
+ break;
+ }
+ }
+ }
+
+ for (EventListener listener : listeners) {
+ // epiloque listener for a event set
+ listener.eventSetComplete(set);
+ }
+ }
+ }
+
+ }
+ catch (Exception e) {
+
+ if(e instanceof InterruptedException) {
+ if(wasInterrupted)
+ break;
+ }
+
+ log.complain("Exception occured in eventHandler thread: " + e.getMessage());
+ e.printStackTrace(log.getOutStream());
+ synchronized(EventHandler.this) {
+ // This will make the waiters such as waitForVMDisconnect
+ // exit their wait loops.
+ vmDisconnected = true;
+ status = 2; // abnormal termination
+ EventHandler.this.notifyAll();
+ }
+ throw new Failure(e);
+ }
+ } while (!wasInterrupted && !isDisconnected());
+
+ if (unexpectedEventCaught || defaultExceptionCaught) {
+ synchronized(EventHandler.this) {
+ status = 2;
+ }
+ }
+ display("finished");
+ }
+
+
+ /**
+ * This is normally called in the main thread of the test debugger.
+ * It starts up an <code>EventHandler</code> thread that gets events coming in
+ * from the debuggee and distributes them to listeners.
+ */
+ public void startListening() {
+ createDefaultEventRequests();
+ createDefaultListeners();
+ listenThread.start();
+ }
+
+
+ /**
+ * This method sets up default requests.
+ */
+ private void createDefaultEventRequests() {
+ /**
+ * The following request will allow to print a warning if a debuggee gets an
+ * unexpected exception. The unexpected exception will be handled in
+ * the eventReceived method in the default listener created.
+ * If a test case does not want an uncaught exception to cause a
+ * message, it must add new listener for uncaught exception events to
+ * handle them.
+ */
+ defaultExceptionRequest = requestManager.createExceptionRequest(null, false, true);
+ defaultExceptionRequest.enable();
+ }
+
+ /**
+ * This method sets up default listeners.
+ */
+ private void createDefaultListeners() {
+ /**
+ * This listener catches up all unexpected events.
+ *
+ */
+ addListener(
+ new EventListener() {
+ public boolean eventReceived(Event event) {
+ log.complain("EventHandler> Unexpected event: " + event.getClass().getName());
+ unexpectedEventCaught = true;
+ return true;
+ }
+ }
+ );
+
+ /**
+ * This listener catches up VMStart event.
+ */
+ addListener(
+ new EventListener() {
+ public boolean eventReceived(Event event) {
+ if (event instanceof VMStartEvent) {
+ display("received VMStart");
+ removeListener(this);
+ return true;
+ }
+ return false;
+ }
+ }
+ );
+
+ /**
+ * This listener catches up VMDeath event.
+ */
+ addListener(
+ new EventListener() {
+ public boolean eventReceived(Event event) {
+ if (event instanceof VMDeathEvent) {
+ display("receieved VMDeath");
+ removeListener(this);
+ return true;
+ }
+ return false;
+ }
+ }
+ );
+
+ /**
+ * This listener catches up <code>VMDisconnectEvent</code>event and
+ * signals <code>EventHandler</code> thread to finish.
+ */
+ addListener(
+ new EventListener() {
+ public boolean eventReceived(Event event) {
+ if (event instanceof VMDisconnectEvent ) {
+ display("receieved VMDisconnect");
+ synchronized(EventHandler.this) {
+ vmDisconnected = true;
+ status = 0; // OK finish
+ EventHandler.this.notifyAll();
+ removeListener(this);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+ );
+
+ /**
+ * This listener catches uncaught exceptions and print a message.
+ */
+ addListener( new EventListener() {
+ public boolean eventReceived(Event event) {
+ boolean handled = false;
+
+ if (event instanceof ExceptionEvent &&
+ defaultExceptionRequest != null &&
+ defaultExceptionRequest.equals(event.request())) {
+
+ if (EventFilters.filtered(event) == false) {
+ log.complain("EventHandler> Unexpected Debuggee Exception: " +
+ (ExceptionEvent)event);
+ defaultExceptionCaught = true;
+ }
+
+ handled = true;
+ vm.resume();
+ }
+
+ return handled;
+ }
+ }
+ );
+ }
+
+ /**
+ * Add at beginning of the list because we want
+ * the LAST added listener to be FIRST to process
+ * current event.
+ */
+ public void addListener(EventListener listener) {
+ display("Adding listener " + listener);
+ synchronized(listeners) {
+ listeners.add(0, listener);
+ }
+ }
+
+ /**
+ * Removes the listener from the list.
+ */
+ public void removeListener(EventListener listener) {
+ display("Removing listener " + listener);
+ synchronized(listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+
+ /**
+ * Returns an event which is received for any of given requests.
+ */
+ public Event waitForRequestedEvent( final EventRequest[] requests,
+ long timeout,
+ boolean shouldRemoveListeners) {
+ class EventNotification {
+ volatile Event event = null;
+ }
+ final EventNotification en = new EventNotification();
+
+ EventListener listener = new EventListener() {
+ public boolean eventReceived(Event event) {
+ for (int i = 0; i < requests.length; i++) {
+ EventRequest request = requests[i];
+ if (!request.isEnabled())
+ continue;
+ if (request.equals(event.request())) {
+ display("waitForRequestedEvent: Received event(" + event + ") for request(" + request + ")");
+ synchronized (EventHandler.this) {
+ en.event = event;
+ EventHandler.this.notifyAll();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ if (shouldRemoveListeners) {
+ display("waitForRequestedEvent: enabling remove of listener " + listener);
+ listener.enableRemovingThisListener();
+ }
+ for (int i = 0; i < requests.length; i++) {
+ requests[i].enable();
+ }
+ addListener(listener);
+
+ try {
+ long timeToFinish = System.currentTimeMillis() + timeout;
+ long timeLeft = timeout;
+ synchronized (EventHandler.this) {
+ display("waitForRequestedEvent: vm.resume called");
+ vm.resume();
+
+ while (!isDisconnected() && en.event == null && timeLeft > 0) {
+ EventHandler.this.wait(timeLeft);
+ timeLeft = timeToFinish - System.currentTimeMillis();
+ }
+ }
+ } catch (InterruptedException e) {
+ return null;
+ }
+ if (shouldRemoveListeners && !isDisconnected()) {
+ for (int i = 0; i < requests.length; i++) {
+ requests[i].disable();
+ }
+ }
+ if (en.event == null) {
+ throw new Failure("waitForRequestedEvent: no requested events have been received.");
+ }
+ return en.event;
+ }
+
+ /**
+ * Returns an event set which is received for any of given requests.
+ */
+ public EventSet waitForRequestedEventSet( final EventRequest[] requests,
+ long timeout,
+ boolean shouldRemoveListeners) {
+ class EventNotification {
+ volatile EventSet set = null;
+ }
+ final EventNotification en = new EventNotification();
+
+ EventListener listener = new EventListener() {
+ public void eventSetReceived(EventSet set) {
+
+ EventIterator eventIterator = set.eventIterator();
+
+ while (eventIterator.hasNext()) {
+
+ Event event = eventIterator.nextEvent();
+
+ for (int i = 0; i < requests.length; i++) {
+ EventRequest request = requests[i];
+ if (!request.isEnabled())
+ continue;
+
+ if (request.equals(event.request())) {
+ display("waitForRequestedEventSet: Received event set for request: " + request);
+ synchronized (EventHandler.this) {
+ en.set = set;
+ EventHandler.this.notifyAll();
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ public boolean eventReceived(Event event) {
+ return (en.set != null);
+ }
+ };
+
+ if (shouldRemoveListeners) {
+ display("waitForRequestedEventSet: enabling remove of listener " + listener);
+ listener.enableRemovingThisListener();
+ }
+ for (int i = 0; i < requests.length; i++) {
+ requests[i].enable();
+ }
+ addListener(listener);
+
+ try {
+ long timeToFinish = System.currentTimeMillis() + timeout;
+ long timeLeft = timeout;
+ synchronized (EventHandler.this) {
+ display("waitForRequestedEventSet: vm.resume called");
+ vm.resume();
+
+ while (!isDisconnected() && en.set == null && timeLeft > 0) {
+ EventHandler.this.wait(timeLeft);
+ timeLeft = timeToFinish - System.currentTimeMillis();
+ }
+ }
+ } catch (InterruptedException e) {
+ return null;
+ }
+ if (shouldRemoveListeners && !isDisconnected()) {
+ for (int i = 0; i < requests.length; i++) {
+ requests[i].disable();
+ }
+ }
+ if (en.set == null) {
+ throw new Failure("waitForRequestedEventSet: no requested events have been received.");
+ }
+ return en.set;
+ }
+
+ public synchronized void waitForVMDisconnect() {
+ display("waitForVMDisconnect");
+ while (!isDisconnected()) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ display("waitForVMDisconnect: done");
+ }
+
+ /**
+ * This is a superclass for any event listener.
+ */
+ public static class EventListener {
+
+ /**
+ * This flag shows if the listener must be removed
+ * after current event has been processed by
+ * this listener.
+ */
+ volatile boolean shouldRemoveListener = false;
+ public boolean shouldRemoveListener() {
+ return shouldRemoveListener;
+ }
+
+ public void enableRemovingThisListener() {
+ shouldRemoveListener = true;
+ }
+
+ /**
+ * This method will be called by <code>EventHandler</code>
+ * for received event set before any call of <code>eventReceived</code>
+ * method for events contained in this set.
+ */
+ public void eventSetReceived(EventSet set) {}
+
+
+ /**
+ * This method will be called by <code>EventHandler</code>
+ * for received event set after all calls of <code>eventReceived</code>
+ * and event specific methods for all events contained in this set.
+ */
+ public void eventSetComplete(EventSet set) {}
+
+ /**
+ * This method will be called by <code>EventHandler</code>
+ * for any event contained in received event set.
+ *
+ * @return <code>true</code> if event was processed by this
+ * <code>EventListener<code> or <code>false</code> otherwise.
+ */
+ public boolean eventReceived(Event event) {
+ return false;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventTestTemplates.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import nsk.share.Consts;
+import nsk.share.TestBug;
+
+/*
+ * Class contains debugger classes based on JDIEventsDebugger intended for JDI events testing
+ */
+public class EventTestTemplates {
+
+ // how many times rerun test in case when tested events aren't generated
+ static final int MAX_TEST_RUN_NUMBER = 10;
+
+ /*
+ * Method contains common code used by EventFilterTests and StressTestTemplate
+ */
+ static void runTestWithRerunPossibilty(JDIEventsDebugger debugger, Runnable testRunner) {
+ for (int i = 0; i < MAX_TEST_RUN_NUMBER; i++) {
+ testRunner.run();
+
+ /*
+ * If events weren't generated at all but test accepts missing events
+ * try to rerun test (rerun test only if it didn't fail yet)
+ */
+ if (debugger.eventsNotGenerated() && debugger.getSuccess()) {
+ if (i < MAX_TEST_RUN_NUMBER - 1) {
+ debugger.log.display("\nWARNING: tested events weren't generated at all, trying to rerun test (rerun attempt " + (i + 1) + ")\n");
+ continue;
+ } else {
+ debugger.setSuccess(false);
+ debugger.log.complain("Tested events weren't generated after " + MAX_TEST_RUN_NUMBER + " runs, test FAILED");
+ }
+ } else
+ break;
+ }
+ }
+
+ /*
+ * Debugger class for testing event filters, subclasses should parse command
+ * line and call method JDIEventsDebugger.eventFilterTestTemplate with
+ * required arguments.
+ *
+ * Class handles common for event filter tests parameters:
+ * - debuggee class name (e.g. -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee)
+ * - tested event type (e.g. -eventType MONITOR_CONTENTED_ENTER)
+ */
+ public static abstract class EventFilterTest extends JDIEventsDebugger {
+ protected String debuggeeClassName;
+
+ protected EventType eventType;
+
+ protected String[] doInit(String[] args, PrintStream out) {
+ args = super.doInit(args, out);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-debuggeeClassName") && (i < args.length - 1)) {
+ debuggeeClassName = args[i + 1];
+ i++;
+ } else if (args[i].equals("-eventType") && (i < args.length - 1)) {
+ try {
+ eventType = EventType.valueOf(args[i + 1]);
+ } catch (IllegalArgumentException e) {
+ TestBug testBug = new TestBug("Invalid event type : " + args[i + 1], e);
+ throw testBug;
+ }
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ if (eventType == null)
+ throw new TestBug("Test requires 'eventType' parameter");
+
+ if (debuggeeClassName == null)
+ throw new TestBug("Test requires 'debuggeeClassName' parameter");
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ abstract protected int getTestFiltersNumber();
+
+ // This class is required to call runTestWithRerunPossibilty()
+ class FilterTestRunner implements Runnable {
+ private int filterIndex;
+
+ FilterTestRunner(int filterIndex) {
+ this.filterIndex = filterIndex;
+ }
+
+ public void run() {
+ eventFilterTestTemplate(eventType, filterIndex);
+ }
+ }
+
+ public final void doTest() {
+ prepareDebuggee(new EventType[] {eventType});
+
+ int filtersNumber = getTestFiltersNumber();
+
+ if (filtersNumber <= 0)
+ throw new TestBug("Invalid filtersNumber: " + filtersNumber);
+
+ for (int filterIndex = 0; filterIndex < getTestFiltersNumber(); filterIndex++) {
+ runTestWithRerunPossibilty(this, new FilterTestRunner(filterIndex));
+ }
+
+ eventHandler.stopEventHandler();
+ removeDefaultBreakpoint();
+ }
+
+ // can't control events from system libraries, so save events only from nsk packages
+ protected boolean shouldSaveEvent(Event event) {
+ return isEventFromNSK(event);
+ }
+
+ protected String debuggeeClassName() {
+ return debuggeeClassName;
+ }
+ }
+
+ /*
+ * Class for testing class exclusion filter, this filter is added by
+ * request's method addClassExclusionFilter(String classPattern) Expected
+ * command line parameter:
+ * - class patterns which should be passed to adding filter method (e.g. -classPatterns java.*:*.Foo)
+ */
+ public static class ClassExclusionFilterTest extends EventFilterTest {
+ protected String classPatterns[];
+
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new ClassExclusionFilterTest().runIt(argv, out);
+ }
+
+ protected String[] doInit(String[] args, PrintStream out) {
+ args = super.doInit(args, out);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-classPatterns") && (i < args.length - 1)) {
+ classPatterns = args[i + 1].split(":");
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ if (classPatterns == null || classPatterns.length == 0)
+ throw new TestBug("Test requires at least one class name pattern");
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ protected int getTestFiltersNumber() {
+ return classPatterns.length;
+ }
+
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
+ throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
+
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ClassExclusionFilter(classPatterns[testedFilterIndex])};
+ }
+ }
+
+ /*
+ * Subclass of ClassExclusionFilterTest, create ClassFilter instead of
+ * ClassExclusionFilter, this filter is added by request's method
+ * addClassFilter(String classPattern)
+ */
+ public static class ClassFilterTest_ClassName extends ClassExclusionFilterTest {
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new ClassFilterTest_ClassName().runIt(argv, out);
+ }
+
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
+ throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
+
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ClassFilter(classPatterns[testedFilterIndex])};
+ }
+ }
+
+ /*
+ * Subclass of ClassExclusionFilterTest, create ClassReferenceFilter instead
+ * of ClassExclusionFilter, this filter is added by request's method
+ * addClassFilter(ReferenceType referenceType)
+ */
+ public static class ClassFilterTest_ReferenceType extends ClassExclusionFilterTest {
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new ClassFilterTest_ReferenceType().runIt(argv, out);
+ }
+
+ protected int getTestFiltersNumber() {
+ return classPatterns.length;
+ }
+
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ if (testedFilterIndex < 0 || testedFilterIndex >= classPatterns.length)
+ throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
+
+ ReferenceType referenceType = debuggee.classByName(classPatterns[testedFilterIndex]);
+ if (referenceType == null)
+ throw new TestBug("Invalid class name is passed: " + classPatterns[testedFilterIndex]);
+
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ClassReferenceFilter(referenceType)};
+ }
+ }
+
+ /*
+ * Class for testing instance filter, this filter is added by request's
+ * method addInstanceFilter(ObjectReference instance). Class tests 3 following
+ * cases:
+ * - add filter for single object
+ * - add filter for the same object 2 times, expect behavior such as in previous case
+ * - add filter for 2 different objects, so events shouldn't be received
+ */
+ public static class InstanceFilterTest extends EventFilterTest {
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new InstanceFilterTest().runIt(argv, out);
+ }
+
+ protected int getTestFiltersNumber() {
+ return 3;
+ }
+
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ List<ObjectReference> objects = getEventObjects();
+
+ if (objects.size() < 2) {
+ throw new TestBug("Debuggee didn't create event generating objects");
+ }
+
+ switch (testedFilterIndex) {
+ case 0:
+ // filter for 1 object
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0))};
+ case 1:
+ // add 2 filters for the same object
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)),
+ new EventFilters.ObjectReferenceFilter(objects.get(0))};
+ case 2:
+ // add 2 filters for 2 different objects, so don't expect any event
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ObjectReferenceFilter(objects.get(0)),
+ new EventFilters.ObjectReferenceFilter(objects.get(1))};
+ default:
+ throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
+ }
+ }
+ }
+
+ /*
+ * Class for testing thread filter, this filter is added by request's method
+ * addThreadFilter(ThreadReference thread). Class test 3 follows cases:
+ * - add filter for single thread
+ * - add filter for the same thread 2 times, expect behavior such as in previous case
+ * - add filter for 2 different threads, so events shouldn't be received
+ */
+ public static class ThreadFilterTest extends EventFilterTest {
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new ThreadFilterTest().runIt(argv, out);
+ }
+
+ protected int getTestFiltersNumber() {
+ return 3;
+ }
+
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ List<ThreadReference> threads = getEventThreads();
+
+ if (threads.size() < 2) {
+ throw new TestBug("Debuggee didn't create event generating threads");
+ }
+
+ switch (testedFilterIndex) {
+ case 0:
+ // filter for 1 thread
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0))};
+ case 1:
+ // add 2 filters for the same thread
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)),
+ new EventFilters.ThreadFilter(threads.get(0))};
+ case 2:
+ // add 2 filters for 2 different threads, so don't expect any event
+ return new EventFilters.DebugEventFilter[]{new EventFilters.ThreadFilter(threads.get(0)),
+ new EventFilters.ThreadFilter(threads.get(1))};
+ default:
+ throw new TestBug("Invalid testedFilterIndex: " + testedFilterIndex);
+ }
+ }
+ }
+
+ /*
+ * Class is intended for stress testing, expected command line parameters:
+ * - debuggee class name (e.g.: -debuggeeClassName nsk.share.jdi.MonitorEventsDebuggee)
+ * - one or more tested event types (e.g.: -eventTypes MONITOR_CONTENTED_ENTER:MONITOR_CONTENTED_ENTERED)
+ * - number of events which should be generated during test execution (e.g.: -eventsNumber 500)
+ * - number of threads which simultaneously generate events (e.g.: -threadsNumber 10)
+ *
+ * Class parses command line and calls method JDIEventsDebugger.stressTestTemplate.
+ */
+ public static class StressTestTemplate extends JDIEventsDebugger {
+ protected String debuggeeClassName;
+
+ protected EventType testedEventTypes[];
+
+ protected int eventsNumber = 1;
+
+ protected int threadsNumber = 1;
+
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new StressTestTemplate().runIt(argv, out);
+ }
+
+ protected String[] doInit(String[] args, PrintStream out) {
+ args = super.doInit(args, out);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-eventsNumber") && (i < args.length - 1)) {
+ eventsNumber = Integer.parseInt(args[i + 1]);
+
+ // for this stress test events number is equivalent of iterations
+ // (don't support 0 value of IterationsFactor)
+ if (stressOptions.getIterationsFactor() != 0)
+ eventsNumber *= stressOptions.getIterationsFactor();
+
+ i++;
+ } else if (args[i].equals("-threadsNumber") && (i < args.length - 1)) {
+ threadsNumber = Integer.parseInt(args[i + 1]);
+
+ // if 'threadsNumber' is specified test should take in account stress options
+ threadsNumber *= stressOptions.getThreadsFactor();
+
+ i++;
+ } else if (args[i].equals("-debuggeeClassName") && (i < args.length - 1)) {
+ debuggeeClassName = args[i + 1];
+ i++;
+ } else if (args[i].equals("-eventTypes") && (i < args.length - 1)) {
+ String eventTypesNames[] = args[i + 1].split(":");
+ testedEventTypes = new EventType[eventTypesNames.length];
+ try {
+ for (int j = 0; j < eventTypesNames.length; j++)
+ testedEventTypes[j] = EventType.valueOf(eventTypesNames[j]);
+ } catch (IllegalArgumentException e) {
+ throw new TestBug("Invalid event type", e);
+ }
+
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ if (testedEventTypes == null || testedEventTypes.length == 0)
+ throw new TestBug("Test requires 'eventTypes' parameter");
+
+ if (debuggeeClassName == null)
+ throw new TestBug("Test requires 'debuggeeClassName' parameter");
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ // can't control events from system libraries, so save events only from nsk packages
+ protected boolean shouldSaveEvent(Event event) {
+ return isEventFromNSK(event);
+ }
+
+ protected String debuggeeClassName() {
+ return debuggeeClassName;
+ }
+
+ public void doTest() {
+ prepareDebuggee(testedEventTypes);
+
+ runTestWithRerunPossibilty(this, new Runnable() {
+ public void run() {
+ stressTestTemplate(testedEventTypes, eventsNumber, threadsNumber);
+ }
+ });
+
+ eventHandler.stopEventHandler();
+ removeDefaultBreakpoint();
+ }
+ }
+
+ static public boolean isEventFromNSK(Event event) {
+ if (event instanceof MonitorContendedEnterEvent) {
+ return ((MonitorContendedEnterEvent) event).location() != null && ((MonitorContendedEnterEvent) event).monitor().type().name().startsWith("nsk.");
+ }
+ if (event instanceof MonitorContendedEnteredEvent) {
+ return ((MonitorContendedEnteredEvent) event).location() != null && ((MonitorContendedEnteredEvent) event).monitor().type().name().startsWith("nsk.");
+ }
+ if (event instanceof MonitorWaitEvent) {
+ return ((MonitorWaitEvent) event).monitor().type().name().startsWith("nsk.");
+ }
+ if (event instanceof MonitorWaitedEvent) {
+ return ((MonitorWaitedEvent) event).monitor().type().name().startsWith("nsk.");
+ }
+
+ // don't filter other events
+ return true;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ForceEarlyReturnDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+
+/*
+ * Class contains methods common for nsk/jdi/ThreadReference/forceEarlyReturn tests
+ */
+public class ForceEarlyReturnDebugger extends TestDebuggerType2 {
+ protected boolean canRunTest() {
+ if (!vm.canForceEarlyReturn()) {
+ log.display("TEST CANCELED due to: vm.canForceEarlyReturn() = false");
+ return false;
+ } else
+ return super.canRunTest();
+ }
+
+ protected void testMethodExitEvent(ThreadReference thread, String methodName) {
+ testMethodExitEvent(thread, methodName, true);
+ }
+
+ /*
+ * Method for checking is after forceEarlyReturn MethodExitEvent is generated as it would be in a normal return
+ * Before calling this method forceEarlyReturn() should be already called and tested thread should be suspended
+ */
+ protected void testMethodExitEvent(ThreadReference thread, String methodName, boolean resumeThreadAfterEvent) {
+ MethodExitRequest methodExitRequest;
+ methodExitRequest = debuggee.getEventRequestManager().createMethodExitRequest();
+ methodExitRequest.addThreadFilter(thread);
+ methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+ methodExitRequest.enable();
+
+ EventListenerThread listenerThread = new EventListenerThread(methodExitRequest);
+ listenerThread.start();
+ listenerThread.waitStartListen();
+
+ thread.resume();
+
+ Event event = listenerThread.getEvent();
+
+ if (event == null) {
+ setSuccess(false);
+ log.complain("MethodExitEvent was not generated " + ", method: " + methodName);
+ } else {
+ if (!((MethodExitEvent) event).method().name().equals(methodName)) {
+ setSuccess(false);
+ log.complain("Invalid MethodExitEvent: expected method - " + methodName + ", actually - "
+ + ((MethodExitEvent) event).method().name());
+ }
+ }
+
+ methodExitRequest.disable();
+ vm.eventRequestManager().deleteEventRequest(methodExitRequest);
+
+ if (resumeThreadAfterEvent)
+ thread.resume();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.Log;
+import nsk.share.ObjectInstancesManager;
+import nsk.share.TestBug;
+import nsk.share.jpda.DebugeeArgumentHandler;
+import nsk.share.jpda.IOPipe;
+
+/*
+ * Debuggee class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers).
+ * Handle commands related to creation of objects instances with given reference type
+ * and given referrers number, use for this purposes nsk.share.ObjectInstancesManager.
+ */
+public class HeapwalkingDebuggee extends AbstractJDIDebuggee {
+ protected ObjectInstancesManager objectInstancesManager;
+
+ // reference of this type should be included in ObjectReference.referringObjects
+ public static Set<String> includedIntoReferrersCountTypes = new HashSet<String>();
+
+ // reference of this type should be included in ReferenceType.instances
+ public static Set<String> includedIntoInstancesCountTypes = new HashSet<String>();
+
+ static {
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE);
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE);
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE);
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE);
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE);
+ includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE);
+
+ includedIntoReferrersCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE);
+ includedIntoReferrersCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE);
+ includedIntoReferrersCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE);
+ includedIntoReferrersCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE);
+ }
+
+ //create number instance of class with given name, command format: createInstances:class_name:instance_count[:referrer_count:referrer_type]
+ static public final String COMMAND_CREATE_INSTANCES = "createInstances";
+
+ //'delete'(make unreachable) number instance of class with given name, command format: deleteInstances:class_name:instance_count:referrer_count
+ static public final String COMMAND_DELETE_INSTANCES = "deleteInstances";
+
+ //delete number referrers
+ static public final String COMMAND_DELETE_REFERRERS = "deleteReferrers";
+
+ //create instance with all type referrers
+ static public final String COMMAND_CREATE_ALL_TYPE_REFERENCES = "createAllTypeReferences";
+
+ protected void init(String args[]) {
+ super.init(args);
+ objectInstancesManager = new ObjectInstancesManager(log);
+ }
+
+ public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String args[], boolean callExit) {
+ super.initDebuggee(argHandler, log, pipe, args, callExit);
+ objectInstancesManager = new ObjectInstancesManager(log);
+ }
+
+ public boolean parseCommand(String command) {
+ if (super.parseCommand(command))
+ return true;
+
+ try {
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
+ tokenizer.whitespaceChars(':', ':');
+ tokenizer.wordChars('_', '_');
+ tokenizer.wordChars('$', '$');
+ tokenizer.wordChars('[', ']');
+ tokenizer.wordChars('|', '|');
+
+ if (command.startsWith(COMMAND_CREATE_INSTANCES)) {
+ //createInstances:class_name:instance_count[:referrer_count:referrer_type]
+
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int instanceCounts = (int) tokenizer.nval;
+
+ int referrerCount = 1;
+ Set<String> referrerType = new HashSet<String>();
+
+ if (tokenizer.nextToken() == StreamTokenizer.TT_NUMBER) {
+ referrerCount = (int) tokenizer.nval;
+
+ if (tokenizer.nextToken() == StreamTokenizer.TT_WORD)
+ referrerType.addAll(Arrays.asList(tokenizer.sval.split("\\|")));
+ }
+ if (referrerType.isEmpty()) {
+ referrerType.add(ObjectInstancesManager.STRONG_REFERENCE);
+ }
+
+ objectInstancesManager.createReferences(instanceCounts, className, referrerCount, referrerType);
+
+ return true;
+ } else if (command.startsWith(COMMAND_DELETE_INSTANCES)) {
+ //deleteInstances:class_name:instance_count:referrer_count
+
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int instanceCounts = (int) tokenizer.nval;
+
+ objectInstancesManager.deleteAllReferrers(instanceCounts, className);
+
+ return true;
+ } else if (command.startsWith(COMMAND_DELETE_REFERRERS)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int referrersCount = (int) tokenizer.nval;
+
+ Set<String> referrerTypes = new HashSet<String>();
+ if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
+ referrerTypes.addAll(Arrays.asList(tokenizer.sval.split("\\|")));
+ }
+
+ objectInstancesManager.deleteReferrers(className, referrersCount, referrerTypes);
+
+ return true;
+ } else if (command.startsWith(COMMAND_CREATE_ALL_TYPE_REFERENCES)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int instanceCounts = (int) tokenizer.nval;
+
+ objectInstancesManager.createAllTypeReferences(className, instanceCounts);
+
+ return true;
+ }
+ } catch (IOException e) {
+ throw new TestBug("Invalid command format: " + command);
+ }
+
+ return false;
+ }
+
+ // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes
+ public static boolean useStrictCheck(String className, boolean otherThreadPresent) {
+ if (className.equals("java.lang.String"))
+ return false;
+
+ if (className.equals("char[]"))
+ return false;
+
+ if (className.equals("byte[]"))
+ return false;
+
+ if (className.equals("java.lang.Thread")) {
+ if (otherThreadPresent)
+ return false;
+ }
+
+ return true;
+ }
+
+ // is reference with given type should be included in ObjectReference.referringObjects
+ static public boolean isIncludedIntoReferrersCount(String referenceType) {
+ if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
+ throw new TestBug("Invalid reference type: " + referenceType);
+ }
+
+ return includedIntoReferrersCountTypes.contains(referenceType);
+ }
+
+ // is reference with given type should be included in ReferenceType.instances
+ static public boolean isIncludedIntoInstancesCount(String referenceType) {
+ if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
+ throw new TestBug("Invalid reference type: " + referenceType);
+ }
+
+ return includedIntoInstancesCountTypes.contains(referenceType);
+ }
+
+ public static void main(String args[]) {
+ HeapwalkingDebuggee debuggee = new HeapwalkingDebuggee();
+ debuggee.init(args);
+ debuggee.doTest();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.util.*;
+import com.sun.jdi.*;
+import nsk.share.TestBug;
+
+/*
+ * Debugger class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers)
+ * Contains several common checking and auxiliary methods.
+ */
+public class HeapwalkingDebugger extends TestDebuggerType2 {
+ // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes
+ protected boolean strictCheck(String className) {
+ boolean otherThreadPresent = isJFR_active();
+ return HeapwalkingDebuggee.useStrictCheck(className, otherThreadPresent);
+ }
+
+ // wrapper for VirtualMachine.instanceCounts
+ public long getInstanceCount(String className) {
+ List<ReferenceType> list = vm.classesByName(className);
+
+ if (list.size() == 0)
+ return 0;
+
+ if (list.size() > 1) {
+ setSuccess(false);
+ log.complain("Unexpected collection size returned by VirtualMachine.classesByName(" + className + "): " + list.size()
+ + ", only 1 entry was expected.");
+ }
+
+ long result[] = (vm.instanceCounts(list));
+
+ return result[0];
+ }
+
+ // tests that vm.instanceCounts(vm.allClasses()) doesn't throws any exceptions
+ protected void testInstanceCounts() {
+ try {
+ vm.instanceCounts(vm.allClasses());
+ } catch (Throwable t) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + t);
+ t.printStackTrace(log.getOutStream());
+ }
+
+ }
+
+ // check size of list returned by ReferenceType.instances
+ protected void checkDebugeeAnswer_instances(String className, int expectedCount) {
+ ReferenceType referenceType = debuggee.classByName(className);
+
+ int instanceCounts = referenceType.instances(0).size();
+
+ if (strictCheck(className)) {
+ if (referenceType.instances(0).size() != expectedCount) {
+ setSuccess(false);
+ log.complain("Unexpected size of referenceType.instances(" + className + "): " + instanceCounts + ", expected: " + expectedCount);
+ }
+ } else {
+ if (referenceType.instances(0).size() < expectedCount) {
+ setSuccess(false);
+ log.complain("Unexpected size of referenceType.instances(" + className + "): " + instanceCounts + ", expected: >= " + expectedCount);
+ }
+ }
+ }
+
+ // check value returned by VirtualMachine.instanceCounts,
+ // note that method call method isDebuggeeReady() which check that debuggee completed pervious command and is ready for new one
+ public void checkDebugeeAnswer_instanceCounts(String className, int expectedValue) {
+ if (!isDebuggeeReady())
+ return;
+
+ try {
+ long instanceCounts = getInstanceCount(className);
+
+ if (strictCheck(className)) {
+ if (instanceCounts != expectedValue) {
+ setSuccess(false);
+ log.complain("Wrong value was returned by VirtualMachine.instanceCounts(" + className + "): " + instanceCounts + ", expected: "
+ + expectedValue);
+ }
+ } else {
+ if (instanceCounts < expectedValue) {
+ setSuccess(false);
+ log.complain("Wrong value was returned by VirtualMachine.instanceCounts(" + className + "): " + instanceCounts
+ + ", expected: >= " + expectedValue);
+ }
+ }
+ } catch (Throwable e) {
+ setSuccess(false);
+
+ log.complain("Unexpected exception when getting instance count info:");
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+
+ // Verifies number of instances of a class.
+ // Two types of checks are done:
+ // 1. Current instances >= old instances + created instances.
+ // 2. New instances >= created instances.
+ //
+ // The check in case 1 can only be done for classes where the test controls
+ // all created and deleted instances.
+ // Other classes, like java.lang.String, can not make this check since
+ // an instance in "old instances" may have been removed by a GC.
+ // In that case the tetst would fail because it finds too few current instances.
+ public void checkDebugeeAnswer_instanceCounts(String className, int countCreated, List<ObjectReference> oldReferences) {
+ if (strictCheck(className)) {
+ int countAll = countCreated + oldReferences.size();
+ checkDebugeeAnswer_instanceCounts(className, countAll);
+ checkDebugeeAnswer_instances(className, countAll);
+ } else {
+ // isDebuggeeReady() check is hidden in checkDebugeeAnswer_instanceCounts() above.
+ // Must call it separately if we don't call checkDebugeeAnswer_instanceCounts().
+ if (!isDebuggeeReady()) {
+ return;
+ }
+ }
+
+ // Verify number of new instances created.
+ int countFoundCreated = countNewInstances(className, oldReferences);
+ if (countFoundCreated < countCreated) {
+ setSuccess(false);
+ log.complain("Too few new instances(" + className + "). Expected >= " + countCreated + ", found " + countFoundCreated);
+ }
+ }
+
+ private int countNewInstances(String className, List<ObjectReference> oldReferences) {
+ // New references = current references - old references.
+ List<ObjectReference> newReferences = new ArrayList<ObjectReference>(getObjectReferences(className, vm));
+ newReferences.removeAll(oldReferences);
+ return newReferences.size();
+ }
+
+ // check value returned by InterfaceType.instances
+ protected void checkDebugeeAnswer_InterfaceType_instances(InterfaceType interfaceType, int expectedInstances) {
+ int instanceCounts = interfaceType.instances(0).size();
+
+ if (instanceCounts != expectedInstances) {
+ setSuccess(false);
+ log.complain("List with wrong size was returned by InterfaceType.instances(" + interfaceType.name() + "): " + instanceCounts
+ + ", expected: " + expectedInstances);
+ }
+ }
+
+ static public List<ObjectReference> filterObjectReferrence(List<ObjectReference> objectsToFilter, List<ObjectReference> sourceList) {
+ List<ObjectReference> result = new ArrayList<ObjectReference>();
+
+ for (ObjectReference object : sourceList) {
+ if (!objectsToFilter.contains(object))
+ result.add(object);
+ }
+
+ return result;
+ }
+
+ static public List<ObjectReference> getObjectReferences(String className, VirtualMachine vm) {
+ List<ReferenceType> referenceTypes = vm.classesByName(className);
+
+ List<ObjectReference> objectReferences;
+
+ if (referenceTypes.size() == 0)
+ objectReferences = new ArrayList<ObjectReference>();
+ else if (referenceTypes.size() == 1)
+ objectReferences = referenceTypes.get(0).instances(0);
+ else {
+ throw new TestBug("Unexpected collection size returned by VirtualMachine.classesByName: " + referenceTypes.size()
+ + ", only 1 entry was expected.");
+ }
+
+ return objectReferences;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.TestBug;
+
+/*
+ * Subclasses of this class generate events and if needed
+ * save debug information about generated events
+ */
+abstract class EventActionsExecutor {
+ // should this event generator save information about generated events
+ public boolean saveEventData;
+
+ // information about generated events(this data available for debugger)
+ public List<DebuggeeEventData.DebugEventData> debugEventDataList = new ArrayList<DebuggeeEventData.DebugEventData>();
+
+ public abstract void doEventAction();
+
+ protected void addEventData(DebuggeeEventData.DebugEventData eventData) {
+ if (saveEventData)
+ debugEventDataList.add(eventData);
+ }
+
+ public void clearDebugData() {
+ debugEventDataList.clear();
+ }
+}
+
+/*
+ * Class handles commands for running given number of threads which generate
+ * given events. Objects which generate events save information about generated
+ * events and this data available for debugger
+ *
+ * Class was written to test monitor evens(MonitorWaitEvent, MonitorWaitedEvent,
+ * MonitorContendedEnterEvent, MonitorContendedEnteredEvent), possible it can be
+ * used in tests for other events
+ */
+abstract public class JDIEventsDebuggee extends AbstractJDIDebuggee {
+ protected String[] doInit(String[] args) {
+ Thread.currentThread().setName(MAIN_THREAD_NAME);
+ return super.doInit(args);
+ }
+
+ public static final String MAIN_THREAD_NAME = "JDIEventsDebuggee_MainThread";
+
+ // command:events_count:event types
+ public static final String COMMAND_CREATE_ACTIONS_EXECUTORS = "createActionsExecutors";
+
+ // command
+ public static final String COMMAND_START_EXECUTION = "startExecution";
+
+ // command
+ public static final String COMMAND_WAIT_EXECUTION_COMPLETION = "waitExecutionCompletion";
+
+ // command
+ public static final String COMMAND_STOP_EXECUTION = "stopExecution";
+
+ protected List<EventActionsThread> eventActionsExecutorsPool = new ArrayList<EventActionsThread>();
+
+ // initialize with empty array
+ public static DebuggeeEventData.DebugEventData generatedEvents[] = new DebuggeeEventData.DebugEventData[0];
+
+ // debuggee's main thread also can generate events and information about
+ // this events should be saved (like for event generators)
+ protected boolean saveEventData;
+
+ public boolean parseCommand(String command) {
+ if (super.parseCommand(command))
+ return true;
+
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(
+ command));
+ tokenizer.whitespaceChars(':', ':');
+ tokenizer.wordChars('_', '_');
+ tokenizer.wordChars(' ', ' ');
+
+ try {
+ if (command.startsWith(COMMAND_CREATE_ACTIONS_EXECUTORS)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int eventsCount = (int) tokenizer.nval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ // pass to the createActionsExecutors() string describing types
+ // of tested events
+ createActionsExecutors(tokenizer.sval, eventsCount);
+
+ return true;
+ } else if (command.equals(COMMAND_START_EXECUTION)) {
+ startExecution();
+
+ return true;
+ } else if (command.equals(COMMAND_WAIT_EXECUTION_COMPLETION)) {
+ if (executionControllingThread == null)
+ throw new TestBug("executionControllingThread wasn't started");
+
+ try {
+ executionControllingThread.join();
+ executionControllingThread = null;
+ } catch (InterruptedException e) {
+ unexpectedException(e);
+ }
+
+ return true;
+ } else if (command.equals(COMMAND_STOP_EXECUTION)) {
+ if (executionControllingThread == null)
+ throw new TestBug("executionControllingThread wasn't started");
+
+ for (EventActionsThread thread : eventActionsExecutorsPool) {
+ thread.stopExecution();
+ }
+
+ return true;
+ }
+
+ } catch (IOException e) {
+ throw new TestBug("Invalid command format: " + command);
+ }
+
+ return false;
+ }
+
+ // debugee waits completion of test threads in separate thread to free thread listening commands
+ protected Thread executionControllingThread;
+
+ protected void startExecution() {
+ if (eventActionsExecutorsPool.size() == 0) {
+ throw new TestBug("ActionsExecutors were not created");
+ }
+
+ for (EventActionsThread thread : eventActionsExecutorsPool) {
+ thread.startExecution();
+ }
+
+ // debugee waits completion of test threads in separate thread to free thread listening commands
+ executionControllingThread = new Thread(
+ new Runnable() {
+ public void run() {
+ for (EventActionsThread thread : eventActionsExecutorsPool) {
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ unexpectedException(e);
+ }
+ }
+
+ completeExecution();
+ }
+ });
+
+ executionControllingThread.start();
+ }
+
+ protected void completeExecution() {
+ // save information about all generated events in array 'generatedEvents'
+ List<DebuggeeEventData.DebugEventData> generatedEventsList = new ArrayList<DebuggeeEventData.DebugEventData>();
+
+ for (EventActionsThread thread : eventActionsExecutorsPool)
+ generatedEventsList.addAll(thread.executor.debugEventDataList);
+
+ generatedEvents = generatedEventsList.toArray(new DebuggeeEventData.DebugEventData[]{});
+
+ // stop at breakpoint when all events was generated
+ breakpointMethod();
+
+ // clear data about generated events to allow execute command
+ // several times
+ clearResults();
+ }
+
+ // clear data about generated events to allow execute test several times
+ protected void clearResults() {
+ for (EventActionsThread thread : eventActionsExecutorsPool)
+ thread.executor.clearDebugData();
+
+ eventActionsExecutorsPool.clear();
+
+ generatedEvents = new DebuggeeEventData.DebugEventData[0];
+ }
+
+ // create threads generating events
+ abstract protected void createActionsExecutors(String description,
+ int eventsCount);
+
+ /*
+ * Thread generating events, call in loop
+ * EventActionsExecutor.doEventAction()
+ */
+ static class EventActionsThread extends Thread {
+ // how many times call executor.doMonitorAction()
+ private int actionsNumber;
+
+ // object generating events
+ public EventActionsExecutor executor;
+
+ public EventActionsThread(EventActionsExecutor executor,
+ int actionsNumber) {
+ this.actionsNumber = actionsNumber;
+ this.executor = executor;
+ }
+
+ private volatile boolean startExecution;
+ private volatile boolean stopExecution;
+
+ public void run() {
+ while (!startExecution)
+ yield();
+
+ for (int i = 0; (i < actionsNumber) && !stopExecution; i++)
+ executor.doEventAction();
+ }
+
+ public void startExecution() {
+ startExecution = true;
+ }
+
+ public void stopExecution() {
+ stopExecution = true;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIEventsDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.PrintStream;
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import nsk.share.TestBug;
+
+/*
+ * Class is used as base debugger in tests for following events and event requests:
+ * - MonitorContendedEnterRequest / MonitorContendedEnterEvent
+ * - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent
+ * - MonitorWaitRequest / MonitorWaitEvent
+ * - MonitorWaitedRequest / MonitorWaitedEvent
+ *
+ * In all these tests similar scenario is used:
+ * - debugger VM forces debuggee VM to create number of objects which should generate events during test
+ * - if any event filters are used each generating event object is checked is this object accepted by all filters,
+ * if object was accepted it should save information about all generated events and this information is available for debugger
+ * - debuggee performs event generation and stop at breakpoint
+ * - debugger reads data saved by event generators and checks is only expected events was generated
+ */
+public class JDIEventsDebugger extends TestDebuggerType2 {
+ // types of tested events
+ static public enum EventType {
+ MONITOR_CONTENTED_ENTER,
+ MONITOR_CONTENTED_ENTERED,
+ MONITOR_WAIT,
+ MONITOR_WAITED
+ }
+
+ /*
+ * Class contains information required for event testing
+ */
+ static class TestedEventData {
+ // event class
+ public Class<?> eventClass;
+
+ // class representing event data on debuggee's side
+ public Class<?> eventDataMirrorClass;
+
+ // class representing event data on debugger's side
+ public Class<?> eventDataClass;
+
+ public TestedEventData(Class<?> eventClass, Class<?> eventDataMirrorClass, Class<?> eventDataClass) {
+ this.eventClass = eventClass;
+ this.eventDataMirrorClass = eventDataMirrorClass;
+ this.eventDataClass = eventDataClass;
+ }
+ }
+
+ static public Map<EventType, TestedEventData> testedEventData = new HashMap<EventType, TestedEventData>();
+
+ static {
+ testedEventData.put(EventType.MONITOR_CONTENTED_ENTER, new TestedEventData(MonitorContendedEnterEvent.class,
+ DebuggeeEventData.DebugMonitorEnterEventData.class, DebuggerEventData.DebugMonitorEnterEventData.class));
+
+ testedEventData.put(EventType.MONITOR_CONTENTED_ENTERED, new TestedEventData(MonitorContendedEnteredEvent.class,
+ DebuggeeEventData.DebugMonitorEnteredEventData.class, DebuggerEventData.DebugMonitorEnteredEventData.class));
+
+ testedEventData.put(EventType.MONITOR_WAIT, new TestedEventData(MonitorWaitEvent.class, DebuggeeEventData.DebugMonitorWaitEventData.class,
+ DebuggerEventData.DebugMonitorWaitEventData.class));
+
+ testedEventData.put(EventType.MONITOR_WAITED, new TestedEventData(MonitorWaitedEvent.class,
+ DebuggeeEventData.DebugMonitorWaitedEventData.class, DebuggerEventData.DebugMonitorWaitedEventData.class));
+ }
+
+ static public TestedEventData[] eventDataByEventTypes(EventType[] eventTypes) {
+ TestedEventData[] result = new TestedEventData[eventTypes.length];
+
+ int i = 0;
+ for (EventType eventType : eventTypes) {
+ TestedEventData eventData = testedEventData.get(eventType);
+
+ if (eventData == null)
+ throw new TestBug("Unsupported event type: " + eventType);
+
+ result[i++] = eventData;
+ }
+
+ return result;
+ }
+
+ /*
+ * Dummy event listener, just accepts all events
+ */
+ public class DummyEventListener extends EventHandler.EventListener {
+ private volatile boolean breakpointEventReceived;
+
+ public boolean eventReceived(Event event) {
+ if (event instanceof BreakpointEvent) {
+ breakpointEventReceived = true;
+ vm.resume();
+ }
+
+ return true;
+ }
+
+ public void waitBreakpoint() {
+ while (!breakpointEventReceived)
+ Thread.yield();
+ }
+ }
+
+ /*
+ * Parse common for event tests parameters
+ */
+ protected String[] doInit(String[] args, PrintStream out) {
+ args = super.doInit(args, out);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-allowExtraEvents")) {
+ extraEventClasses = createEventClassArray(args[i + 1]);
+
+ i++;
+ } else if (args[i].equals("-allowMissedEvents")) {
+ missedEventClasses = createEventClassArray(args[i + 1]);
+
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ return standardArgs.toArray(new String[standardArgs.size()]);
+ }
+
+ // can't control some kinds of events (events from system libraries) and
+ // not all events should be saved for analysis
+ // (should be implemented in subclasses)
+ protected boolean shouldSaveEvent(Event event) {
+ return true;
+ }
+
+ public Class<?> findEventDataClass(TestedEventData[] testedEventData, Event event) {
+ for (TestedEventData eventData : testedEventData) {
+ if (eventData.eventClass.isAssignableFrom(event.getClass()))
+ return eventData.eventClass;
+ }
+
+ return null;
+ }
+
+ /*
+ * This event listener stores received monitor events until BreakpointEvent
+ * is not received, after getting of BreakpointEvent checks only expected
+ * events were received
+ */
+ public class EventListener extends EventHandler.EventListener {
+
+ private TestedEventData[] testedEventData;
+
+ public EventListener(TestedEventData[] testedEventData) {
+ this.testedEventData = testedEventData;
+ }
+
+ private boolean shouldHandleEvent(Event event) {
+ return findEventDataClass(testedEventData, event) == null ? false : true;
+ }
+
+ volatile boolean breakpointWasReceived;
+
+ // execution was interrupted because of timeout
+ volatile boolean executionWasInterrupted;
+
+ public boolean eventReceived(Event event) {
+ if (shouldHandleEvent(event)) {
+ if (shouldSaveEvent(event)) {
+
+ Class<?> eventClass;
+
+ eventClass = findEventDataClass(testedEventData, event);
+ List<Event> events = allReceivedEvents.get(eventClass);
+
+ if (events == null) {
+ events = new LinkedList<Event>();
+ allReceivedEvents.put(eventClass, events);
+ }
+
+ events.add(event);
+ }
+
+ return true;
+ }
+ // debuggee should stop at the end of test
+ else if (event instanceof BreakpointEvent) {
+ breakpointWasReceived = true;
+
+ try {
+ // if execution was interrupted because of timeout don't check received
+ // events because it can consume too much time
+ if (!executionWasInterrupted) {
+ // get data from debuggee about all generated events
+ initExpectedEvents(testedEventData);
+
+ checkEvents();
+ } else
+ log.complain("WARNING: execution was interrupted because of timeout, test doesn't check received events");
+ } catch (Throwable t) {
+ unexpectedException(t);
+ }
+
+ vm.resume();
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ protected Class<?> extraEventClasses[];
+
+ protected Class<?> missedEventClasses[];
+
+ /*
+ * If test can't strictly control event generation it may allow generation
+ * of extra events and unexpected events aren't treated as error
+ * (subclasses should specify what kinds of extra events are allowed)
+ */
+ private Class<?>[] allowedExtraEvents() {
+ return extraEventClasses;
+ }
+
+ /*
+ * If test can't strictly control event generation case when debugger doesn't
+ * receive expected event may be not treated as failure
+ * (subclasses should specify what kinds of expected events can be not received)
+ */
+ private Class<?>[] allowedMissedEvents() {
+ return missedEventClasses;
+ }
+
+ private boolean isExtraEventAllowed(Class<?> eventClass) {
+ return checkEvent(eventClass, allowedExtraEvents());
+ }
+
+ private boolean isMissedEventAllowed(Class<?> eventClass) {
+ return checkEvent(eventClass, allowedMissedEvents());
+ }
+
+ private boolean checkEvent(Class<?> eventClass, Class<?> classes[]) {
+ if (classes == null)
+ return false;
+
+ for (Class<?> klass : classes) {
+ if (klass.isAssignableFrom(eventClass))
+ return true;
+ }
+
+ return false;
+ }
+
+ // flag is modified from the event listener thread
+ private volatile boolean eventsNotGenerated;
+
+ /*
+ * Method returns true if test expects event generation, but events weren't
+ * generated. If test can't strictly control event generation such case isn't
+ * necessarily treated as test failure (sublasses of JDIEventsDebugger can
+ * for example try to rerun test several times).
+ */
+ protected boolean eventsNotGenerated() {
+ return eventsNotGenerated;
+ }
+
+ /*
+ * Print debug information about expected and received events(this data
+ * should be stored in lists 'allExpectedEvents' and 'allReceivedEvents')
+ * and check that only expected events were received
+ */
+ private void checkEvents() {
+ if (getAllExpectedEvents().size() > 0 && getAllReceivedEvents().size() == 0 && allowedMissedEvents() != null) {
+ log.display("WARNING: didn't receive any event");
+ eventsNotGenerated = true;
+ }
+
+ log.display("ALL RECEIVED EVENTS: ");
+ for (Event event : getAllReceivedEvents())
+ log.display("received event: " + eventToString(event));
+
+ log.display("ALL EXPECTED EVENTS: ");
+ for (DebuggerEventData.DebugEventData eventData : getAllExpectedEvents())
+ log.display("expected event: " + eventData);
+
+ // try to find received event in the list of expected events, if this event
+ // was found remove data about events from both lists
+ for (Class<?> eventClass : allReceivedEvents.keySet()) {
+ List<Event> receivedEvents = allReceivedEvents.get(eventClass);
+ List<DebuggerEventData.DebugEventData> expectedEvents = allExpectedEvents.get(eventClass);
+
+ for (Iterator<Event> allReceivedEventsIterator = receivedEvents.iterator();
+ allReceivedEventsIterator.hasNext();) {
+
+ Event event = allReceivedEventsIterator.next();
+
+ for (Iterator<DebuggerEventData.DebugEventData> allExpectedEventsIterator = expectedEvents.iterator();
+ allExpectedEventsIterator.hasNext();) {
+
+ DebuggerEventData.DebugEventData debugEventData = allExpectedEventsIterator.next();
+
+ if (debugEventData.shouldCheckEvent(event)) {
+ if (debugEventData.checkEvent(event)) {
+ allExpectedEventsIterator.remove();
+ allReceivedEventsIterator.remove();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ List<Event> receivedEventsLeft = getAllReceivedEvents();
+
+ // check is all received events were found in expected
+ if (receivedEventsLeft.size() > 0) {
+ // if allowExtraEvents = true extra events are not treated as error
+ for (Event event : receivedEventsLeft) {
+ if (!isExtraEventAllowed(event.getClass())) {
+ setSuccess(false);
+ log.complain("Unexpected event " + eventToString(event));
+ }
+ }
+ }
+
+ List<DebuggerEventData.DebugEventData> expectedEventsLeft = getAllExpectedEvents();
+
+ // check is all expected events were received
+ if (expectedEventsLeft.size() > 0) {
+ for (DebuggerEventData.DebugEventData eventData : expectedEventsLeft) {
+ if (!isMissedEventAllowed(eventData.eventClass)) {
+ setSuccess(false);
+ log.complain("Expected event was not generated: " + eventData);
+ }
+ }
+ }
+ }
+
+ private String eventToString(Event event) {
+ try {
+ if (event instanceof MonitorContendedEnterEvent)
+ return event + ". Details(MonitorContendedEnterEvent):" + " Monitor: " + ((MonitorContendedEnterEvent) event).monitor() + " Thread: "
+ + ((MonitorContendedEnterEvent) event).thread();
+ else if (event instanceof MonitorContendedEnteredEvent)
+ return event + ". Details(MonitorContendedEnteredEvent):" + " Monitor: " + ((MonitorContendedEnteredEvent) event).monitor()
+ + " Thread: " + ((MonitorContendedEnteredEvent) event).thread();
+ else if (event instanceof MonitorWaitEvent)
+ return event + ". Details(MonitorWaitEvent):" + " Monitor: " + ((MonitorWaitEvent) event).monitor() + " Thread: "
+ + ((MonitorWaitEvent) event).thread() + " Timeout: " + ((MonitorWaitEvent) event).timeout();
+ else if (event instanceof MonitorWaitedEvent)
+ return event + ". Details(MonitorWaitedEvent):" + " Monitor: " + ((MonitorWaitedEvent) event).monitor() + " Thread: "
+ + ((MonitorWaitedEvent) event).thread() + " Timedout: " + ((MonitorWaitedEvent) event).timedout();
+
+ return event.toString();
+ }
+ // this exception can occur when unexpected event was received
+ catch (ObjectCollectedException e) {
+ // allowExtraEvents=true extra events are not treated as error
+ if (!isExtraEventAllowed(event.getClass())) {
+ setSuccess(false);
+ e.printStackTrace(log.getOutStream());
+ log.complain("Unexpected ObjectCollectedException was caught, possible unexpected event was received");
+ }
+
+ return event.getClass().getName() + " [ Can't get full description, ObjectCollectedException was thrown ]";
+ }
+ }
+
+ // events received during test execution are stored here
+ private Map<Class<?>, List<Event>> allReceivedEvents = new HashMap<Class<?>, List<Event>>();
+
+ private List<Event> getAllReceivedEvents() {
+ List<Event> result = new LinkedList<Event>();
+
+ for (Class<?> eventClass : allReceivedEvents.keySet()) {
+ result.addAll(allReceivedEvents.get(eventClass));
+ }
+
+ return result;
+ }
+
+ protected Map<Class<?>, List<DebuggerEventData.DebugEventData>> allExpectedEvents = new HashMap<Class<?>, List<DebuggerEventData.DebugEventData>>();
+
+ private List<DebuggerEventData.DebugEventData> getAllExpectedEvents() {
+ List<DebuggerEventData.DebugEventData> result = new LinkedList<DebuggerEventData.DebugEventData>();
+
+ for (Class<?> eventClass : allExpectedEvents.keySet()) {
+ result.addAll(allExpectedEvents.get(eventClass));
+ }
+
+ return result;
+ }
+
+ // find in debuggee VM and add to the list 'allExpectedEvents' instances
+ // of classes representing generated events
+ protected void initExpectedEvents(TestedEventData testedEventData[]) {
+ List<DebuggerEventData.DebugEventData> events;
+
+ ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs());
+
+ ArrayReference generatedEvents = (ArrayReference) referenceType.getValue(referenceType.fieldByName("generatedEvents"));
+
+ for (TestedEventData eventData : testedEventData) {
+ events = new LinkedList<DebuggerEventData.DebugEventData>();
+ allExpectedEvents.put(eventData.eventClass, events);
+ }
+
+ for (int i = 0; i < generatedEvents.length(); i++) {
+ ObjectReference debuggeeMirror = (ObjectReference) generatedEvents.getValue(i);
+
+ for (TestedEventData eventData : testedEventData) {
+
+ if (debuggeeMirror.referenceType().name().equals(eventData.eventDataMirrorClass.getName())) {
+ events = allExpectedEvents.get(eventData.eventClass);
+
+ /*
+ * Use reflection to create object representing generated
+ * event Event data class should has constructor with single
+ * parameter of type com.sun.jdi.ObjectReference
+ */
+ Constructor<?> constructor;
+
+ try {
+ constructor = eventData.eventDataClass.getConstructor(new Class[] { ObjectReference.class });
+ } catch (NoSuchMethodException e) {
+ TestBug testBug = new TestBug(
+ "Class representing debug event data should implement constructor with single parameter of type com.sun.jdi.ObjectReference");
+ testBug.initCause(e);
+ throw testBug;
+ }
+
+ DebuggerEventData.DebugEventData expectedEvent;
+
+ try {
+ expectedEvent = (DebuggerEventData.DebugEventData) constructor.newInstance(new Object[] { debuggeeMirror });
+ } catch (Exception e) {
+ TestBug testBug = new TestBug("Error when create debug event data: " + e);
+ testBug.initCause(e);
+ throw testBug;
+ }
+ events.add(expectedEvent);
+ }
+ }
+ }
+ }
+
+ private void printFiltersInfo() {
+ if (eventFilters.size() > 0) {
+ log.display("Use following filters: ");
+
+ for (EventFilters.DebugEventFilter filter : eventFilters)
+ log.display("" + filter);
+ } else {
+ log.display("Don't use event filters");
+ }
+ }
+
+ // filters used in test
+ protected List<EventFilters.DebugEventFilter> eventFilters = new LinkedList<EventFilters.DebugEventFilter>();
+
+ // Check is object generating events matches all filters,
+ // if object was accepted by all filters set this object's field
+ // 'saveEventData' to 'true', otherwise to 'false',
+ private void checkEventGenerator(ThreadReference eventThread, ObjectReference executor) {
+ boolean acceptedByFilters = true;
+
+ for (EventFilters.DebugEventFilter eventFilter : eventFilters) {
+ if (!eventFilter.isObjectMatch(executor, eventThread)) {
+ acceptedByFilters = false;
+ break;
+ }
+ }
+
+ try {
+ executor.setValue(executor.referenceType().fieldByName("saveEventData"), vm.mirrorOf(acceptedByFilters));
+ } catch (Exception e) {
+ throw new TestBug("Unexpected exception when change object field in debugee VM: " + e, e);
+ }
+ }
+
+ /*
+ * Find all event generating threads in debuggee VM (instances of
+ * nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread) all these
+ * threads have special field - 'executor', this is object which generates
+ * events. If event generating thread and event generating object was
+ * accepted by all filters generating object should store information about
+ * all generated events and this information will be available for debugger
+ */
+ protected void initializeEventGenerators() {
+ printFiltersInfo();
+
+ List<ThreadReference> eventThreads = getEventThreads();
+
+ for (ThreadReference eventThread : eventThreads) {
+ ObjectReference executor = (ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor"));
+ checkEventGenerator(eventThread, executor);
+ }
+
+ // debuggee's main thread also can generate events, need to filter it in
+ // the same way as other threads
+ checkEventGenerator(debuggee.threadByName(JDIEventsDebuggee.MAIN_THREAD_NAME), findSingleObjectReference(debuggeeClassNameWithoutArgs()));
+ }
+
+ // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread
+ protected List<ThreadReference> getEventThreads() {
+ ReferenceType referenceType = debuggee.classByName(JDIEventsDebuggee.EventActionsThread.class.getName());
+ List<ObjectReference> debuggeeEventThreads = referenceType.instances(0);
+
+ List<ThreadReference> result = new LinkedList<ThreadReference>();
+ for (ObjectReference threadReference : debuggeeEventThreads)
+ result.add((ThreadReference) threadReference);
+
+ return result;
+ }
+
+ // find instances of nsk.share.jdi.MonitorEventsDebuggee$MonitorActionsThread,
+ // and get value of this object's field with name 'executor'
+ protected List<ObjectReference> getEventObjects() {
+ List<ObjectReference> eventObjects = new LinkedList<ObjectReference>();
+
+ List<ThreadReference> eventThreads = getEventThreads();
+
+ for (ThreadReference eventThread : eventThreads) {
+ eventObjects.add((ObjectReference) eventThread.getValue(eventThread.referenceType().fieldByName("executor")));
+ }
+
+ return eventObjects;
+ }
+
+ // remove all filters, received and expected events
+ private void clearTestData() {
+ allExpectedEvents.clear();
+ allReceivedEvents.clear();
+ eventFilters.clear();
+ eventsNotGenerated = false;
+ }
+
+ private boolean isEventSupported(EventType eventType) {
+ switch (eventType) {
+ case MONITOR_CONTENTED_ENTER:
+ case MONITOR_CONTENTED_ENTERED:
+ case MONITOR_WAIT:
+ case MONITOR_WAITED:
+ return vm.canRequestMonitorEvents();
+
+ default:
+ throw new TestBug("Invalid tested event type: " + eventType);
+ }
+ }
+
+ // create instance of EventRequest depending on given eventType
+ private EventRequest createTestRequest(EventType eventType) {
+ switch (eventType) {
+ case MONITOR_CONTENTED_ENTER:
+ return debuggee.getEventRequestManager().createMonitorContendedEnterRequest();
+ case MONITOR_CONTENTED_ENTERED:
+ return debuggee.getEventRequestManager().createMonitorContendedEnteredRequest();
+ case MONITOR_WAIT:
+ return debuggee.getEventRequestManager().createMonitorWaitRequest();
+ case MONITOR_WAITED:
+ return debuggee.getEventRequestManager().createMonitorWaitedRequest();
+
+ default:
+ throw new TestBug("Invalid tested event type: " + eventType);
+ }
+ }
+
+ // create command depending on given eventType
+ private String createCommand(EventType eventTypes[], int eventsNumber) {
+ String command = JDIEventsDebuggee.COMMAND_CREATE_ACTIONS_EXECUTORS + ":" + eventsNumber + ":";
+
+ for (EventType eventType : eventTypes) {
+ switch (eventType) {
+ case MONITOR_CONTENTED_ENTER:
+ case MONITOR_CONTENTED_ENTERED:
+ case MONITOR_WAIT:
+ case MONITOR_WAITED:
+ command += " " + eventType.name();
+ break;
+
+ default:
+ throw new TestBug("Invalid tested event type: " + eventType);
+ }
+ }
+
+ return command;
+ }
+
+ // get list of event requests from EventRequestManager depending on the given eventType
+ private List<?> getEventRequestsFromManager(EventType eventType) {
+ switch (eventType) {
+ case MONITOR_CONTENTED_ENTER:
+ return debuggee.getEventRequestManager().monitorContendedEnterRequests();
+ case MONITOR_CONTENTED_ENTERED:
+ return debuggee.getEventRequestManager().monitorContendedEnteredRequests();
+ case MONITOR_WAIT:
+ return debuggee.getEventRequestManager().monitorWaitRequests();
+ case MONITOR_WAITED:
+ return debuggee.getEventRequestManager().monitorWaitedRequests();
+
+ default:
+ throw new TestBug("Invalid tested event type: " + eventType);
+ }
+ }
+
+ protected EventHandler eventHandler;
+
+ private EventListener eventListener;
+
+ // perform event generation before test begins to load all using classes
+ // and avoid unexpected events related to classloading
+ protected void prepareDebuggee(EventType[] eventTypes) {
+ initDefaultBreakpoint();
+
+ eventHandler = new EventHandler(debuggee, log);
+ eventHandler.startListening();
+
+ // use event listener which just skip all received events
+ DummyEventListener dummyEventListener = new DummyEventListener();
+ eventHandler.addListener(dummyEventListener);
+
+ EventRequest eventRequests[] = new EventRequest[eventTypes.length];
+
+ for (int i = 0; i < eventRequests.length; i++) {
+ eventRequests[i] = createTestRequest(eventTypes[i]);
+ eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
+ eventRequests[i].enable();
+ }
+
+ // debuggee should create event generators
+ pipe.println(createCommand(eventTypes, 1));
+
+ if (!isDebuggeeReady())
+ return;
+
+ // start event generation
+ pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ for (int i = 0; i < eventRequests.length; i++)
+ eventRequests[i].disable();
+
+ dummyEventListener.waitBreakpoint();
+
+ eventHandler.removeListener(dummyEventListener);
+
+ pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ eventListener = new EventListener(eventDataByEventTypes(eventTypes));
+ eventHandler.addListener(eventListener);
+ }
+
+ /*
+ * Method for stress testing, allows specify requests for several event
+ * types, number of events which should be generated during test and number
+ * of threads which simultaneously generate events
+ */
+ protected void stressTestTemplate(EventType[] eventTypes, int eventsNumber, int threadsNumber) {
+ for (EventType eventType : eventTypes) {
+ if (!isEventSupported(eventType)) {
+ log.complain("Can't test event because of it isn't supported: " + eventType);
+ return;
+ }
+ }
+
+ // Used framework is intended for testing event filters and debuggee
+ // creates 3 threads performing event generation and there is possibility
+ // to filter events from some threads
+ for (int i = 0; i < threadsNumber; i++) {
+ pipe.println(createCommand(eventTypes, eventsNumber));
+
+ if (!isDebuggeeReady())
+ return;
+ }
+
+ // clear data(if this method is executed several times)
+ clearTestData();
+
+ initializeEventGenerators();
+
+ EventRequest eventRequests[] = new EventRequest[eventTypes.length];
+
+ // create event requests
+ for (int i = 0; i < eventTypes.length; i++) {
+ eventRequests[i] = createTestRequest(eventTypes[i]);
+ eventRequests[i].setSuspendPolicy(EventRequest.SUSPEND_NONE);
+ eventRequests[i].enable();
+
+ log.display("Use following event request: " + eventRequests[i]);
+ }
+
+ // stressTestTemplate can control only execution time, so ignore iteration count
+ stresser.start(0);
+ try {
+ // start event generation
+ pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ // check is stressTime exceeded
+ while (stresser.continueExecution()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ unexpectedException(e);
+ }
+
+ // periodically check is test completed
+ if (eventListener.breakpointWasReceived)
+ break;
+ }
+ } finally {
+ stresser.finish();
+ }
+
+ // debugger should interrupt test because of timeout
+ if (!eventListener.breakpointWasReceived) {
+
+ eventListener.executionWasInterrupted = true;
+
+ log.complain("WARNING: time is exceeded, interrupt test");
+
+ pipe.println(JDIEventsDebuggee.COMMAND_STOP_EXECUTION);
+
+ if (!isDebuggeeReady())
+ return;
+ }
+
+ pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ for (int i = 0; i < eventRequests.length; i++)
+ eventRequests[i].disable();
+ }
+
+ /*
+ * Hook method for subclasses implementing tests against event filters (it is called from eventFilterTestTemplate)
+ */
+ protected EventFilters.DebugEventFilter[] createTestFilters(int testedFilterIndex) {
+ throw new TestBug("Not implemented");
+ }
+
+ /*
+ * Test event request with filter
+ *
+ * Also this method check following:
+ * - InvalidRequestStateException is thrown if add filter for deleted or enabled request
+ * - EventRequestManager.xxxRequests() returns created event request
+ */
+ protected void eventFilterTestTemplate(EventType eventType, int testedFilterIndex) {
+ if (!isEventSupported(eventType)) {
+ log.complain("Can't test event because of it isn't supported: " + eventType);
+ return;
+ }
+
+ // debuggee create event generators
+ pipe.println(createCommand(new EventType[] { eventType }, 1));
+
+ if (!isDebuggeeReady())
+ return;
+
+ clearTestData();
+
+ EventFilters.DebugEventFilter[] filters = createTestFilters(testedFilterIndex);
+
+ for (EventFilters.DebugEventFilter filter : filters) {
+ if (filter.isSupported(vm))
+ eventFilters.add(filter);
+ else {
+ log.complain("Can't test filter because of it isn't supported: " + filter);
+ return;
+ }
+ }
+
+ initializeEventGenerators();
+
+ // create event request
+ EventRequest request = createTestRequest(eventType);
+ request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+
+ // try add filter to enabled request, expect
+ // 'InvalidRequestStateException'
+ request.enable();
+ try {
+ for (EventFilters.DebugEventFilter filter : filters)
+ filter.addFilter(request);
+
+ setSuccess(false);
+ log.complain("Expected 'InvalidRequestStateException' was not thrown");
+ } catch (InvalidRequestStateException e) {
+ // expected exception
+ } catch (Throwable e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ // add event filter
+ request.disable();
+
+ for (EventFilters.DebugEventFilter filter : filters)
+ addFilter(filter, request);
+
+ request.enable();
+
+ log.display("Use following event request: " + request);
+
+ // start event generation
+ pipe.println(JDIEventsDebuggee.COMMAND_START_EXECUTION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ // wait execution completion
+ pipe.println(JDIEventsDebuggee.COMMAND_WAIT_EXECUTION_COMPLETION);
+
+ if (!isDebuggeeReady())
+ return;
+
+ // check that method EventRequestManager.xxxRequests() return created
+ // request
+ if (!getEventRequestsFromManager(eventType).contains(request)) {
+ setSuccess(false);
+ log.complain("EventRequestManager doesn't return request: " + request);
+ }
+
+ // delete event request
+ debuggee.getEventRequestManager().deleteEventRequest(request);
+
+ // try add filter to removed request, expect
+ // 'InvalidRequestStateException'
+ try {
+ for (EventFilters.DebugEventFilter filter : filters)
+ filter.addFilter(request);
+ setSuccess(false);
+ log.complain("Expected 'InvalidRequestStateException' was not thrown");
+ } catch (InvalidRequestStateException e) {
+ // expected exception
+ } catch (Throwable t) {
+ unexpectedException(t);
+ }
+ }
+
+ private void addFilter(EventFilters.DebugEventFilter filter, EventRequest request) {
+ try {
+ filter.addFilter(request);
+ } catch (Throwable t) {
+ unexpectedException(t);
+ }
+ }
+
+ // used to parse parameters -allowExtraEvents and -allowMissedEvents
+ private Class<?>[] createEventClassArray(String string) {
+ String eventTypesNames[] = string.split(":");
+ EventType eventTypes[] = new EventType[eventTypesNames.length];
+ try {
+ for (int i = 0; i < eventTypesNames.length; i++) {
+ eventTypes[i] = EventType.valueOf(eventTypesNames[i]);
+ }
+ } catch (IllegalArgumentException e) {
+ throw new TestBug("Invalid event type", e);
+ }
+
+ if (eventTypesNames.length == 0)
+ throw new TestBug("Event types weren't specified");
+
+ Class<?>[] result = new Class[eventTypesNames.length];
+
+ for (int i = 0; i < result.length; i++)
+ result[i] = testedEventData.get(eventTypes[i]).eventClass;
+
+ return result;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MockReferenceType.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A mock implementation of com.sun.jdi.ReferenceType interface.
+ */
+
+public class MockReferenceType implements ReferenceType {
+
+ private final String signature;
+ private final String name;
+ private final VirtualMachine virtualMachine;
+
+ private MockReferenceType(VirtualMachine virtualMachine, String signature, String name) {
+ this.signature = signature;
+ this.name = name;
+ this.virtualMachine = virtualMachine;
+ }
+
+ @Override
+ public String signature() {
+ return signature;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public String genericSignature() {
+ return null;
+ }
+
+ @Override
+ public ClassLoaderReference classLoader() {
+ return null;
+ }
+
+ @Override
+ public String sourceName() throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<String> sourceNames(String stratum) throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<String> sourcePaths(String stratum) throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public String sourceDebugExtension() throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public boolean isStatic() {
+ return false;
+ }
+
+ @Override
+ public boolean isAbstract() {
+ return false;
+ }
+
+ @Override
+ public boolean isFinal() {
+ return false;
+ }
+
+ @Override
+ public boolean isPrepared() {
+ return false;
+ }
+
+ @Override
+ public boolean isVerified() {
+ return false;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return false;
+ }
+
+ @Override
+ public boolean failedToInitialize() {
+ return false;
+ }
+
+ @Override
+ public List<Field> fields() {
+ return null;
+ }
+
+ @Override
+ public List<Field> visibleFields() {
+ return null;
+ }
+
+ @Override
+ public List<Field> allFields() {
+ return null;
+ }
+
+ @Override
+ public Field fieldByName(String fieldName) {
+ return null;
+ }
+
+ @Override
+ public List<Method> methods() {
+ return null;
+ }
+
+ @Override
+ public List<Method> visibleMethods() {
+ return null;
+ }
+
+ @Override
+ public List<Method> allMethods() {
+ return null;
+ }
+
+ @Override
+ public List<Method> methodsByName(String name) {
+ return null;
+ }
+
+ @Override
+ public List<Method> methodsByName(String name, String signature) {
+ return null;
+ }
+
+ @Override
+ public List<ReferenceType> nestedTypes() {
+ return null;
+ }
+
+ @Override
+ public Value getValue(Field field) {
+ return null;
+ }
+
+ @Override
+ public Map<Field, Value> getValues(List<? extends Field> fields) {
+ return null;
+ }
+
+ @Override
+ public ClassObjectReference classObject() {
+ return null;
+ }
+
+ @Override
+ public List<Location> allLineLocations() throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<Location> allLineLocations(String stratum, String sourceName) throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<Location> locationsOfLine(int lineNumber) throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<Location> locationsOfLine(String stratum, String sourceName, int lineNumber)
+ throws AbsentInformationException {
+ return null;
+ }
+
+ @Override
+ public List<String> availableStrata() {
+ return null;
+ }
+
+ @Override
+ public String defaultStratum() {
+ return null;
+ }
+
+ @Override
+ public List<ObjectReference> instances(long maxInstances) {
+ return null;
+ }
+
+ @Override
+ public int majorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int minorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int constantPoolCount() {
+ return 0;
+ }
+
+ @Override
+ public byte[] constantPool() {
+ return new byte[0];
+ }
+
+ @Override
+ public VirtualMachine virtualMachine() {
+ return virtualMachine;
+ }
+
+ @Override
+ public int modifiers() {
+ return 0;
+ }
+
+ @Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
+ public boolean isPackagePrivate() {
+ return false;
+ }
+
+ @Override
+ public boolean isProtected() {
+ return false;
+ }
+
+ @Override
+ public boolean isPublic() {
+ return false;
+ }
+
+ @Override
+ public int compareTo(ReferenceType o) {
+ return 0;
+ }
+
+ /*
+ * Creates a mock instance of com.sun.tools.jdi.ObjectReference with a given type.
+ */
+
+ public static Value createObjectReference(VirtualMachine virtualMachine, String typeSignature, String typeName)
+ throws Exception {
+
+ Class clazz = Class.forName("com.sun.tools.jdi.ObjectReferenceImpl");
+ java.lang.reflect.Constructor c = clazz.getDeclaredConstructor(VirtualMachine.class, long.class);
+ c.setAccessible(true);
+ Value objRef = (Value) c.newInstance(virtualMachine, 0);
+
+ Type mockType = new MockReferenceType(virtualMachine, typeSignature, typeName);
+ java.lang.reflect.Field typeField = clazz.getDeclaredField("type");
+ typeField.setAccessible(true);
+ typeField.set(objRef, mockType);
+
+ return objRef;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEnterExecutor.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2006, 2018, 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.
+ */
+#include "jni.h"
+#include "nsk_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_PTR
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG_2(x, y) y
+#define JNI_ENV_ARG_3(x,y, z) y, z
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG_2(x,y) x, y
+#define JNI_ENV_ARG_3(x,y, z) x, y, z
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+JNIEXPORT void JNICALL
+Java_nsk_share_jdi_MonitorEnterExecutor_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject)
+{
+ jint success;
+
+ success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero"));
+ }
+
+ success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero"));
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_nsk_share_jdi_MonitorEnterExecutor_11Subclass_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject)
+{
+ jint success;
+
+ success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero"));
+ }
+
+ success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero"));
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_nsk_share_jdi_MonitorEnterExecutor_12Subclass_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject)
+{
+ jint success;
+
+ success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero"));
+ }
+
+ success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero"));
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.util.*;
+import nsk.share.TestBug;
+import nsk.share.locks.MonitorLockingThread;
+
+/*
+ * This class generates MonitorWaitEvent and MonitorWaitedEvent
+ */
+class MonitorWaitExecutor extends EventActionsExecutor {
+ // MonitorWaited event may occurs when waiting thread was interrupted,
+ // notified by notify or notifyAll, or when timeout expired
+ enum ExitFromWaitType {
+ EXIT_WITH_TIMEOUT,
+ INTERRUPT,
+ NOTIFY,
+ NOTIFY_ALL
+ }
+
+ // this thread forces MonitorWaitExecutor to exit from wait()
+ class AuxiliaryThread extends Thread {
+ private Thread threadToInterrupt;
+
+ private Object monitor;
+
+ public AuxiliaryThread(Thread threadToInterrupt, Object monitor) {
+ this.threadToInterrupt = threadToInterrupt;
+ this.monitor = monitor;
+ }
+
+ public void run() {
+ // wait when interrupted thread switches state to 'TIMED_WAITING'
+ while ((threadToInterrupt.getState() != Thread.State.WAITING) && !exitedFromWait) {
+ yield();
+ }
+
+ // threadToInterrupt 'spuriously' exited from wait()
+ if(exitedFromWait)
+ return;
+
+ if (exitFromWaitType == ExitFromWaitType.INTERRUPT) {
+ threadToInterrupt.interrupt();
+ } else if ((exitFromWaitType == ExitFromWaitType.NOTIFY)
+ || (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL)) {
+ /*
+ * NOTE: thread's state WAITING doesn't guarantee that thread released
+ * monitor, and entering to the next synchronized block may cause MonitorContentedEnterEvent
+ * (if corresponding request was created).
+ *
+ * Debugger should take in account this issue.
+ */
+ synchronized (monitor) {
+ if (exitFromWaitType == ExitFromWaitType.NOTIFY)
+ monitor.notify();
+ else if (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL)
+ monitor.notifyAll();
+ }
+ }
+ }
+ }
+
+ // thread may 'spuriously' exit from wait(), in this case AuxiliaryThread shouldn't wait 'WAITING' state
+ private volatile boolean exitedFromWait;
+
+ // save data about MonitorWait events
+ private boolean monitorWait;
+
+ // save data about MonitorWaited events
+ private boolean monitorWaited;
+
+ public MonitorWaitExecutor(boolean monitorWait, boolean monitorWaited) {
+ this.monitorWait = monitorWait;
+ this.monitorWaited = monitorWaited;
+ }
+
+ protected ExitFromWaitType exitFromWaitType;
+
+ public void doEventAction() {
+ for (ExitFromWaitType exitType : ExitFromWaitType.values()) {
+ exitFromWaitType = exitType;
+
+ monitorWait();
+ }
+ }
+
+ protected void monitorWait() {
+
+ exitedFromWait = false;
+
+ long timeout;
+
+ if (exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT)
+ timeout = 100;
+ else
+ timeout = 0;
+
+ if (monitorWait) {
+ DebuggeeEventData.DebugMonitorWaitEventData eventData = new DebuggeeEventData.DebugMonitorWaitEventData(
+ this, Thread.currentThread(), timeout, this);
+ addEventData(eventData);
+ }
+
+ if (monitorWaited) {
+ DebuggeeEventData.DebugMonitorWaitedEventData eventData = new DebuggeeEventData.DebugMonitorWaitedEventData(
+ this, Thread.currentThread(),
+ (exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT),
+ this);
+ addEventData(eventData);
+ }
+
+ AuxiliaryThread auxiliaryThread = null;
+
+ if (exitFromWaitType != ExitFromWaitType.EXIT_WITH_TIMEOUT) {
+ auxiliaryThread = new AuxiliaryThread(Thread.currentThread(), this);
+ auxiliaryThread.start();
+ }
+
+ try {
+ eventMethod(timeout);
+ } catch (InterruptedException e) {
+ // expected exception
+ }
+
+ exitedFromWait = true;
+
+ if (auxiliaryThread != null) {
+ // don't using join, because of join is realized with using of
+ // wait(), and this method can generate unexpected events
+ while (auxiliaryThread.getState() != Thread.State.TERMINATED)
+ Thread.yield();
+ }
+ }
+
+ // move event actions to the separate method to simplify method redifinition
+ // in subclasses
+ synchronized protected void eventMethod(long timeout)
+ throws InterruptedException {
+ wait(timeout);
+ }
+
+}
+
+/*
+ * Subclass of MonitorWaitExecutor, define its own event method(copy of parent
+ * method), intended for event filters test
+ */
+class MonitorWaitExecutor_1Subclass extends MonitorWaitExecutor {
+ public MonitorWaitExecutor_1Subclass(boolean monitorWait,
+ boolean monitorWaited) {
+ super(monitorWait, monitorWaited);
+ }
+
+ synchronized protected void eventMethod(long timeout)
+ throws InterruptedException {
+ wait(timeout);
+ }
+}
+
+/*
+ * Subclass of MonitorWaitExecutor, define its own event method(copy of parent
+ * method), intended for event filters test
+ */
+class MonitorWaitExecutor_2Subclass extends MonitorWaitExecutor_1Subclass {
+ public MonitorWaitExecutor_2Subclass(boolean monitorWait,
+ boolean monitorWaited) {
+ super(monitorWait, monitorWaited);
+ }
+
+ synchronized protected void eventMethod(long timeout)
+ throws InterruptedException {
+ wait(timeout);
+ }
+}
+
+/*
+ * This class generates MonitorContendedEnterEvent and
+ * MonitorContendedEnteredEvent
+ */
+class MonitorEnterExecutor extends EventActionsExecutor {
+ /*
+ * Types of monitor acquiring:
+ * - through synchronized block
+ * - through synchronized method
+ * - through JNI MonitorEnter
+ */
+ static enum MonitorAcquireType {
+ SYNCHRONIZED_BLOCK,
+ SYNCHRONIZED_METHOD,
+ JNI_MONITOR_ENTER
+ }
+
+ // native method uses this class
+ private static final Class<?> jniError = nsk.share.TestJNIError.class;
+
+
+ static final String nativeLibararyName = "MonitorEnterExecutor";
+
+ static {
+ System.loadLibrary(nativeLibararyName);
+ }
+
+ // this thread forces MonitorLockingThread to release holding lock
+ static class LockFreeThread extends Thread {
+ private Thread blockedThread;
+
+ private MonitorLockingThread lockingThread;
+
+ public LockFreeThread(Thread blockedThread,
+ MonitorLockingThread lockingThread) {
+ this.blockedThread = blockedThread;
+ this.lockingThread = lockingThread;
+ }
+
+ public void run() {
+ // wait when blocked thread switches state to 'BLOCKED'
+ while (blockedThread.getState() != Thread.State.BLOCKED)
+ yield();
+
+ lockingThread.releaseLock();
+ }
+ }
+
+ private boolean monitorEnter;
+
+ private boolean monitorEntered;
+
+ public MonitorEnterExecutor(boolean monitorEnter, boolean monitorEntered) {
+ this.monitorEnter = monitorEnter;
+ this.monitorEntered = monitorEntered;
+ }
+
+ protected void monitorEnter() {
+ // locking thread acquires 'this' lock
+ MonitorLockingThread lockingThread = new MonitorLockingThread(this);
+ lockingThread.acquireLock();
+
+ if (monitorEnter) {
+ DebuggeeEventData.DebugMonitorEnterEventData eventData = new DebuggeeEventData.DebugMonitorEnterEventData(
+ this, Thread.currentThread(), this);
+ addEventData(eventData);
+ }
+ if (monitorEntered) {
+ DebuggeeEventData.DebugMonitorEnteredEventData eventData = new DebuggeeEventData.DebugMonitorEnteredEventData(
+ this, Thread.currentThread(), this);
+ addEventData(eventData);
+ }
+
+ /*
+ * This thread forces lockingThread to free 'this' lock when current thread's state will change to 'BLOCKED'
+ *
+ * NOTE: this method to provoke MonitorContended events isn't 100% robust
+ * Tests should take in account this issue.
+ *
+ */
+ LockFreeThread lockFreeThread = new LockFreeThread(Thread.currentThread(), lockingThread);
+ lockFreeThread.start();
+
+ // try to acquire 'this' lock
+ eventMethod();
+
+ while(lockingThread.getState() != Thread.State.TERMINATED)
+ Thread.yield();
+
+ while(lockFreeThread.getState() != Thread.State.TERMINATED)
+ Thread.yield();
+ }
+
+ private MonitorAcquireType monitorAcquireType;
+
+ // generate events in different ways
+ public void doEventAction() {
+ for (MonitorAcquireType monitorAcquireType : MonitorAcquireType.values()) {
+ this.monitorAcquireType = monitorAcquireType;
+ monitorEnter();
+ }
+ }
+
+ protected void eventMethod() {
+ switch (monitorAcquireType) {
+ case SYNCHRONIZED_BLOCK:
+ synchronizedBlock();
+ break;
+ case SYNCHRONIZED_METHOD:
+ synchronizedMethod();
+ break;
+ case JNI_MONITOR_ENTER:
+ nativeJNIMonitorEnter();
+ break;
+
+ default:
+ throw new TestBug("Invalid monitorAcquireType: "
+ + monitorAcquireType);
+ }
+ }
+
+ // move event actions to the separate methods to simplify method
+ // redifinition in subclasses:
+
+ protected void synchronizedBlock() {
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized (this) {
+ // don't expect events for following synchronized block
+ synchronized (this) {
+ }
+ }
+ }
+
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized protected void synchronizedMethod() {
+ // don't expect events for following synchronized block
+ synchronized (this) {
+ }
+ }
+
+ // call JNI methods MonitorEnter and MonitorExit for 'this' object
+ protected native void nativeJNIMonitorEnter();
+
+}
+
+/*
+ * Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent
+ * method), intended for event filters test
+ */
+class MonitorEnterExecutor_1Subclass extends MonitorEnterExecutor {
+ static {
+ System.loadLibrary(nativeLibararyName);
+ }
+
+ public MonitorEnterExecutor_1Subclass(boolean monitorEnter,
+ boolean monitorEntered) {
+ super(monitorEnter, monitorEntered);
+ }
+
+ protected void synchronizedBlock() {
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized (this) {
+ }
+ }
+
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized protected void synchronizedMethod() {
+ }
+
+ // call JNI methods MonitorEnter and MonitorExit for 'this' object
+ protected native void nativeJNIMonitorEnter();
+}
+
+/*
+ * Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent
+ * method), intended for event filters test
+ */
+class MonitorEnterExecutor_2Subclass extends MonitorEnterExecutor_1Subclass {
+ static {
+ System.loadLibrary(nativeLibararyName);
+ }
+
+ public MonitorEnterExecutor_2Subclass(boolean monitorEnter,
+ boolean monitorEntered) {
+ super(monitorEnter, monitorEntered);
+ }
+
+ protected void synchronizedBlock() {
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized (this) {
+ }
+ }
+
+ // MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here
+ synchronized protected void synchronizedMethod() {
+ }
+
+ // call JNI methods MonitorEnter and MonitorExit for 'this' object
+ protected native void nativeJNIMonitorEnter();
+}
+
+/*
+ * Class is used as base debuggee in tests for following events and event requests:
+ * - MonitorContendedEnterRequest / MonitorContendedEnterEvent
+ * - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent
+ * - MonitorWaitRequest / MonitorWaitEvent
+ * - MonitorWaitedRequest / MonitorWaitedEvent
+ */
+public class MonitorEventsDebuggee extends JDIEventsDebuggee {
+ public static void main(String[] args) {
+ MonitorEventsDebuggee debuggee = new MonitorEventsDebuggee();
+ debuggee.doTest(args);
+ }
+
+ protected void createActionsExecutors(String description, int eventsCount) {
+ boolean monitorEnter = description
+ .contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTER
+ .name());
+ boolean monitorEntered = description
+ .contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTERED
+ .name());
+ boolean monitorWait = description
+ .contains(JDIEventsDebugger.EventType.MONITOR_WAIT.name());
+ boolean monitorWaited = description
+ .contains(JDIEventsDebugger.EventType.MONITOR_WAITED.name());
+
+ if (monitorEnter || monitorEntered || monitorWait || monitorWaited) {
+ createActionsExecutors(monitorEnter, monitorEntered, monitorWait,
+ monitorWaited, eventsCount);
+ } else
+ throw new TestBug(
+ "Invalid command format (required event not specified)");
+ }
+
+ private List<DebuggeeEventData.DebugMonitorEventData> eventsData = new ArrayList<DebuggeeEventData.DebugMonitorEventData>();
+
+ protected void clearResults() {
+ super.clearResults();
+ eventsData.clear();
+ }
+
+ private void createActionsExecutors(boolean monitorEnter,
+ boolean monitorEntered, boolean monitorWait, boolean monitorWaited,
+ int actionsCount) {
+ EventActionsThread thread;
+
+ // create 3 instances of generating objects of 3 different classes (for
+ // event filters tests)
+ if (monitorEnter || monitorEntered) {
+ thread = new EventActionsThread(new MonitorEnterExecutor(
+ monitorEnter, monitorEntered), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+
+ thread = new EventActionsThread(new MonitorEnterExecutor_1Subclass(
+ monitorEnter, monitorEntered), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+
+ thread = new EventActionsThread(new MonitorEnterExecutor_2Subclass(
+ monitorEnter, monitorEntered), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+ }
+
+ // create 3 instances of generating objects of 3 different classes (for
+ // event filters tests)
+ if (monitorWait || monitorWaited) {
+ thread = new EventActionsThread(new MonitorWaitExecutor(
+ monitorWait, monitorWaited), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+
+ thread = new EventActionsThread(new MonitorWaitExecutor_1Subclass(
+ monitorWait, monitorWaited), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+
+ thread = new EventActionsThread(new MonitorWaitExecutor_2Subclass(
+ monitorWait, monitorWaited), actionsCount);
+ thread.start();
+ eventActionsExecutorsPool.add(thread);
+ }
+ }
+
+ // start event generating threads and wait when all this threads finish
+ // execution
+ // override parent method because of Thread.join() used in parent method
+ // generates unexpected MonitorWait/MonitorWaited events
+ protected void startExecution() {
+ if (eventActionsExecutorsPool.size() == 0) {
+ throw new TestBug("ActionsExecutors were not created");
+ }
+
+ for (EventActionsThread thread : eventActionsExecutorsPool) {
+ thread.startExecution();
+ }
+
+ // wait completion of test threads in separate thread to free thread listening commands
+ executionControllingThread = new Thread(
+ new Runnable() {
+ public void run() {
+ boolean executionCompleted;
+ do {
+ try {
+ // give time to event generators
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ unexpectedException(e);
+ }
+ executionCompleted = true;
+ for (EventActionsThread thread : eventActionsExecutorsPool) {
+ if (thread.isAlive()) {
+ executionCompleted = false;
+ break;
+ }
+ }
+ } while (!executionCompleted);
+
+ completeExecution();
+ }
+ });
+
+ executionControllingThread.start();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.locks.LockingThread;
+import nsk.share.TestBug;
+
+/*
+ * Class is used as base debuggee in tests for ThreadReference.ownedMonitorsAndFrames().
+ *
+ * Class handle commands for creating threads which acquires and relinquish locks in different ways,
+ * nsk.share.locks.LockingThread is used for this purposes.
+ *
+ * Information about acquired monitors can be stored in static array 'monitorsInfo' and in this way this
+ * data is available for debugger.
+ */
+public class OwnedMonitorsDebuggee extends AbstractJDIDebuggee {
+ // command:threadName:stackFrameDescription
+ public static final String COMMAND_CREATE_LOCKING_THREAD = "createLockingThread";
+
+ // command:threadName
+ public static final String COMMAND_STOP_LOCKING_THREAD = "stopLockingThread";
+
+ // command:threadName
+ public static final String COMMAND_UPDATE_MONITOR_INFO = "updateMonitorInfo";
+
+ // command:threadName
+ public static final String COMMAND_EXIT_SINGLE_FRAME = "exitSingleFrame";
+
+ // command:threadName:monitorIndex
+ public static final String COMMAND_RELINQUISH_MONITOR = "relinquishMonitor";
+
+ // command:threadName
+ public static final String COMMAND_ACQUIRE_RELINQUISHED_MONITOR = "acquireRelinquishedMonitor";
+
+ // from this array information about acquired monitors is available for debugger
+ // (this class is used in stress tests where several tests are executed consecutively, but in this case using of
+ // static array shouldn't cause problems because of before using of array 'monitorsInfo' debugger
+ // uses COMMAND_UPDATE_MONITOR_INFO which updates this array with latest data, so excution of one test shouldn't
+ // affect other tests)
+ public static LockingThread.DebugMonitorInfo monitorsInfo[];
+
+ private boolean returnJNIMonitors;
+
+ public final static String mainThreadName = "OwnedMonitorDebuggeeMainThread";
+
+ protected String[] doInit(String[] args) {
+ Thread.currentThread().setName(mainThreadName);
+
+ args = super.doInit(args);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equalsIgnoreCase("-returnJNIMonitors")) {
+ returnJNIMonitors = true;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ public boolean parseCommand(String command) {
+ if (super.parseCommand(command))
+ return true;
+
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
+ tokenizer.whitespaceChars(':', ':');
+ tokenizer.wordChars('_', '_');
+
+ try {
+ if (command.startsWith(COMMAND_ACQUIRE_RELINQUISHED_MONITOR)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ acquireRelinquishMonitor(threadName);
+
+ return true;
+ } else if (command.startsWith(COMMAND_RELINQUISH_MONITOR)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
+ throw new TestBug("Invalid command format: " + command);
+
+ int monitorIndex = (int) tokenizer.nval;
+
+ relinquishMonitor(threadName, monitorIndex);
+
+ return true;
+ } else if (command.startsWith(COMMAND_CREATE_LOCKING_THREAD)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ List<String> stackFramesDescription = new ArrayList<String>();
+
+ while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
+ stackFramesDescription.add(tokenizer.sval);
+ }
+
+ createLockingThread(threadName, stackFramesDescription);
+ return true;
+ } else if (command.startsWith(COMMAND_STOP_LOCKING_THREAD)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ stopLockingThread(threadName);
+
+ return true;
+ } else if (command.startsWith(COMMAND_UPDATE_MONITOR_INFO)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ updateMonitorInfo(threadName);
+
+ return true;
+ } else if (command.startsWith(COMMAND_EXIT_SINGLE_FRAME)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String threadName = tokenizer.sval;
+
+ exitSingleFrame(threadName);
+
+ return true;
+ }
+ } catch (IOException e) {
+ throw new TestBug("Invalid command format: " + command);
+ }
+
+ return false;
+ }
+
+ public void acquireRelinquishMonitor(String threadName) {
+ LockingThread thread = getThread(threadName);
+ thread.acquireRelinquishedMonitor();
+
+ thread.waitState();
+ updateMonitorInfo(threadName);
+ }
+
+ public void relinquishMonitor(String threadName, int monitorIndex) {
+ LockingThread thread = getThread(threadName);
+ thread.relinquishMonitor(monitorIndex);
+
+ thread.waitState();
+ updateMonitorInfo(threadName);
+ }
+
+ private void updateMonitorInfo(String threadName) {
+ LockingThread thread = getThread(threadName);
+ monitorsInfo = thread.getMonitorsInfo(returnJNIMonitors);
+ }
+
+ private Map<String, LockingThread> threads = new TreeMap<String, LockingThread>();
+
+ private LockingThread getThread(String threadName) {
+ LockingThread thread = threads.get(threadName);
+
+ if (thread == null)
+ throw new TestBug("Locking thread with name: " + threadName + " was not created");
+
+ return thread;
+ }
+
+ private void stopLockingThread(String threadName) {
+ LockingThread thread = getThread(threadName);
+ thread.stopLockingThread();
+ thread.waitState();
+
+ updateMonitorInfo(threadName);
+ }
+
+ private void exitSingleFrame(String threadName) {
+ LockingThread thread = getThread(threadName);
+ thread.exitSingleFrame();
+ thread.waitState();
+
+ updateMonitorInfo(threadName);
+ }
+
+ private void createLockingThread(String threadName, List<String> stackFramesDescription) {
+ if (threads.get(threadName) != null)
+ throw new TestBug("Locking thread with name: " + threadName + " already exists");
+
+ LockingThread thread = new LockingThread(log, stackFramesDescription);
+ thread.setName(threadName);
+ thread.start();
+ thread.waitState();
+
+ threads.put(threadName, thread);
+
+ updateMonitorInfo(threadName);
+ }
+
+ public static void main(String args[]) {
+ OwnedMonitorsDebuggee debuggee = new OwnedMonitorsDebuggee();
+ debuggee.doTest(args);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/OwnedMonitorsDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+import com.sun.jdi.*;
+
+import nsk.share.Consts;
+
+/*
+ * Class is used as base debugger in tests for ThreadReference.ownedMonitorsAndFrames().
+ *
+ * In all this test similar scenario is used:
+ * - debugger VM force debugge VM to create test thread which acquires different monitors
+ * - when test thread acquire all monitors debuggee save information about all acquired monitors in special array 'monitorsInfo'
+ * - debugger read data from 'monitorsInfo' and compare it with data returned by ThreadReference.ownedMonitorsAndFrames()
+ */
+public class OwnedMonitorsDebugger extends TestDebuggerType2 {
+
+ /*
+ * debug data about monitor acquired by debuggee test thread,
+ * intended to compare with data returned by ThreadReference.ownedMonitorsAndFrames
+ */
+ public static class DebugMonitorInfo {
+ // create DebugMonitorInfo using mirror of instance of nsk.share.locks.LockingThread.DebugMonitorInfo
+ DebugMonitorInfo(ObjectReference debuggeeMirror) {
+ monitor = (ObjectReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("monitor"));
+ stackDepth = ((IntegerValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("stackDepth"))).intValue();
+ thread = (ThreadReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("thread"));
+ }
+
+ public DebugMonitorInfo(ObjectReference monitor, int stackDepth, ThreadReference thread) {
+ this.monitor = monitor;
+ this.stackDepth = stackDepth;
+ this.thread = thread;
+ }
+
+ public ObjectReference monitor;
+
+ public int stackDepth;
+
+ public ThreadReference thread;
+ }
+
+ public static void main(String argv[]) {
+ System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ }
+
+ public static int run(String argv[], PrintStream out) {
+ return new OwnedMonitorsDebugger().runIt(argv, out);
+ }
+
+ protected boolean canRunTest() {
+ if (!vm.canGetMonitorFrameInfo()) {
+ log.display("TEST CANCELED due to: vm.canGetMonitorFrameInfo() = false");
+ return false;
+ } else
+ return super.canRunTest();
+ }
+
+ protected String debuggeeClassName() {
+ return OwnedMonitorsDebuggee.class.getName();
+ }
+
+ // read debuggee's array 'monitorsInfo' containing information about acquired monitors
+ protected List<DebugMonitorInfo> getDebugMonitorsInfo() {
+ List<DebugMonitorInfo> result = new ArrayList<DebugMonitorInfo>();
+
+ ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs());
+ ArrayReference monitorsInfo = (ArrayReference) referenceType.getValue(referenceType.fieldByName("monitorsInfo"));
+
+ for (int i = 0; i < monitorsInfo.length(); i++)
+ result.add(new DebugMonitorInfo((ObjectReference) monitorsInfo.getValue(i)));
+
+ return result;
+ }
+
+ private boolean compare(MonitorInfo actual, DebugMonitorInfo expected) {
+ boolean success = true;
+
+ if (actual.stackDepth() != expected.stackDepth) {
+ setSuccess(false);
+ success = false;
+ log.complain("Expected and actual monitor(" + actual.monitor() + ") stack depth differs, expected: " + expected.stackDepth + " actual: "
+ + actual.stackDepth());
+ }
+
+ if (!actual.thread().equals(expected.thread)) {
+ setSuccess(false);
+ success = false;
+ log.complain("Expected and actual monitor(" + actual.monitor() + " thread differs, expected: " + expected.thread + " actual: "
+ + actual.thread());
+ }
+
+ return success;
+ }
+
+ protected void compare(List<MonitorInfo> actualData, List<DebugMonitorInfo> expectedData) {
+ boolean success = true;
+
+ // compare total amount of monitors
+ if (actualData.size() != expectedData.size()) {
+ setSuccess(false);
+ success = false;
+ log.complain("Number of expected monitors and actual ones differs");
+ log.complain("Expected: " + expectedData.size() + ", actual: " + actualData.size());
+ }
+
+ // check that all expected monitors are contained in 'actualData'
+ for (DebugMonitorInfo expectedMonitorInfo : expectedData) {
+ boolean isMonitorFound = false;
+
+ for (MonitorInfo actualMonitorInfo : actualData) {
+ if (expectedMonitorInfo.monitor.equals(actualMonitorInfo.monitor())) {
+ isMonitorFound = true;
+
+ if (!compare(actualMonitorInfo, expectedMonitorInfo))
+ success = false;
+
+ break;
+ }
+ }
+
+ if (!isMonitorFound) {
+ setSuccess(false);
+ success = false;
+ log.complain("Expected monitor not found in result of ownedMonitorsAndFrames(): " + expectedMonitorInfo.monitor);
+ }
+ }
+
+ // check that all monitors from 'actualData' are contained in
+ // 'expectedData'
+ for (MonitorInfo actualMonitorInfo : actualData) {
+ boolean isMonitorFound = false;
+
+ for (DebugMonitorInfo expectedMonitorInfo : expectedData) {
+ if (actualMonitorInfo.monitor().equals(expectedMonitorInfo.monitor)) {
+ isMonitorFound = true;
+ break;
+ }
+ }
+
+ if (!isMonitorFound) {
+ setSuccess(false);
+ success = false;
+ log.complain("Unexpected monitor in result of ownedMonitorsAndFrames(): " + actualMonitorInfo.monitor() + " Depth: "
+ + actualMonitorInfo.stackDepth() + " Thread: " + actualMonitorInfo.thread());
+ }
+ }
+
+ if (!success)
+ logDebugInfo(actualData, expectedData);
+ }
+
+ private void logDebugInfo(List<MonitorInfo> actualData, List<DebugMonitorInfo> expectedData) {
+ log.display("ACTUAL MONITORS (total " + actualData.size() + "):");
+
+ ThreadReference thread = null;
+
+ for (MonitorInfo monitorInfo : actualData) {
+ log.display("Monitor: " + monitorInfo.monitor());
+ log.display("Depth: " + monitorInfo.stackDepth());
+ log.display("Thread: " + monitorInfo.thread());
+ if (thread == null)
+ thread = monitorInfo.thread();
+ }
+
+ log.display("EXPECTED MONITORS (total " + expectedData.size() + "):");
+
+ for (DebugMonitorInfo monitorInfo : expectedData) {
+ log.display("Monitor: " + monitorInfo.monitor);
+ log.display("Depth: " + monitorInfo.stackDepth);
+ log.display("Thread: " + monitorInfo.thread);
+ if (thread == null)
+ thread = monitorInfo.thread;
+ }
+
+ if (thread != null) {
+ try {
+ log.display("Thread frames:");
+ for (StackFrame frame : thread.frames()) {
+ Location location = frame.location();
+ log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber());
+ }
+ } catch (Exception e) {
+ unexpectedException(e);
+ }
+ }
+ }
+
+ /*
+ * Check that ThreadReference.ownedMonitorsAndFrames() returns correct
+ * data before calling this method debuggee should save information about
+ * acquired monitors in special array 'monitorsInfo',
+ * debugger forces debuggee to do it using command 'COMMAND_UPDATE_MONITOR_INFO'
+ */
+ protected void checkMonitorInfo(ThreadReference threadReference) {
+ List<MonitorInfo> actualData = null;
+
+ try {
+ actualData = threadReference.ownedMonitorsAndFrames();
+ } catch (Exception e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ List<DebugMonitorInfo> expectedData = getDebugMonitorsInfo();
+
+ compare(actualData, expectedData);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugConnectors.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+/*
+ * A Super class for pluggable connectors used by
+ * nsk/jdi/PlugConnectors tests
+ */
+
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+import java.io.*;
+import java.util.*;
+
+public class PlugConnectors implements Connector {
+
+ String plugConnectorName = "Undefined_PlugConnector_Name";
+ String plugConnectorDescription = "Undefined_PlugConnector_Description";
+ Transport plugConnectorTransport = new PlugConnectorsTransport();
+ Map<java.lang.String,com.sun.jdi.connect.Connector.Argument> plugConnectorDefaultArguments = new HashMap<java.lang.String,com.sun.jdi.connect.Connector.Argument>();
+
+ /*
+ * Simple implementation of Connector.Argument
+ */
+ public static class TestArgument implements Connector.Argument {
+ String argName;
+ String argLabel;
+ String argDescription;
+ String argStringValue;
+ boolean argMustSpecify;
+
+ public TestArgument(
+ String argName,
+ String argLabel,
+ String argDescription,
+ String argValue,
+ boolean argMustSpecify) {
+
+ this.argName = argName;
+ this.argLabel = argLabel;
+ this.argDescription = argDescription;
+ this.argStringValue = argValue;
+ this.argMustSpecify = argMustSpecify;
+ }
+
+ public String name() {
+ return argName;
+ }
+
+ public String label() {
+ return argLabel;
+ }
+
+ public String description() {
+ return argDescription;
+ }
+
+ public String value() {
+ return argStringValue;
+ }
+
+ public void setValue(String argValue) {
+ this.argStringValue = argValue;
+ }
+
+ public boolean isValid(String argValue) {
+ if ( argValue != null ) {
+ if (argValue.length() > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean mustSpecify() {
+ return argMustSpecify;
+ }
+ } // end of TestArgument static class
+
+ /*
+ * Simple implementation of Connector.StringArgument
+ */
+ public static class TestStringArgument extends TestArgument implements Connector.StringArgument {
+
+ public TestStringArgument( String argName,
+ String argLabel,
+ String argDescription,
+ String argValue,
+ boolean argMustSpecify) {
+
+ super(argName, argLabel, argDescription, argValue, argMustSpecify);
+ }
+
+ } // end of TestStringArgument static class
+
+ /*
+ * Simple implementation of Connector.IntegerArgument
+ */
+ public static class TestIntegerArgument extends TestArgument implements Connector.IntegerArgument {
+
+ int argIntValue;
+ int minArgIntValue;
+ int maxArgIntValue;
+
+ public TestIntegerArgument(String argName,
+ String argLabel,
+ String argDescription,
+ int argValue,
+ int minArgIntValue,
+ int maxArgIntValue,
+ boolean argMustSpecify) {
+
+ super(argName, argLabel, argDescription, "" + argValue, argMustSpecify);
+ this.argIntValue = argValue;
+ this.minArgIntValue = minArgIntValue;
+ this.maxArgIntValue = maxArgIntValue;
+
+ }
+
+ public int intValue() {
+ return argIntValue;
+ }
+
+ public boolean isValid(int value) {
+ if ( value >= minArgIntValue && value <= maxArgIntValue ) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isValid(String stringValue) {
+ int intValue;
+ try {
+ intValue = Integer.parseInt(stringValue);
+ } catch (NumberFormatException exception) {
+ return false;
+ }
+ return isValid(intValue);
+ }
+
+ public int max() {
+ return maxArgIntValue;
+ }
+
+ public int min() {
+ return minArgIntValue;
+ }
+
+ public void setValue(int value) {
+ argIntValue = value;
+ }
+
+ public String stringValueOf(int value) {
+ return "" + value;
+ }
+
+ } // end of TestIntegerArgument static class
+
+ /*
+ * Simple implementation of Connector.BooleanArgument
+ */
+ public static class TestBooleanArgument extends TestArgument implements Connector.BooleanArgument {
+
+ static final String argStringValueTrue = "true";
+ static final String argStringValueFalse = "false";
+ boolean argBooleanValue;
+
+ public TestBooleanArgument(String argName,
+ String argLabel,
+ String argDescription,
+ boolean argValue,
+ boolean argMustSpecify) {
+
+ super(argName, argLabel, argDescription,
+ argValue ? argStringValueTrue : argStringValueFalse,
+ argMustSpecify);
+ this.argBooleanValue = argValue;
+
+ }
+
+ public boolean booleanValue() {
+ return argBooleanValue;
+ }
+
+ public boolean isValid(String stringValue) {
+ if ( argStringValueTrue.equals(stringValue) || argStringValueFalse.equals(stringValue) ) {
+ return true;
+ }
+ return false;
+ }
+
+ public void setValue(boolean value) {
+ argBooleanValue = value;
+ }
+
+ public String stringValueOf(boolean value) {
+ if ( value ) {
+ return argStringValueTrue;
+ }
+ return argStringValueFalse;
+ }
+
+ } // end of TestBooleanArgument static class
+
+ /*
+ * Simple implementation of Connector.SelectedArgument
+ */
+ public static class TestSelectedArgument extends TestArgument implements Connector.SelectedArgument {
+
+ List<String> acceptableArgsList;
+
+ public TestSelectedArgument( String argName,
+ String argLabel,
+ String argDescription,
+ String argValue,
+ List<String> acceptableArgsList,
+ boolean argMustSpecify) {
+
+ super(argName, argLabel, argDescription, argValue, argMustSpecify);
+ this.acceptableArgsList = acceptableArgsList;
+ }
+
+ public List<String> choices() {
+ return acceptableArgsList;
+ }
+
+ public boolean isValid(String stringValue) {
+
+ return acceptableArgsList.contains(stringValue);
+ }
+
+ } // end of TestSelectedArgument static class
+
+ public PlugConnectors(
+ String plugConnectorName,
+ String plugConnectorDescription,
+ Transport plugConnectorTransport,
+ Map<java.lang.String,com.sun.jdi.connect.Connector.Argument> plugConnectorDefaultArguments
+ ) {
+
+ this.plugConnectorName = plugConnectorName;
+ this.plugConnectorDescription = plugConnectorDescription;
+ this.plugConnectorTransport = plugConnectorTransport;
+ this.plugConnectorDefaultArguments = plugConnectorDefaultArguments;
+ }
+
+ public String name() {
+ return plugConnectorName;
+ }
+
+ public String description() {
+ return plugConnectorDescription;
+ }
+
+ public Transport transport() {
+ return plugConnectorTransport;
+ }
+
+ public Map<java.lang.String,com.sun.jdi.connect.Connector.Argument> defaultArguments() {
+ return plugConnectorDefaultArguments;
+ }
+
+ public VirtualMachine launch(Map<String,? extends Connector.Argument> arguments) throws
+ IOException,
+ IllegalConnectorArgumentsException,
+ VMStartException {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of launch(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public VirtualMachine attach(Map<String,? extends Connector.Argument> arguments) throws
+ java.io.IOException,
+ IllegalConnectorArgumentsException {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of attach(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public String startListening(Map<String,? extends Connector.Argument> arguments) throws
+ java.io.IOException,
+ IllegalConnectorArgumentsException {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of startListening(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public void stopListening(Map<String,? extends Connector.Argument> arguments) throws
+ java.io.IOException,
+ IllegalConnectorArgumentsException {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of stopListening(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+ }
+
+ public VirtualMachine accept(Map<String,? extends Connector.Argument> arguments) throws
+ java.io.IOException,
+ IllegalConnectorArgumentsException {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of accept(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public boolean supportsMultipleConnections() {
+
+ String exceptionMessage = "## PlugConnectors: Connector name = '" +
+ plugConnectorName + "';\nNon-authorized call of supportsMultipleConnections() method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return false;
+ }
+
+ public static class PlugConnectorsTransport implements Transport {
+
+ String transportName = "Undefined_Transport_Name";
+
+ public PlugConnectorsTransport() {
+ }
+
+ public PlugConnectorsTransport(String transportName) {
+ this.transportName = transportName;
+ }
+
+ public String name() {
+ return transportName;
+ }
+
+ } // end of PlugConnectorsTransport class
+
+ // Auxiliary general purpose methods for pluggable connectors' tests.
+
+ public static String compareConnectors(
+ String errorLogPrefixHead,
+ String errorLogPrefix,
+ Connector referenceConnector,
+ Connector checkedConnector) {
+
+ String emptyString = "";
+ String errorMessage = emptyString;
+
+ // check that connectors have the same name
+ String referenceConnectorName = referenceConnector.name();
+ String checkedConnectorName = checkedConnector.name();
+ if ( ! referenceConnectorName.equals(checkedConnectorName) ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked pluggable Connector has unexpected name:\n"
+ + errorLogPrefix + "Expected Connector's name = '" + referenceConnectorName + "'\n"
+ + errorLogPrefix + "Actual Connector's name = '" + checkedConnectorName + "'\n";
+ }
+
+ // check that connectors have the same description
+ String referenceConnectorDescription = referenceConnector.description();
+ String checkedConnectorDescription = checkedConnector.description();
+ if ( ! referenceConnectorDescription.equals(checkedConnectorDescription) ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked pluggable Connector has unexpected description:\n"
+ + errorLogPrefix + "Expected Connector's description = '" + referenceConnectorDescription + "'\n"
+ + errorLogPrefix + "Actual Connector's description = '" + checkedConnectorDescription + "'\n";
+ }
+
+ // check that connectors have the same transport name
+ String referenceConnectorTransportName = referenceConnector.transport().name();
+ String checkedConnectorTransportName = checkedConnector.transport().name();
+ if ( ! referenceConnectorTransportName.equals(checkedConnectorTransportName) ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked pluggable Connector has unexpected transport name:\n"
+ + errorLogPrefix + "Expected Connector's transport name = '" + referenceConnectorTransportName + "'\n"
+ + errorLogPrefix + "Actual Connector's transport name = '" + checkedConnectorTransportName + "'\n";
+ }
+
+ // check that connectors have the same number of default arguments
+ int referenceConnectorArgumentsNumber = referenceConnector.defaultArguments().size();
+ int checkedConnectorArgumentsNumber = checkedConnector.defaultArguments().size();
+ if ( referenceConnectorArgumentsNumber != checkedConnectorArgumentsNumber ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked pluggable Connector has unexpected number of default arguments:\n"
+ + errorLogPrefix + "Expected number of default arguments = '" + referenceConnectorArgumentsNumber + "'\n"
+ + errorLogPrefix + "Actual number of default arguments = '" + checkedConnectorArgumentsNumber + "'\n";
+ }
+
+
+ return errorMessage;
+ } // end of compareConnectors(...) method
+
+ public static String compareConnectorArguments(
+ String errorLogPrefixHead,
+ String errorLogPrefix,
+ Connector.Argument referenceArgument,
+ Connector.Argument checkedArgument) {
+
+ String emptyString = "";
+ String errorMessage = emptyString;
+
+ if ( referenceArgument == null ) {
+ errorMessage =
+ errorLogPrefixHead + "Reference connector's argument is null!\n";
+ }
+
+ if ( checkedArgument == null ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked connector's argument is null!\n";
+ }
+
+ if ( ! errorMessage.equals(emptyString) ) {
+ return errorMessage;
+ }
+
+ String referenceArgumentName = referenceArgument.name();
+ String checkedArgumentName = checkedArgument.name();
+ if ( ! referenceArgumentName.equals(checkedArgumentName) ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's argument has unexpected name:\n"
+ + errorLogPrefix + "Expected connector's argument name = '" + referenceArgumentName + "'\n"
+ + errorLogPrefix + "Actual connector's argument name = '" + checkedArgumentName + "'";
+ return errorMessage;
+ }
+
+ String referenceArgumentLabel = referenceArgument.label();
+ String checkedArgumentLabel = checkedArgument.label();
+ if ( ! referenceArgumentLabel.equals(checkedArgumentLabel) ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's argument has unexpected label:\n"
+ + errorLogPrefix + "Expected connector's argument label = '" + referenceArgumentLabel + "'\n"
+ + errorLogPrefix + "Actual connector's argument label = '" + checkedArgumentLabel + "'";
+ return errorMessage;
+ }
+
+ String referenceArgumentDescription = referenceArgument.description();
+ String checkedArgumentDescription = checkedArgument.description();
+ if ( ! referenceArgumentDescription.equals(checkedArgumentDescription) ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's argument has unexpected description:\n"
+ + errorLogPrefix + "Expected connector's argument description = '" + referenceArgumentDescription + "'\n"
+ + errorLogPrefix + "Actual connector's argument description = '" + checkedArgumentDescription + "'";
+ return errorMessage;
+ }
+
+ String referenceArgumentValue = referenceArgument.value();
+ String checkedArgumentValue = checkedArgument.value();
+ if ( ! referenceArgumentValue.equals(checkedArgumentValue) ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's argument has unexpected value:\n"
+ + errorLogPrefix + "Expected connector's argument value = '" + referenceArgumentValue + "'\n"
+ + errorLogPrefix + "Actual connector's argument value = '" + checkedArgumentValue + "'";
+ return errorMessage;
+ }
+
+ boolean referenceArgumentMustSpecify = referenceArgument.mustSpecify();
+ boolean checkedArgumentMustSpecify = checkedArgument.mustSpecify();
+ if ( referenceArgumentMustSpecify != checkedArgumentMustSpecify ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's argument has unexpected 'mustSpecify' property:\n"
+ + errorLogPrefix + "Expected connector's argument 'mustSpecify' property = '"
+ + referenceArgumentMustSpecify + "'\n"
+ + errorLogPrefix + "Actual connector's argument 'mustSpecify' property = '"
+ + checkedArgumentMustSpecify + "'";
+ return errorMessage;
+ }
+
+ if ( referenceArgument instanceof Connector.IntegerArgument ) {
+
+ int referenceArgumentMin = ((Connector.IntegerArgument)referenceArgument).min();
+ int checkedArgumentMin = ((Connector.IntegerArgument)checkedArgument).min();
+ if ( referenceArgumentMin != checkedArgumentMin ) {
+ errorMessage =
+ errorLogPrefixHead + "Checked connector's integer argument has unexpected min value:\n"
+ + errorLogPrefix + "Expected connector's argument min value = "
+ + referenceArgumentMin + "\n"
+ + errorLogPrefix + "Actual connector's argument min value = "
+ + checkedArgumentMin + "\n";
+ }
+
+ int referenceArgumentMax = ((Connector.IntegerArgument)referenceArgument).max();
+ int checkedArgumentMax = ((Connector.IntegerArgument)checkedArgument).max();
+ if ( referenceArgumentMax != checkedArgumentMax ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked connector's integer argument has unexpected max value:\n"
+ + errorLogPrefix + "Expected connector's argument max value = "
+ + referenceArgumentMax + "\n"
+ + errorLogPrefix + "Actual connector's argument max value = "
+ + checkedArgumentMax + "\n";
+ }
+
+ }
+
+ if ( referenceArgument instanceof Connector.SelectedArgument ) {
+
+ List referenceArgumentChoices = ((Connector.SelectedArgument)referenceArgument).choices();
+ List checkedArgumentChoices = ((Connector.SelectedArgument)checkedArgument).choices();
+
+ int referenceArgumentChoicesSize = referenceArgumentChoices.size();
+ int checkedArgumentChoicesSize = checkedArgumentChoices.size();
+
+ if ( referenceArgumentChoicesSize != checkedArgumentChoicesSize) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked connector's Selected argument has unexpected choices' size:\n"
+ + errorLogPrefix + "Expected size = '"
+ + referenceArgumentChoicesSize + "'\n"
+ + errorLogPrefix + "Actual size = "
+ + checkedArgumentChoicesSize;
+ return errorMessage;
+ }
+
+ for (int i=0; i < referenceArgumentChoicesSize; i++) {
+ String referenceArgumentChoice = (String)(referenceArgumentChoices.get(i));
+ if ( ! checkedArgumentChoices.contains(referenceArgumentChoice) ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked connector's Selected argument has NOT expected choices' element:\n"
+ + errorLogPrefix + "Expected choices' element = '"
+ + referenceArgumentChoice + "'\n";
+ }
+
+ String checkedArgumentChoice = (String)(checkedArgumentChoices.get(i));
+ if ( ! referenceArgumentChoices.contains(checkedArgumentChoice) ) {
+ errorMessage = errorMessage +
+ errorLogPrefixHead + "Checked connector's Selected argument has unexpected choices' element:\n"
+ + errorLogPrefix + "Unexpected choices' element = '"
+ + checkedArgumentChoice + "'\n";
+ }
+ }
+ }
+ return errorMessage;
+ } // end of compareConnectorArguments(...) method
+
+ public static Connector.Argument getConnectorDefaultArgument(
+ Connector connector,
+ String argumentName) {
+
+ Connector.Argument foundArgument = null;
+
+ Map connectorDefaultArguments = connector.defaultArguments();
+ Object[] defaultArgumentsArray = connectorDefaultArguments.values().toArray();
+
+ for (int i=0; i < defaultArgumentsArray.length; i++) {
+ Connector.Argument connectorArgument = (Connector.Argument)defaultArgumentsArray[i];
+ if ( argumentName.equals(connectorArgument.name()) ) {
+ foundArgument = connectorArgument;
+ break;
+ }
+ }
+ return foundArgument;
+ }
+
+} // end of PlugConnectors class
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/PlugTransportService.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+/*
+ * A Super class for Transport Services used by
+ * nsk/jdi/PlugConnectors tests
+ */
+
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+import com.sun.jdi.connect.spi.*;
+import java.io.*;
+import java.util.*;
+
+public class PlugTransportService extends TransportService {
+
+ String plugTransportServiceName = "Undefined_PlugTransportService_Name";
+ String plugTransportServiceDescription = "Undefined_PlugTransportService_Description";
+ TransportService.Capabilities plugTransportServiceCapabilities = new TestCapabilities();
+
+ /*
+ * Simple implementation of TransportService.Capabilities
+ */
+ public static class TestCapabilities extends TransportService.Capabilities {
+ boolean supportsAcceptTimeout = false;
+ boolean supportsAttachTimeout = false;
+ boolean supportsHandshakeTimeout = false;
+ boolean supportsMultipleConnections = false;
+
+ public TestCapabilities() {
+ }
+
+ public TestCapabilities(
+ boolean supportsAcceptTimeout,
+ boolean supportsAttachTimeout,
+ boolean supportsHandshakeTimeout,
+ boolean supportsMultipleConnections) {
+
+ this.supportsAcceptTimeout = supportsAcceptTimeout;
+ this.supportsAttachTimeout = supportsAttachTimeout;
+ this.supportsHandshakeTimeout = supportsHandshakeTimeout;
+ this.supportsMultipleConnections = supportsMultipleConnections;
+ }
+
+ public boolean supportsAcceptTimeout() {
+ return supportsAcceptTimeout;
+ }
+
+ public boolean supportsAttachTimeout() {
+ return supportsAttachTimeout;
+ }
+
+ public boolean supportsHandshakeTimeout() {
+ return supportsHandshakeTimeout;
+ }
+
+ public boolean supportsMultipleConnections() {
+ return supportsMultipleConnections;
+ }
+
+ } // end of TestCapabilities static class
+
+ /*
+ * Simple implementation of TransportService.ListenKey
+ */
+ public static class TestListenKey extends TransportService.ListenKey {
+ String address = null;
+
+ public TestListenKey() {
+ }
+
+ public TestListenKey(String address) {
+
+ this.address = address;
+ }
+
+ public String address() {
+ return address;
+ }
+
+ } // end of TestListenKey static class
+
+ public PlugTransportService() {
+ }
+
+ public PlugTransportService(
+ String plugTransportServiceName,
+ String plugTransportServiceDescription,
+ TransportService.Capabilities plugTransportServiceCapabilities
+ ) {
+
+ this.plugTransportServiceName = plugTransportServiceName;
+ this.plugTransportServiceDescription = plugTransportServiceDescription;
+ this.plugTransportServiceCapabilities = plugTransportServiceCapabilities;
+ }
+
+ public String name() {
+ return plugTransportServiceName;
+ }
+
+ public String description() {
+ return plugTransportServiceDescription;
+ }
+
+ public TransportService.Capabilities capabilities() {
+ return plugTransportServiceCapabilities;
+ }
+
+ public Connection attach(
+ String address,
+ long attachTimeout,
+ long handshakeTimeout) throws IOException {
+
+ String exceptionMessage = "## PlugTransportService: TransportService name = '" +
+ plugTransportServiceName + "';\nNon-authorized call of attach(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public TransportService.ListenKey startListening(String address) throws IOException {
+
+ String exceptionMessage = "## PlugTransportService: TransportService name = '" +
+ plugTransportServiceName + "';\nNon-authorized call of startListening(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public TransportService.ListenKey startListening() throws IOException {
+
+ String exceptionMessage = "## PlugTransportService: TransportService name = '" +
+ plugTransportServiceName + "';\nNon-authorized call of startListening() method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ public void stopListening(TransportService.ListenKey listenKey) throws IOException {
+
+ String exceptionMessage = "## PlugTransportService: TransportService name = '" +
+ plugTransportServiceName + "';\nNon-authorized call of stopListening() method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+ }
+
+ public Connection accept(
+ TransportService.ListenKey listenKey,
+ long acceptTimeout,
+ long handshakeTimeout) throws IOException {
+
+ String exceptionMessage = "## PlugTransportService: TransportService name = '" +
+ plugTransportServiceName + "';\nNon-authorized call of accept(...) method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+
+ return null;
+ }
+
+ /*
+ * Simple implementation of Connection
+ */
+ public static class PlugTransportServiceConnection extends Connection {
+
+ public void close() throws IOException {
+ String exceptionMessage =
+ "## PlugTransportConnection: \nNon-authorized call of close() method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+ }
+
+ public boolean isOpen() {
+ String exceptionMessage =
+ "## PlugTransportConnection: \nNon-authorized call of isOpen() method!";
+
+ if ( true ) {
+ throw new RuntimeException(exceptionMessage);
+ }
+ return false;
+ }
+
+ public byte[] readPacket() throws IOException {
+ String exceptionMessage =
+ "## PlugTransportConnection: \nNon-authorized call of readPacket() method!";
+
+ if ( true ) {
+ throw new ClosedConnectionException(exceptionMessage);
+ }
+
+ if ( true ) {
+ throw new ClosedConnectionException();
+ }
+
+ return null;
+ }
+
+ public void writePacket(byte[] pkt) throws IOException {
+ String exceptionMessage =
+ "## PlugTransportConnection: \nNon-authorized call of writePacket(...) method!";
+
+ if ( true ) {
+ throw new ClosedConnectionException(exceptionMessage);
+ }
+
+ if ( true ) {
+ throw new ClosedConnectionException();
+ }
+
+ }
+
+ } // end of PlugTransportServiceConnection class
+
+} // end of PlugTransportService class
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import nsk.share.Consts;
+
+/*
+ * This class is intended for execution several JDI tests in single VM and used together with nsk.share.jdi.SerialExecutionDebugger
+ *
+ * SerialExecutionDebuggee handles 2 commands:
+ * - COMMAND_EXECUTE_DEBUGGEE:<debuggee_class_name> :
+ * initialize 'currentDebuggee' with instance of class 'debuggee_class_name'(this class should
+ * be subclass of nsk.share.jpda.AbstractDebugeeTest) and execute it's method doTest()
+ *
+ * - COMMAND_CLEAR_DEBUGGEE
+ * set 'currentDebuggee' to null
+ *
+ * For more detailed description of serial test execution see SerialExecutionDebugger
+ */
+public class SerialExecutionDebuggee extends AbstractJDIDebuggee {
+ public static void main(String args[]) {
+ new SerialExecutionDebuggee().doTest(args);
+ }
+
+ // command:<debuggee_class_name>[ debugee_parameters]
+ public static final String COMMAND_EXECUTE_DEBUGGEE = "COMMAND_EXECUTE_DEBUGGEE";
+
+ public static final String COMMAND_CLEAR_DEBUGGEE = "COMMAND_CLEAR_DEBUGGEE";
+
+ private AbstractJDIDebuggee currentDebuggee;
+
+ public boolean parseCommand(String command) {
+ if (super.parseCommand(command))
+ return true;
+
+ if (command.startsWith(COMMAND_EXECUTE_DEBUGGEE)) {
+ String debuggeeClassName = null;
+
+ try {
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
+ tokenizer.resetSyntax();
+ tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ tokenizer.whitespaceChars(':', ':');
+
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) {
+ log.complain("Invalid command format: " + command);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ debuggeeClassName = tokenizer.sval;
+ } catch (IOException e) {
+ log.complain("Invalid command format: " + command);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ try {
+ // parse debuggee parameters
+ String[] debuggeeParameters = {};
+
+ int index = debuggeeClassName.indexOf(' ');
+
+ if (index > 0) {
+ debuggeeParameters = debuggeeClassName.substring(index).split(" ");
+ log.display("Debuggee parameters: " + debuggeeClassName.substring(index));
+ debuggeeClassName = debuggeeClassName.substring(0, index);
+ }
+
+ // create debuggee object
+ Class debuggeeClass = Class.forName(debuggeeClassName);
+
+ if (!AbstractJDIDebuggee.class.isAssignableFrom(debuggeeClass)) {
+ log.complain("Invalid debugee class: " + debuggeeClass);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ currentDebuggee = (AbstractJDIDebuggee) debuggeeClass.newInstance();
+
+ // pass to the current debuggee already created objects:
+ // argHandler, log, pipe
+ currentDebuggee.initDebuggee(argHandler, log, pipe, debuggeeParameters, false);
+ } catch (Exception e) {
+ log.complain("Unexpected exception during debuggee initialization: " + e);
+ e.printStackTrace(log.getOutStream());
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ try {
+ // current debuggee performs test
+ currentDebuggee.doTest();
+
+ if (currentDebuggee.getSuccess()) {
+ log.display("Debuggee " + currentDebuggee + " finished successfully");
+ } else {
+ setSuccess(false);
+ log.complain("Debuggee " + currentDebuggee + "finished with errors");
+ }
+
+ return true;
+ } catch (Exception e) {
+ log.complain("Unexpected exception during debuggee execution: " + e);
+ e.printStackTrace(log.getOutStream());
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ } else if (command.equals(COMMAND_CLEAR_DEBUGGEE)) {
+ currentDebuggee = null;
+
+ return true;
+ }
+
+ return false;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/SerialExecutionDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import nsk.share.Consts;
+import nsk.share.TestBug;
+import nsk.share.jpda.AbstractDebuggeeTest;
+import java.io.*;
+import java.util.*;
+
+/*
+ * This class serial executes several JDI tests based on nsk.share.jdi.TestDebuggerType2 in single VM
+ * SerialExecutionDebugger is used together with SerialExecutionDebuggee, execution process is following:
+ *
+ * - SerialExecutionDebugger reads tests to execute from input file, test description is debugger class name and test's parameters,
+ * if 'shuffle' option is specified in input file debugger executes tests in random order (input file should contain line "OPTIONS:shuffle").
+ * SerialExecutionDebugger can execute tests several times in loop, number of iterations should be specified in input file in following manner:
+ * OPTIONS:iterations <iterations_number>.
+ *
+ * - SerialExecutionDebugger starts debuggee VM with main class SerialExecutionDebuggee,
+ * initializes IOPipe and 'debuggee' object which represents debuggee VM
+ *
+ * - for each test from input file:
+ *
+ * - SerialExecutionDebugger creates object of current debugger and initializes it with already created pipe and debuggee
+ * - SerialExecutionDebugger sends command to SerialExecutionDebuggee: 'COMMAND_EXECUTE_DEBUGGEE <CurrentDebuggeeName>'
+ * (CurrentDebuggeeName name should provide current debugger), and waits READY signal from debuggee
+ * - SerialExecutionDebuggee parses received command, extracts debugee name, creates object of current debuggee, which should be
+ * subclass of nsk.share.jpda.AbstractDebuggeeTestName
+ * - SerialExecutionDebuggee executes current debuggee's method 'doTest()', in this method debuggee sends signal READY
+ * and waits debugger command
+ * - SerialExecutionDebugger receives signal READY and executes current debugger's method 'doTest()', in
+ * this method debugger should perform test
+ * - when debugger method doTest() finishes SerialExecutionDebugger checks is this test passed or failed and
+ * sends command QUIT to the current debuggee, and when current debuggee finishes sends command 'COMMAND_CLEAR_DEBUGGEE' to the SerialExecutionDebuggee,
+ * after this command SerialExecutionDebugger and SerialExecutionDebuggee ready to execute next test
+ *
+ * - when all tests was executed SerialExecutionDebugger sends command QUIT to the SerialExecutionDebuggee and exits
+ *
+ * SerialExecutionDebugger requires "-configFile <ini-file>" parameter, <ini-file> - file with list of tests for execution
+ */
+public class SerialExecutionDebugger extends TestDebuggerType2 {
+ static public void main(String[] args) {
+ System.exit(Consts.JCK_STATUS_BASE + new SerialExecutionDebugger().runIt(args, System.out));
+ }
+
+ public String debuggeeClassName() {
+ return SerialExecutionDebuggee.class.getName();
+ }
+
+ // contains test's debugger class name and test parameters
+ static class Test {
+ public Test(String debuggerClassName, String[] arguments) {
+ this.debuggerClassName = debuggerClassName;
+ this.arguments = arguments;
+ }
+
+ public String argumentsToString() {
+ String result = "";
+
+ for (String argument : arguments)
+ result += argument + " ";
+
+ return result;
+ }
+
+ String debuggerClassName;
+
+ String arguments[];
+ }
+
+ private Test tests[];
+
+ // how many times execute tests
+ private int iterations = 1;
+
+ // requires "-configFile <ini-file>" parameter, <ini-file> - file with list
+ // of tests for execution
+ protected String[] doInit(String args[], PrintStream out) {
+ args = super.doInit(args, out);
+
+ String configFileName = null;
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-configFile") && (i < args.length - 1)) {
+ configFileName = args[i + 1];
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ if (configFileName == null) {
+ throw new TestBug("Config file wasn't specified (use option -configFile <file name>)");
+ }
+
+ tests = parseConfigFile(configFileName);
+
+ if (tests.length == 0)
+ throw new TestBug("Tests to run were not specified");
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ // read test names and test parameters from ini-file
+ private Test[] parseConfigFile(String fileName) {
+ List<Test> result = new ArrayList<Test>();
+
+ boolean shuffle = false;
+
+ try {
+ File file = new File(fileName);
+
+ LineNumberReader lineReader = new LineNumberReader(new FileReader(file));
+
+ String line = null;
+
+ while ((line = lineReader.readLine()) != null) {
+ // skip empty lines and comments started with '#"
+ if (line.length() == 0 || line.startsWith("#"))
+ continue;
+
+ if (line.startsWith("OPTIONS:")) {
+ String arguments[] = line.substring(8).split(" ");
+
+ for (int i = 0; i < arguments.length; i++) {
+ if (arguments[i].equalsIgnoreCase("shuffle"))
+ shuffle = true;
+ else if (arguments[i].equalsIgnoreCase("iterations") && (i < (arguments.length - 1))) {
+ iterations = Integer.parseInt(arguments[i + 1]);
+ i++;
+ }
+ }
+
+ continue;
+ }
+
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line));
+ tokenizer.resetSyntax();
+ tokenizer.wordChars(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ tokenizer.whitespaceChars(' ', ' ');
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid ini file format");
+
+ String testClassName = tokenizer.sval;
+ List<String> parameters = new ArrayList<String>();
+
+ int token;
+ while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
+ if (token == StreamTokenizer.TT_WORD) {
+ if (tokenizer.sval.equals("$CLASSPATH"))
+ parameters.add(classpath);
+ else
+ parameters.add(tokenizer.sval);
+ }
+
+ if (token == StreamTokenizer.TT_NUMBER) {
+ parameters.add("" + tokenizer.nval);
+ }
+ }
+
+ result.add(new Test(testClassName, parameters.toArray(new String[] {})));
+ }
+
+ } catch (IOException e) {
+ throw new TestBug("Exception during config file parsing: " + e);
+ }
+
+ if (shuffle) {
+ if (testWorkDir == null)
+ throw new TestBug("Debugger requires -testWorkDir parameter");
+
+ Collections.shuffle(result);
+
+ // save resulted tests sequence in file (to simplify reproducing)
+ try {
+ File file = new File(testWorkDir + File.separator + "run.tests");
+ file.createNewFile();
+
+ PrintWriter writer = new PrintWriter(new FileWriter(file));
+
+ for (Test test : result) {
+ writer.println(test.debuggerClassName + " " + test.argumentsToString());
+ }
+
+ writer.close();
+ } catch (IOException e) {
+ throw new TestBug("Unexpected IOException: " + e);
+ }
+ }
+
+ System.out.println("Tests execution order: ");
+ for (Test test : result) {
+ System.out.println(test.debuggerClassName + " " + test.argumentsToString());
+ }
+
+ return result.toArray(new Test[] {});
+ }
+
+ public void doTest() {
+
+ stresser.start(iterations);
+
+ try {
+ if (iterations == 1) {
+ /*
+ * Since many test couldn't be run in single VM twice and test config specifies only 1 iteration don't
+ * multiple iterations by iterations factor and execute tests once (not depending on iterations factor)
+ */
+ executeTests();
+ } else {
+ while (stresser.continueExecution()) {
+ if (!executeTests()) {
+ // if error occured stop execution
+ break;
+ }
+ }
+ }
+ } finally {
+ stresser.finish();
+ }
+ }
+
+ boolean executeTests() {
+ // maximum execution time of single test
+ long maxExecutionTime = 0;
+
+ for (Test test : tests) {
+ long testStartTime = System.currentTimeMillis();
+
+ TestDebuggerType2 debugger = null;
+
+ try {
+ // create debugger object
+ Class debuggerClass = Class.forName(test.debuggerClassName);
+
+ if (!TestDebuggerType2.class.isAssignableFrom(debuggerClass)) {
+ setSuccess(false);
+ log.complain("Invalid debugger class: " + debuggerClass);
+ return false;
+ }
+
+ // init test debugger, pass to the debugger already created
+ // objects: argHandler, log, pipe, debuggee, vm
+ debugger = (TestDebuggerType2) debuggerClass.newInstance();
+ debugger.initDebugger(argHandler, log, pipe, debuggee, vm);
+ debugger.doInit(test.arguments, System.out);
+ } catch (Exception e) {
+ setSuccess(false);
+ log.complain("Unexpected exception during debugger initialization: " + e);
+ e.printStackTrace(log.getOutStream());
+
+ return false;
+ }
+
+ log.display("Execute debugger: " + debugger);
+
+ // send command to the SerialExecutionDebuggee (create debuggee
+ // object)
+ pipe.println(SerialExecutionDebuggee.COMMAND_EXECUTE_DEBUGGEE + ":" + debugger.debuggeeClassName());
+
+ // wait first READY from AbstractDebuggeeTest.doTest() (debuggee
+ // sends this command when it was initialized and ready for
+ // test)
+ if (!isDebuggeeReady())
+ return false;
+
+ try {
+ // here debuggee should be ready for test and current
+ // debugger may perform test
+ debugger.doTest();
+
+ if (debugger.getSuccess()) {
+ log.display("Debugger " + debugger + " finished successfully");
+ } else {
+ setSuccess(false);
+ log.complain("Debugger " + debugger + " finished with errors");
+ }
+ } catch (TestBug testBug) {
+ setSuccess(false);
+ log.complain("Test bug in " + debugger + ": " + testBug);
+ testBug.printStackTrace(log.getOutStream());
+ } catch (Throwable t) {
+ setSuccess(false);
+ log.complain("Unexpected exception during test execution(debugger: " + debugger + "): " + t);
+ t.printStackTrace(log.getOutStream());
+ }
+
+ // send QUIT command to the current debuggee
+ pipe.println(AbstractDebuggeeTest.COMMAND_QUIT);
+
+ if (!isDebuggeeReady())
+ return false;
+
+ // send command to the SerialExecutionDebuggee
+ pipe.println(SerialExecutionDebuggee.COMMAND_CLEAR_DEBUGGEE);
+
+ if (!isDebuggeeReady())
+ return false;
+
+ long testExecutionTime = System.currentTimeMillis() - testStartTime;
+
+ if (testExecutionTime > maxExecutionTime)
+ maxExecutionTime = testExecutionTime;
+
+ if (maxExecutionTime > stresser.getTimeLeft()) {
+ log.display("WARNING: stop test execution because of timeout " +
+ "(max execution time for single test: " + maxExecutionTime + ", time left: " + stresser.getTimeLeft() + ")");
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass1.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+/*
+ * Empty class, used to be sure that there are no instances of this class in target VM
+ */
+public class TestClass1 {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestClass2.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+/*
+ * Empty class, used to be sure that there are no instances of this class in target VM
+ * Used in tests where subclass of test class is needed
+ */
+public class TestClass2 extends TestClass1 {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+
+import java.io.*;
+
+import nsk.share.*;
+
+/**
+ * This class is a template for test debugger.
+ * It bases on some existed tests for testing of
+ * JDI requests and events.
+ *
+ * Requirements for a test debugger which extends
+ * this template are as folllows:
+ * - the subclass must have 'main' and 'run' methods
+ * defined like:
+ * public static void main (String argv[]) {
+ * System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
+ * }
+ *
+ * public static int run (String argv[], PrintStream out) {
+ * debuggeeName = <DEBUGGEE_NAME_AS_STRING>;
+ * return new filter001().runThis(argv, out);
+ * }
+ *
+ * - the subclass must implement 'testRun' method
+ * which must contain checkings of all test's assertions.
+ */
+public abstract class TestDebuggerType1 {
+
+ protected static int waitTime;
+ protected static int testExitCode = Consts.TEST_PASSED;
+
+ protected static Binder binder;
+ protected static Debugee debuggee;
+ protected static VirtualMachine vm;
+ protected static ArgumentHandler argsHandler;
+ protected static Log log;
+ protected static String debuggeeName; /* must be assigned in a subclass */
+ protected static ReferenceType debuggeeClass;
+
+ protected static EventRequestManager eventRManager;
+ protected static EventHandler eventHandler;
+ protected static BreakpointRequest bpRequest /* communication breakpoint */;
+ protected static volatile int bpCount;
+
+ protected static void display(String message) {
+ log.display("debugger> " + message);
+ }
+
+ protected static void complain(String message) {
+ log.complain("debugger> " + message);
+ }
+
+ /**
+ * Should be used in test debugger when assertion failed.
+ */
+ protected static void setFailedStatus(String message) {
+ complain(message);
+ testExitCode = Consts.TEST_FAILED;
+ }
+
+ protected int runThis (String argv[], PrintStream out) {
+
+ argsHandler = new ArgumentHandler(argv);
+ log = new Log(out, argsHandler);
+ binder = new Binder(argsHandler, log);
+ waitTime = argsHandler.getWaitTime() * 60000;
+
+ try {
+ debuggee = binder.bindToDebugee(debuggeeName);
+ debuggee.redirectStdout(log, Debugee.DEBUGEE_STDERR_LOG_PREFIX);
+ vm = debuggee.VM();
+ eventRManager = vm.eventRequestManager();
+
+ eventHandler = new EventHandler(debuggee, log);
+ eventHandler.startListening();
+
+ debuggeeClass = waitForClassPrepared(debuggeeName);
+
+ /* A debuggee class must define 'methodForCommunication'
+ * method and invoke it in points of synchronization
+ * with a debugger.
+ */
+ setCommunicationBreakpoint(debuggeeClass,"methodForCommunication");
+
+ display("TESTING BEGINS");
+
+ // after waitForClassPrepared() main debuggee thread is suspended, resume it before test start
+ display("RESUME DEBUGGEE VM");
+ vm.resume();
+
+ testRun();
+
+ display("TESTING ENDS");
+
+ display("Waiting for debuggee's exit...");
+ eventHandler.waitForVMDisconnect();
+
+ int status = EventHandler.getStatus();
+ if (status != 0) {
+ setFailedStatus("Event handler returned unexpected exit status: " + status);
+ } else {
+ display("Event handler thread exited.");
+ }
+
+ debuggee.endDebugee();
+ status = debuggee.getStatus();
+ if (status != (Consts.TEST_PASSED + Consts.JCK_STATUS_BASE)) {
+ setFailedStatus("Debuggee returned unexpected exit status: " + status);
+ } else {
+ display("Debuggee PASSED.");
+ }
+
+ } catch (VMDisconnectedException e) {
+ setFailedStatus("Unexpected VMDisconnectedException");
+ e.printStackTrace(log.getOutStream());
+ throw new Failure(e.getMessage());
+
+ } catch (Exception e) {
+ setFailedStatus("Unexpected exception : " + e.getMessage());
+ e.printStackTrace(log.getOutStream());
+ display("Forcing debuggee to exit...");
+ vm.exit(Consts.TEST_PASSED + Consts.JCK_STATUS_BASE);
+ }
+
+ return testExitCode;
+ }
+
+ /**
+ * This method which be implemented in all test debuggers
+ * and must contain checking of test assertions.
+ */
+ protected abstract void testRun();
+
+ /**
+ * Waits until debuggee class is prepared.
+ *
+ */
+ private ReferenceType waitForClassPrepared(String className) {
+ ClassPrepareRequest cpRequest = eventRManager.createClassPrepareRequest();
+ cpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD);
+ cpRequest.addClassFilter(className);
+
+ ClassPrepareEvent event = (ClassPrepareEvent)eventHandler.waitForRequestedEvent(
+ new EventRequest[]{cpRequest}, waitTime, true);
+ ReferenceType refType = event.referenceType();
+ if (!refType.name().equals(className))
+ throw new Failure("Unexpected class name for received ClassPrepareEvent: " + refType.name() +
+ "\n\texpected name: " + debuggeeName);
+ display("Received ClassPrepareEvent for debuggee class: " + refType.name());
+ return refType;
+ };
+
+ /**
+ * Sets up breakpoint request which serves for synchronization
+ * between debugger and debuggee.
+ *
+ */
+ private void setCommunicationBreakpoint(ReferenceType refType, String methodName) {
+ Method method = debuggee.methodByName(refType, methodName);
+ Location location = null;
+ try {
+ location = method.allLineLocations().get(0);
+ } catch (AbsentInformationException e) {
+ throw new Failure(e);
+ }
+ bpRequest = debuggee.makeBreakpoint(location);
+
+ bpRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+ bpRequest.putProperty("number", "zero");
+ bpRequest.enable();
+
+ eventHandler.addListener(
+ new EventHandler.EventListener() {
+ public boolean eventReceived(Event event) {
+ if (event instanceof BreakpointEvent && bpRequest.equals(event.request())) {
+ synchronized(eventHandler) {
+ display("Received communication breakpoint event.");
+ bpCount++;
+ eventHandler.notifyAll();
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+ );
+ }
+
+ /**
+ * Waits for synchronization breakpoint event and checks
+ * up if there are more test case to check.
+ *
+ * Note: debuggee VM shouldn't be suspended when this method
+ * is called
+ *
+ * @return true if there are more test case to check,
+ * false otherwise or debuggee is disconnected.
+ */
+ protected boolean shouldRunAfterBreakpoint() {
+ display("shouldRunAfterBreakpoint: entered");
+ boolean shouldRun = true;
+
+ long timeToFinish = System.currentTimeMillis() + waitTime;
+ long timeLeft = waitTime;
+ synchronized(eventHandler) {
+ while (!EventHandler.isDisconnected() && bpCount <= 0 && timeLeft > 0) {
+ display("shouldRunAfterBreakpoint: waiting for breakpoint event during 1 sec.");
+ try {
+ eventHandler.wait(1000);
+ } catch (InterruptedException e) {
+ throw new Failure(e);
+ }
+ timeLeft = timeToFinish - System.currentTimeMillis();
+ }
+ }
+ if (timeLeft <= 0 && bpCount <= 0) {
+ setFailedStatus("shouldRunAfterBreakpoint: had not received breakpoint event during waitTime.");
+ shouldRun = false;
+
+ } else if (bpCount > 0) {
+ display("shouldRunAfterBreakpoint: received breakpoint event.");
+ bpCount--;
+ }
+
+ if (!EventHandler.isDisconnected()) {
+ try {
+ int instruction = ((IntegerValue)
+ (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value();
+
+ if (instruction == 0) {
+ display("shouldRunAfterBreakpoint: received instruction from debuggee to finish.");
+ shouldRun = false;
+ }
+ } catch (VMDisconnectedException e) {
+ shouldRun = false;
+ }
+ } else {
+ shouldRun = false;
+ }
+
+ if (shouldRun) {
+ display("shouldRunAfterBreakpoint: exited with true.");
+ } else {
+ display("shouldRunAfterBreakpoint: exited with false.");
+ }
+ return shouldRun;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType2.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.io.*;
+import java.util.*;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import nsk.share.*;
+import nsk.share.jpda.*;
+import nsk.share.test.StressOptions;
+import nsk.share.test.Stresser;
+
+/*
+ * Class can be used as base debugger class in jdi tests.
+ * Class contains common method for initializing log, debugee, pipe, vm, and several common auxiliary methods.
+ * Sublcass should implement doTest() and, if needed, doInit(parse command line parameters) and canRunTest(check if VM support tested functionality)
+ */
+public class TestDebuggerType2 {
+ public class EventListenerThread extends Thread {
+ private EventRequest eventRequest;
+
+ private Event event;
+
+ private Wicket wicket = new Wicket();
+
+ public EventListenerThread(EventRequest eventRequest) {
+ this.eventRequest = eventRequest;
+ }
+
+ public void run() {
+ wicket.unlock();
+
+ try {
+ event = debuggee.waitingEvent(eventRequest, argHandler.getWaitTime() * 60000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ public void waitStartListen() {
+ wicket.waitFor();
+ }
+
+ public Event getEvent() {
+ try {
+ // wait when EventListenerThread complete execution
+ this.join();
+ } catch (InterruptedException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ }
+
+ return event;
+ }
+ }
+
+ protected ArgumentHandler argHandler;
+
+ protected Log log;
+
+ protected IOPipe pipe;
+
+ protected Debugee debuggee;
+
+ protected VirtualMachine vm;
+
+ /*
+ * this method is called from nsk.share.jdi.SerialExecutionDebugger to set for debugger
+ * already created instances of ArgumentHandler, Log, IOPipe, Debugee, VirtualMachine
+ */
+ public void initDebugger(ArgumentHandler argHandler, Log log, IOPipe pipe, Debugee debuggee, VirtualMachine vm) {
+ this.argHandler = argHandler;
+ this.log = log;
+ this.pipe = pipe;
+ this.debuggee = debuggee;
+ this.vm = vm;
+ }
+
+ private boolean success = true;
+
+ protected void setSuccess(boolean value) {
+ success = value;
+ }
+
+ protected boolean getSuccess() {
+ return success;
+ }
+
+ // class name used during initialization
+ protected String debuggeeClassName() {
+ return null;
+ }
+
+ // select only class name if debuggeeClassName() returns className + debuggee parameters
+ protected String debuggeeClassNameWithoutArgs() {
+ String className = debuggeeClassName();
+
+ int index = className.indexOf(' ');
+ if (index > 0) {
+ return className.substring(0, index);
+ } else
+ return className;
+ }
+
+ protected String classpath;
+
+ protected String testWorkDir;
+
+ // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments
+ // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options)
+ // support -testClassPath parameter: path to find classes for custom classloader in debuggee VM
+ // (note that in this method stressOptions and stresser are created, so if subclasses override this method
+ // overrided version should first call super.doInit())
+ protected String[] doInit(String args[], PrintStream out) {
+ stressOptions = new StressOptions(args);
+ stresser = new Stresser(stressOptions);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-testClassPath") && (i < args.length - 1)) {
+ classpath = args[i + 1];
+ i++;
+ } else if (args[i].equals("-testWorkDir") && (i < args.length - 1)) {
+ testWorkDir = args[i + 1];
+
+ if (testWorkDir.endsWith(File.separator)) {
+ testWorkDir = testWorkDir.substring(0, testWorkDir.length() - 1);
+ }
+
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ protected void doTest() {
+ setSuccess(false);
+ throw new TestBug("TEST BUG: method doTest not implemented");
+ }
+
+ protected Stresser stresser;
+ protected StressOptions stressOptions;
+
+ // initialize log, debuggee, pipe
+ public void init(String args[], PrintStream out) {
+ argHandler = new ArgumentHandler(doInit(args, out));
+ log = new Log(out, argHandler);
+ Binder binder = new Binder(argHandler, log);
+ debuggee = binder.bindToDebugee(debuggeeClassName());
+ pipe = debuggee.createIOPipe();
+ debuggee.redirectStderr(log, "Debugger.err> ");
+ vm = debuggee.VM();
+ debuggee.resume();
+
+ String command = pipe.readln();
+
+ if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) {
+ setSuccess(false);
+ log.complain("TEST BUG: unknown debuggee's command: " + command);
+ }
+ }
+
+ // check that vm support tested functions
+ protected boolean canRunTest() {
+ return true;
+ }
+
+ // send quit command to debuggee
+ protected void quitDebuggee() {
+ pipe.println(AbstractDebuggeeTest.COMMAND_QUIT);
+ debuggee.waitFor();
+
+ int debStat = debuggee.getStatus();
+
+ if (debStat != (Consts.JCK_STATUS_BASE + Consts.TEST_PASSED)) {
+ setSuccess(false);
+ log.complain("TEST FAILED: debuggee's process finished with status: " + debStat);
+ } else
+ log.display("Debuggee's process finished with status: " + debStat);
+
+ }
+
+ // init test, execute test, quit debuggee
+ protected int runIt(String args[], PrintStream out) {
+ init(args, out);
+
+ try {
+ if (canRunTest())
+ doTest();
+ } catch (TestBug testBug) {
+ setSuccess(false);
+ log.complain("Test bug: " + testBug);
+ testBug.printStackTrace(log.getOutStream());
+ } catch (Throwable t) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + t);
+ t.printStackTrace(log.getOutStream());
+ }
+
+ quitDebuggee();
+
+ if (getSuccess()) {
+ log.display("TEST PASSED");
+ return Consts.TEST_PASSED;
+ } else {
+ log.display("TEST FAILED");
+ return Consts.TEST_FAILED;
+ }
+ }
+
+ // check the debuggee completed pervious command and is ready for new one
+ protected boolean isDebuggeeReady() {
+ String command = pipe.readln();
+
+ if (!command.equals(AbstractDebuggeeTest.COMMAND_READY)) {
+ setSuccess(false);
+ log.complain("TEST BUG: unknown debuggee's command: " + command);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // find in debuggee VM instance of object with given class and check
+ // that there is only one instance of this class
+ protected ObjectReference findSingleObjectReference(String className) {
+ ReferenceType referenceType = debuggee.classByName(className);
+
+ if (referenceType == null)
+ throw new TestBug("There is no class '" + className + "' in debuggee");
+
+ List<ObjectReference> instances = referenceType.instances(0);
+
+ if (instances.size() == 0)
+ throw new TestBug("There are no instances of class '" + className + "' in debuggee");
+
+ if (instances.size() > 1)
+ throw new TestBug("There are more than one(" + instances.size() + ") instance of '" + className + " in debuggee");
+
+ return instances.get(0);
+ }
+
+ protected BreakpointEvent waitForBreakpoint(BreakpointRequest breakpointRequest) {
+ BreakpointEvent breakpointEvent;
+
+ try {
+ breakpointEvent = (BreakpointEvent) debuggee.waitingEvent(breakpointRequest, argHandler.getWaitTime() * 60000);
+ } catch (InterruptedException e) {
+ setSuccess(false);
+ e.printStackTrace(log.getOutStream());
+ log.complain("unexpected InterruptedException: " + e);
+
+ breakpointEvent = null;
+ }
+
+ if (breakpointEvent == null) {
+ setSuccess(false);
+ log.complain("Didn't get expected breakpoint event");
+ }
+
+ return breakpointEvent;
+ }
+
+
+ private boolean currentSuccess = false;
+ protected void forceGC() {
+ pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_GC);
+ if (!isDebuggeeReady())
+ return;
+ currentSuccess = getSuccess();
+ }
+
+ // Get GC statistics
+ protected void resetStatusIfGC() {
+ pipe.println(AbstractDebuggeeTest.COMMAND_GC_COUNT);
+ String command = pipe.readln();
+ if (command.startsWith(AbstractDebuggeeTest.COMMAND_GC_COUNT)) {
+ if (!isDebuggeeReady()) {
+ return;
+ }
+ if (Integer.valueOf(command.substring(AbstractDebuggeeTest.COMMAND_GC_COUNT.length() + 1)) > 0) {
+ log.display("WARNING: The GC worked during tests. Results are skipped.");
+ setSuccess(currentSuccess);
+ }
+ return;
+ }
+ setSuccess(false);
+ }
+
+
+ protected BreakpointRequest defaultBreakpointRequest;
+
+ protected void initDefaultBreakpoint() {
+ defaultBreakpointRequest = debuggee.makeBreakpoint(debuggee.classByName(debuggeeClassNameWithoutArgs()),
+ AbstractDebuggeeTest.DEFAULT_BREAKPOINT_METHOD_NAME, AbstractDebuggeeTest.DEFAULT_BREAKPOINT_LINE);
+
+ defaultBreakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+ defaultBreakpointRequest.enable();
+ }
+
+ protected void removeDefaultBreakpoint() {
+ defaultBreakpointRequest.disable();
+ debuggee.getEventRequestManager().deleteEventRequest(defaultBreakpointRequest);
+ defaultBreakpointRequest = null;
+ }
+
+ protected Value createVoidValue() {
+ return vm.mirrorOfVoid();
+ }
+
+ // force debuggee call 'TestDebuggeeType2.breakpointMethod()'
+ protected BreakpointEvent forceBreakpoint() {
+ pipe.println(AbstractDebuggeeTest.COMMAND_FORCE_BREAKPOINT);
+
+ BreakpointEvent event = waitForBreakpoint(defaultBreakpointRequest);
+
+ return event;
+ }
+
+ protected void unexpectedException(Throwable t) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + t);
+ t.printStackTrace(log.getOutStream());
+ }
+
+ protected void display(String msg) {
+ log.display(msg);
+ }
+
+ protected void complain(String msg) {
+ log.complain("debugger FAILURE> " + msg + "\n");
+ }
+
+ protected boolean isJFR_active() {
+ return debuggee.isJFR_active();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestInterfaceImplementer1.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+interface Interface1 {
+
+}
+
+interface Interface2 {
+
+}
+
+interface Interface3 {
+
+}
+
+interface Interface4 {
+
+}
+
+interface Interface5 {
+
+}
+
+/*
+ * Empty class, used to be sure that there are no instances of this class in target VM
+ * Used in tests where interface implementer is needed
+ */
+public class TestInterfaceImplementer1 implements Interface1, Interface2, Interface3, Interface4, Interface5 {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ThreadState.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jdi;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.TimeUnit;
+
+import nsk.share.Failure;
+
+/**
+ * Functions to set and wait for states in threads.
+ * Used to sync main thread and debuggee thread.
+ */
+public class ThreadState {
+ private final Lock lock = new ReentrantLock();
+ private final Condition cond = lock.newCondition();
+ private volatile String currentState;
+ private long timeoutMs;
+
+ public ThreadState(String startState, long timeoutMs) {
+ currentState = startState;
+ this.timeoutMs = timeoutMs;
+ }
+
+ /**
+ * Set new state.
+ */
+ public void setState(String newState) {
+ lock.lock();
+ try {
+ log(MSG_SET_STATE, newState);
+ currentState = newState;
+ cond.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Wait for the specified state.
+ * Throws Failure if timeout.
+ */
+ public void waitForState(String waitState) {
+ lock.lock();
+ try {
+ log(MSG_WAIT_STATE, waitState);
+ while (!currentState.equals(waitState)) {
+ if (!cond.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+ throw new Failure(format(MSG_TIMEOUT, waitState));
+ }
+ }
+ log(MSG_GOT_STATE, waitState);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ throw new Failure(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Simple helper that sets a new state and then wait for another state.
+ */
+ public void setAndWait(String newState, String waitState) {
+ setState(newState);
+ waitForState(waitState);
+ }
+
+ private static final String MSG_TIMEOUT = "ThreadState(thread='%s', state='%s') timeout waiting for %s";
+ private static final String MSG_SET_STATE = "ThreadState(thread='%s', state='%s') set state to %s";
+ private static final String MSG_WAIT_STATE = "ThreadState(thread='%s', state='%s') waiting for state %s";
+ private static final String MSG_GOT_STATE = "ThreadState(thread='%s', state='%s') got state %s";
+
+ private String format(String pattern, String state) {
+ final String threadName = Thread.currentThread().getName();
+ return String.format(pattern, threadName, currentState, state);
+ }
+
+ private void log(String pattern, String state) {
+ System.out.println(format(pattern, state));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/ValueConversionDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi;
+
+import java.lang.reflect.*;
+import nsk.share.*;
+import nsk.share.jpda.ConversionUtils;
+import com.sun.jdi.*;
+
+/*
+ * Class contains several common methods used by tests checking that values are
+ * correctly converted as a result of JDI interface work (e.g. when method
+ * 'ObjectReference.setValue(Field, Value)' is called)
+ */
+public class ValueConversionDebugger extends TestDebuggerType2 {
+
+ protected static enum ValueType {
+ BYTE,
+ CHAR,
+ SHORT,
+ INT,
+ LONG,
+ FLOAT,
+ DOUBLE
+ }
+
+ /*
+ * short aliases for ValueType members
+ */
+ protected static ValueType BYTE = ValueType.BYTE;
+ protected static ValueType CHAR = ValueType.CHAR;
+ protected static ValueType SHORT = ValueType.SHORT;
+ protected static ValueType INT = ValueType.INT;
+ protected static ValueType LONG = ValueType.LONG;
+ protected static ValueType FLOAT = ValueType.FLOAT;
+ protected static ValueType DOUBLE = ValueType.DOUBLE;
+
+ /*
+ * Is information lost when given PrimitiveValue converted to the
+ * primitive type representing by the destType
+ */
+ public static boolean informationLoss(PrimitiveValue value, Class destType) {
+ /*
+ * Use reflection here to avoid large nested switches
+ * (construct method name, method is located in the nsk.share.jpda.ConversionUtils)
+ */
+ String methodNameToCall = "informationLoss";
+
+ Object param = null;
+
+ if (value instanceof ByteValue) {
+ methodNameToCall += "ByteTo";
+ param = new Byte(value.byteValue());
+ } else if (value instanceof ShortValue) {
+ methodNameToCall += "ShortTo";
+ param = new Short(value.shortValue());
+ } else if (value instanceof CharValue) {
+ methodNameToCall += "CharTo";
+ param = new Character(value.charValue());
+ } else if (value instanceof IntegerValue) {
+ methodNameToCall += "IntTo";
+ param = new Integer(value.intValue());
+ } else if (value instanceof LongValue) {
+ methodNameToCall += "LongTo";
+ param = new Long(value.longValue());
+ } else if (value instanceof FloatValue) {
+ methodNameToCall += "FloatTo";
+ param = new Float(value.floatValue());
+ } else if (value instanceof DoubleValue) {
+ methodNameToCall += "DoubleTo";
+ param = new Double(value.doubleValue());
+ } else
+ throw new IllegalArgumentException("Illegal PrimitiveValue: " + value);
+
+ if (!destType.isPrimitive())
+ throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type");
+
+ if (destType == Byte.TYPE) {
+ methodNameToCall += "Byte";
+ } else if (destType == Short.TYPE) {
+ methodNameToCall += "Short";
+ } else if (destType == Character.TYPE) {
+ methodNameToCall += "Char";
+ } else if (destType == Integer.TYPE) {
+ methodNameToCall += "Int";
+ } else if (destType == Long.TYPE) {
+ methodNameToCall += "Long";
+ } else if (destType == Float.TYPE) {
+ methodNameToCall += "Float";
+ } else if (destType == Double.TYPE) {
+ methodNameToCall += "Double";
+ } else
+ throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type");
+
+ java.lang.reflect.Method method;
+ try {
+ method = ConversionUtils.class.getMethod(methodNameToCall, param.getClass());
+ } catch (NoSuchMethodException e) {
+ throw new Failure("Unexpected exception: " + e, e);
+ }
+
+ try {
+ return (Boolean)method.invoke(null, new Object[]{param});
+ } catch (IllegalAccessException e) {
+ throw new Failure("Unexpected exception: " + e, e);
+ } catch (InvocationTargetException e) {
+ throw new Failure("Unexpected exception: " + e, e);
+ }
+ }
+
+ /*
+ * Is given PrimitiveValue can be converted to the primitive type represented by the
+ * destType without information loss
+ */
+ public static boolean isValidConversion(PrimitiveValue value, Class destType) {
+ return !informationLoss(value, destType);
+ }
+
+ /*
+ * Method is used in subclasses for creation of tested values
+ * (reflection is used to simplify coding)
+ */
+ protected PrimitiveValue createValue(Object arr, int arrayIndex) {
+ PrimitiveValue value;
+
+ if (arr instanceof byte[]) {
+ value = debuggee.VM().mirrorOf(Array.getByte(arr,arrayIndex));
+ } else if (arr instanceof char[]) {
+ value = debuggee.VM().mirrorOf(Array.getChar(arr,arrayIndex));
+ } else if (arr instanceof double[]) {
+ value = debuggee.VM().mirrorOf(Array.getDouble(arr,arrayIndex));
+ } else if (arr instanceof float[]) {
+ value = debuggee.VM().mirrorOf(Array.getFloat(arr,arrayIndex));
+ } else if (arr instanceof int[]) {
+ value = debuggee.VM().mirrorOf(Array.getInt(arr,arrayIndex));
+ } else if (arr instanceof long[]) {
+ value = debuggee.VM().mirrorOf(Array.getLong(arr,arrayIndex));
+ } else if (arr instanceof short[]) {
+ value = debuggee.VM().mirrorOf(Array.getShort(arr,arrayIndex));
+ } else {
+ setSuccess(false);
+ throw new TestBug("Unexpected object was passed in the 'createValue': " + arr);
+ }
+
+ return value;
+ }
+
+ /*
+ * used by subclasses for debug output
+ * (modified in the method 'isValidConversion')
+ */
+ protected String lastConversion;
+
+ /*
+ * Is given PrimitiveValue can be converted to the primitive type represented by the given type
+ * without information loss
+ */
+ protected boolean isValidConversion(ValueType type, PrimitiveValue value) {
+ com.sun.jdi.Type fromType = value.type();
+
+ boolean ret = false;
+ lastConversion = " conversion from "
+ + value + "(" + fromType + ")" + " to ";
+ switch (type) {
+ case BYTE:
+ byte b = value.byteValue();
+ ret = isValidConversion(value, Byte.TYPE);
+ lastConversion += b + "(byte)";
+ break;
+ case CHAR:
+ char c = value.charValue();
+ ret = isValidConversion(value, Character.TYPE);
+ lastConversion += Integer.toHexString(c) + "(char)";
+ break;
+ case DOUBLE:
+ double d = value.doubleValue();
+ ret = isValidConversion(value, Double.TYPE);
+ lastConversion += d + "(double)";
+ break;
+ case FLOAT:
+ float f = value.floatValue();
+ ret = isValidConversion(value, Float.TYPE);
+ lastConversion += f + "(float)";
+ break;
+ case INT:
+ int i = value.intValue();
+ ret = isValidConversion(value, Integer.TYPE);
+ lastConversion += i + "(int)";
+ break;
+ case LONG:
+ long j = value.longValue();
+ ret = isValidConversion(value, Long.TYPE);
+ lastConversion += j + "(long)";
+ break;
+ case SHORT:
+ short s = value.shortValue();
+ ret = isValidConversion(value, Short.TYPE);
+ lastConversion += s + "(short)";
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid type: " + type);
+ }
+ return ret;
+ }
+
+ /*
+ * Used in subclasses to check that given PrimitiveValue was correctly converted as a result
+ * of JDI interface work (retValue - conversion result)
+ * (
+ * example:
+ * test assigns DoubleValue = 1.5 (value) to the byte Field (retValue - ByteValue = 1),
+ * in this case we should check that value.byteValue() == retValue.byteValue()
+ * )
+ */
+ protected void checkValueConversion(PrimitiveValue value, PrimitiveValue retValue) {
+ boolean res;
+
+ if (retValue instanceof ByteValue) {
+ res = value.byteValue() != retValue.byteValue();
+ } else if (retValue instanceof ShortValue) {
+ res = value.shortValue() != retValue.shortValue();
+ } else if (retValue instanceof CharValue) {
+ res = value.charValue() != retValue.charValue();
+ } else if (retValue instanceof IntegerValue) {
+ res = value.intValue() != retValue.intValue();
+ } else if (retValue instanceof LongValue) {
+ res = value.longValue() != retValue.longValue();
+ } else if (retValue instanceof FloatValue) {
+ res = value.floatValue() != retValue.floatValue();
+ } else if (retValue instanceof DoubleValue) {
+ res = value.doubleValue() != retValue.doubleValue();
+ } else {
+ throw new TestBug("Invalid value type in the 'checkValueConversion': " + retValue.type().name());
+ }
+
+ if (res) {
+ setSuccess(false);
+ complain("Conversion error");
+ complain("From type: " + value.type().name() + ", to type: " + retValue.type().name());
+ complain(retValue + " != " + value);
+ display("");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/InstallSDE.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi.sde;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import nsk.share.Consts;
+
+/*
+ * Inserts in class file 'SourceDebugExtension' attribute based on input .SMAP file.
+ */
+public class InstallSDE {
+ static final String nameSDE = "SourceDebugExtension";
+
+ private byte[] orig;
+
+ private byte[] sdeAttr;
+
+ private byte[] gen;
+
+ private int origPos = 0;
+
+ private int genPos = 0;
+
+ private int sdeIndex;
+
+ public static void install(File inClassFile, File smapFile, File outClassFile, boolean verbose) throws IOException {
+ new InstallSDE(inClassFile, smapFile, outClassFile, verbose);
+ }
+
+ public static void install(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException {
+ new InstallSDE(aOrig, aSdeAttr, outClassFile, verbose);
+ }
+
+ public static void install(File inOutClassFile, File attrFile, boolean verbose) throws IOException {
+ File tmpFile = new File(inOutClassFile.getPath() + "tmp");
+
+ new InstallSDE(inOutClassFile, attrFile, tmpFile, verbose);
+
+ if (!inOutClassFile.delete()) {
+ throw new IOException("inOutClassFile.delete() failed");
+ }
+ if (!tmpFile.renameTo(inOutClassFile)) {
+ throw new IOException("tmpFile.renameTo(inOutClassFile) failed");
+ }
+ }
+
+ private static void abort(String msg) {
+ System.err.println(msg);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+
+ private InstallSDE(File inClassFile, File attrFile, File outClassFile, boolean verbose) throws IOException {
+ if (!inClassFile.exists()) {
+ abort("no such file: " + inClassFile);
+ }
+ if (!attrFile.exists()) {
+ abort("no such file: " + attrFile);
+ }
+
+ // get the bytes
+ orig = readWhole(inClassFile);
+ sdeAttr = readWhole(attrFile);
+ gen = new byte[orig.length + sdeAttr.length + 100];
+
+ // do it
+ addSDE(verbose);
+
+ // write result
+ FileOutputStream outStream = new FileOutputStream(outClassFile);
+ outStream.write(gen, 0, genPos);
+ outStream.close();
+ }
+
+ private InstallSDE(byte[] aOrig, byte[] aSdeAttr, File outClassFile, boolean verbose) throws IOException {
+ orig = aOrig;
+ sdeAttr = aSdeAttr;
+ gen = new byte[orig.length + sdeAttr.length + 100];
+
+ // do it
+ addSDE(verbose);
+
+ // write result
+ FileOutputStream outStream = new FileOutputStream(outClassFile);
+ outStream.write(gen, 0, genPos);
+ outStream.close();
+ }
+
+ private byte[] readWhole(File input) throws IOException {
+ FileInputStream inStream = new FileInputStream(input);
+ try {
+ return readWhole(inStream, (int) input.length());
+ } finally {
+ inStream.close();
+ }
+ }
+
+ private byte[] readWhole(InputStream inStream, int len) throws IOException {
+ byte[] bytes = new byte[len];
+
+ if (inStream.read(bytes, 0, len) != len) {
+ abort("expected size: " + len);
+ }
+
+ return bytes;
+ }
+
+ private void addSDE(boolean verbose) throws UnsupportedEncodingException {
+ copy(4 + 2 + 2); // magic min/maj version
+ int constantPoolCountPos = genPos;
+ int constantPoolCount = readU2();
+ writeU2(constantPoolCount);
+ // copy old constant pool return index of SDE symbol, if found
+ sdeIndex = copyConstantPool(constantPoolCount, verbose);
+ if (sdeIndex < 0) {
+ // if "SourceDebugExtension" symbol not there add it
+ writeUtf8ForSDE();
+
+ // increment the countantPoolCount
+ sdeIndex = constantPoolCount;
+ ++constantPoolCount;
+ randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
+
+ if (verbose) {
+ System.out.println("SourceDebugExtension not found, installed at: " + sdeIndex);
+ }
+ } else {
+ if (verbose) {
+ System.out.println("SourceDebugExtension found at: " + sdeIndex);
+ }
+ }
+ copy(2 + 2 + 2); // access, this, super
+ int interfaceCount = readU2();
+ writeU2(interfaceCount);
+ if (verbose) {
+ System.out.println("interfaceCount: " + interfaceCount);
+ }
+ copy(interfaceCount * 2);
+ copyMembers(verbose); // fields
+ copyMembers(verbose); // methods
+ int attrCountPos = genPos;
+ int attrCount = readU2();
+ writeU2(attrCount);
+ if (verbose) {
+ System.out.println("class attrCount: " + attrCount);
+ }
+ // copy the class attributes, return true if SDE attr found (not copied)
+ if (!copyAttrs(attrCount, verbose)) {
+ // we will be adding SDE and it isn't already counted
+ ++attrCount;
+ randomAccessWriteU2(attrCountPos, attrCount);
+ if (verbose) {
+ System.out.println("class attrCount incremented");
+ }
+ }
+ writeAttrForSDE(sdeIndex);
+ }
+
+ private void copyMembers(boolean verbose) {
+ int count = readU2();
+ writeU2(count);
+ if (verbose) {
+ System.out.println("members count: " + count);
+ }
+ for (int i = 0; i < count; ++i) {
+ copy(6); // access, name, descriptor
+ int attrCount = readU2();
+ writeU2(attrCount);
+ if (verbose) {
+ System.out.println("member attr count: " + attrCount);
+ }
+ copyAttrs(attrCount, verbose);
+ }
+ }
+
+ private boolean copyAttrs(int attrCount, boolean verbose) {
+ boolean sdeFound = false;
+ for (int i = 0; i < attrCount; ++i) {
+ int nameIndex = readU2();
+ // don't write old SDE
+ if (nameIndex == sdeIndex) {
+ sdeFound = true;
+ if (verbose) {
+ System.out.println("SDE attr found");
+ }
+ } else {
+ writeU2(nameIndex); // name
+ int len = readU4();
+ writeU4(len);
+ copy(len);
+ if (verbose) {
+ System.out.println("attr len: " + len);
+ }
+ }
+ }
+ return sdeFound;
+ }
+
+ private void writeAttrForSDE(int index) {
+ writeU2(index);
+ writeU4(sdeAttr.length);
+ for (int i = 0; i < sdeAttr.length; ++i) {
+ writeU1(sdeAttr[i]);
+ }
+ }
+
+ private void randomAccessWriteU2(int pos, int val) {
+ int savePos = genPos;
+ genPos = pos;
+ writeU2(val);
+ genPos = savePos;
+ }
+
+ private int readU1() {
+ return ((int) orig[origPos++]) & 0xFF;
+ }
+
+ private int readU2() {
+ int res = readU1();
+ return (res << 8) + readU1();
+ }
+
+ private int readU4() {
+ int res = readU2();
+ return (res << 16) + readU2();
+ }
+
+ private void writeU1(int val) {
+ gen[genPos++] = (byte) val;
+ }
+
+ private void writeU2(int val) {
+ writeU1(val >> 8);
+ writeU1(val & 0xFF);
+ }
+
+ private void writeU4(int val) {
+ writeU2(val >> 16);
+ writeU2(val & 0xFFFF);
+ }
+
+ private void copy(int count) {
+ for (int i = 0; i < count; ++i) {
+ gen[genPos++] = orig[origPos++];
+ }
+ }
+
+ private byte[] readBytes(int count) {
+ byte[] bytes = new byte[count];
+ for (int i = 0; i < count; ++i) {
+ bytes[i] = orig[origPos++];
+ }
+ return bytes;
+ }
+
+ private void writeBytes(byte[] bytes) {
+ for (int i = 0; i < bytes.length; ++i) {
+ gen[genPos++] = bytes[i];
+ }
+ }
+
+ private int copyConstantPool(int constantPoolCount, boolean verbose) throws UnsupportedEncodingException {
+ int sdeIndex = -1;
+ // copy const pool index zero not in class file
+ if ( verbose )
+ System.out.println("cp count=" + constantPoolCount);
+ for (int i = 1; i < constantPoolCount; ++i) {
+ int tag = readU1();
+ writeU1(tag);
+ if ( verbose )
+ System.out.println(i + ": tag=" + tag);
+ switch (tag) {
+ case 7: // Class
+ case 8: // String
+ case 16: // MethodType
+ copy(2);
+ break;
+ case 15: // MethodHandle
+ copy(3);
+ break;
+ case 9: // Field
+ case 10: // Method
+ case 11: // InterfaceMethod
+ case 3: // Integer
+ case 4: // Float
+ case 12: // NameAndType
+ case 17: // InvokeDynamic_17 (will go away)
+ case 18: // InokeDynamic
+ copy(4);
+ break;
+ case 5: // Long
+ case 6: // Double
+ copy(8);
+ ++i;
+ break;
+ case 1: // Utf8
+ int len = readU2();
+ writeU2(len);
+ byte[] utf8 = readBytes(len);
+ String str = new String(utf8, "UTF-8");
+ if (verbose) {
+ System.out.println(i + " read class attr -- '" + str + "'");
+ }
+ if (str.equals(nameSDE)) {
+ sdeIndex = i;
+ }
+ writeBytes(utf8);
+ break;
+ default:
+ abort("unexpected tag: " + tag);
+ break;
+ }
+ }
+ return sdeIndex;
+ }
+
+ private void writeUtf8ForSDE() {
+ int len = nameSDE.length();
+ writeU1(1); // Utf8 tag
+ writeU2(len);
+ for (int i = 0; i < len; ++i) {
+ writeU1(nameSDE.charAt(i));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebuggee.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi.sde;
+
+import java.lang.reflect.Method;
+import nsk.share.TestBug;
+import nsk.share.jdi.*;
+
+public class SDEDebuggee extends AbstractJDIDebuggee {
+ public static String mainThreadName = "SDEDebuggee_mainThread";
+
+ // command:class_name
+ public static String COMMAND_EXECUTE_TEST_METHODS = "executeTestMethods";
+
+ public static void main(String args[]) {
+ new SDEDebuggee().doTest(args);
+ }
+
+ protected String[] doInit(String[] args) {
+ args = super.doInit(args);
+
+ if (classpath == null)
+ throw new TestBug("Debuggee requires '-testClassPath' parameter");
+
+ Thread.currentThread().setName(mainThreadName);
+
+ return args;
+ }
+
+ public boolean parseCommand(String command) {
+ if (super.parseCommand(command))
+ return true;
+
+ if (command.startsWith(COMMAND_EXECUTE_TEST_METHODS)) {
+ // extract class name
+ String split[] = command.split(":");
+
+ if ((split.length != 2) || (split[1].length() == 0))
+ throw new TestBug("");
+
+ executeTestMethods(split[1]);
+ breakpointMethod();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // create instance of given class and execute all methods which names start
+ // with 'sde_testMethod'
+ private void executeTestMethods(String className) {
+ TestClassLoader classLoader = new TestClassLoader();
+ classLoader.setClassPath(classpath);
+
+ try {
+ Class<?> klass = classLoader.loadClass(className);
+ Object testObject = klass.newInstance();
+
+ for (Method method : klass.getDeclaredMethods()) {
+ if (method.getName().startsWith("sde_testMethod"))
+ method.invoke(testObject, new Object[] {});
+ }
+ } catch (Exception e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+
+ throw new TestBug("Unexpected exception: " + e);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SDEDebugger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi.sde;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.util.*;
+import com.sun.jdi.*;
+import com.sun.jdi.event.BreakpointEvent;
+import com.sun.jdi.event.Event;
+import com.sun.jdi.event.StepEvent;
+import nsk.share.ClassFileFinder;
+import nsk.share.TestBug;
+import nsk.share.jdi.EventHandler;
+import nsk.share.jdi.TestDebuggerType2;
+
+/*
+ * Class is used as base debugger for SDE tests.
+ *
+ * This class contains several methods called 'prepareDefaultPatchedClassFile_TypeXXX' which create
+ * class file with added SourceDebugExtension attribute and return debug information about created file.
+ * (this methods was moved in SDEDebugger class if similar generated class files were used in 2 or more tests)
+ *
+ *
+ */
+public class SDEDebugger extends TestDebuggerType2 {
+ protected static final int INIT_LINE = 32; // n.s.j.sde.TestClass1::<init>
+ protected static final int METHOD1_LINE = 43; // n.s.j.sde.TestClass1::sde_testMethod1
+ protected static final int METHOD2_LINE = 54; // n.s.j.sde.TestClass1::sde_testMethod2
+ public static String javaStratumName = "Java";
+
+ // Set debug data for "Java" stratum for TestClass1
+ public static List<DebugLocation> javaStratumLocations_TestClass1 = new ArrayList<DebugLocation>();
+
+ public static String javaSourceName_TestClass1 = "TestClass1.java";
+
+ public static String javaSourcePath_TestClass1 = "nsk" + File.separator + "share" + File.separator + "jdi"
+ + File.separator + "sde" + File.separator + "TestClass1.java";
+
+ static {
+ for (int i = 0; i < 8; i++) {
+ javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1,
+ "<init>", INIT_LINE + i, INIT_LINE + i));
+ javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1,
+ "sde_testMethod1", METHOD1_LINE + i, METHOD1_LINE + i));
+ javaStratumLocations_TestClass1.add(new DebugLocation(javaSourceName_TestClass1, javaSourcePath_TestClass1,
+ "sde_testMethod2", METHOD2_LINE + i, METHOD2_LINE + i));
+ }
+ }
+
+ // insert debug information about "Java" stratum in the given Map<String,
+ // LocationsData>
+ static protected void addJavaLocations(Map<String, LocationsData> testStratumData, boolean setJavaStratumDefault) {
+ LocationsData locationsData = new LocationsData(javaStratumName);
+
+ if (setJavaStratumDefault)
+ locationsData.isDefault = true;
+
+ locationsData.paths.add(javaSourcePath_TestClass1);
+ locationsData.allLocations.addAll(javaStratumLocations_TestClass1);
+ locationsData.sourceLocations.put(javaSourceName_TestClass1, javaStratumLocations_TestClass1);
+
+ testStratumData.put(javaStratumName, locationsData);
+
+ }
+
+ // common base names for test stratum, stratum source name and stratum
+ // source path
+ public static final String testStratumName = "TestStratum";
+
+ public static final String testStratumSourceName = "testSource";
+
+ public static final String testStratumSourcePath = "testSourcePath";
+
+ // Event listener thread which saves all received StepEvents
+ public class StepEventListener extends EventHandler.EventListener {
+ // is BreakpointEvent was received (debuggee should stop at breakpoint
+ // after StepEvents generation)
+ private volatile boolean breakpointEventReceived;
+
+ private List<Location> stepLocations = new ArrayList<Location>();
+
+ public List<Location> stepLocations() {
+ return stepLocations;
+ }
+
+ public void clearLocations() {
+ stepLocations.clear();
+ }
+
+ public boolean eventReceived(Event event) {
+ if (event instanceof StepEvent) {
+ StepEvent stepEvent = (StepEvent) event;
+
+ stepLocations.add(stepEvent.location());
+
+ vm.resume();
+
+ return true;
+ }
+ // debuggee should stop after event generation
+ else if (event instanceof BreakpointEvent) {
+ breakpointEventReceived = true;
+ vm.resume();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public void waitBreakpointEvent() {
+ while (!breakpointEventReceived)
+ Thread.yield();
+ }
+ }
+
+ // debug information about location (implements Comparable to make possible
+ // using DebugLocation with java.util.Set)
+ public static class DebugLocation implements Comparable<DebugLocation> {
+ public DebugLocation(String sourceName, String sourcePath, String methodName, int inputLine, int outputLine) {
+ this.sourceName = sourceName;
+ this.sourcePath = sourcePath;
+ this.inputLine = inputLine;
+ this.outputLine = outputLine;
+ this.methodName = methodName;
+ }
+
+ public String sourceName;
+
+ public String sourcePath;
+
+ public String methodName;
+
+ public int inputLine;
+
+ public int outputLine;
+
+ public String toString() {
+ return "Line number: " + inputLine + " SourceName: " + sourceName + " SourcePath: " + sourcePath;
+ }
+
+ // compare DebugLocation with com.sun.jdi.Location
+ public boolean compare(Location location, String stratum) {
+ try {
+ if (stratum == null) {
+ return (location.lineNumber() == inputLine) && location.sourceName().equals(sourceName)
+ && location.sourcePath().equals(sourcePath);
+ } else {
+ return (location.lineNumber(stratum) == inputLine)
+ && location.sourceName(stratum).equals(sourceName)
+ && location.sourcePath(stratum).equals(sourcePath);
+ }
+ } catch (AbsentInformationException e) {
+ return false;
+ }
+ }
+
+ // used to find locations for given line
+ public boolean isConform(String sourceName, int lineNumber) {
+ boolean sourceConform = (sourceName == null ? true : this.sourceName.equals(sourceName));
+
+ return sourceConform && (this.inputLine == lineNumber);
+ }
+
+ // implements this method to make possible using DebugLocation with java.util.Set
+ public int compareTo(DebugLocation location) {
+ return (this.sourceName.equals(location.sourceName) && this.inputLine == location.inputLine) ? 0 : 1;
+ }
+ }
+
+ // Class contains debug information about sources, paths, locations
+ // available for class
+ public static class LocationsData {
+ public LocationsData(String stratumName) {
+ this.stratumName = stratumName;
+ }
+
+ public List<String> sourceNames() {
+ List<String> sourceNames = new ArrayList<String>();
+ sourceNames.addAll(sourceLocations.keySet());
+
+ return sourceNames;
+ }
+
+ public String stratumName;
+
+ // is stratum default for ReferenceType
+ public boolean isDefault;
+
+ // locations for source files
+ public Map<String, List<DebugLocation>> sourceLocations = new TreeMap<String, List<DebugLocation>>();
+
+ // all locations for stratum
+ public List<DebugLocation> allLocations = new ArrayList<DebugLocation>();
+
+ // all paths for stratum
+ public List<String> paths = new ArrayList<String>();
+ }
+
+ static protected String locationToString(Location location, String stratum) {
+ String result;
+
+ result = "Line number: " + (stratum == null ? location.lineNumber() : location.lineNumber(stratum));
+
+ try {
+ result += (" Source name: " + (stratum == null ? location.sourceName() : location.sourceName(stratum)));
+ } catch (AbsentInformationException e) {
+ result += (" Source name: " + " INFORMATION IS ABSENT");
+ }
+
+ try {
+ result += (" Source path: " + (stratum == null ? location.sourcePath() : location.sourcePath(stratum)));
+ } catch (AbsentInformationException e) {
+ result += (" Source path: " + " INFORMATION IS ABSENT");
+ }
+
+ return result;
+ }
+
+ // seach class file for given class and create copy of this class file in
+ // 'testWorkDir' directory
+ protected File createLocalClassfileCopy(String className) throws IOException {
+ int index = className.lastIndexOf(".");
+
+ String path;
+
+ if (index < 0)
+ path = "";
+ else
+ path = className.substring(0, index).replace(".", "/");
+
+ File dirs = new File(testWorkDir + "/" + path);
+ dirs.mkdirs();
+
+ File oldFile = null;
+ {
+ java.nio.file.Path tmp = ClassFileFinder.findClassFile(className, classpath);
+ oldFile = tmp == null ? null : tmp.toFile();
+ }
+ File newFile = copyFile(oldFile,
+ testWorkDir + "/" + className.replace(".", "/") + ".class");
+
+ return newFile;
+ }
+
+ // create class file with multiple strata
+ protected void savePathcedClassFile(String className, SmapGenerator smapGenerator, String smapFileName) {
+ File patchedClassFile = null;
+
+ try {
+ patchedClassFile = createLocalClassfileCopy(className);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Unexpected IO exception: " + e);
+ }
+
+ smapFileName = testWorkDir + "/" + smapFileName;
+ smapGenerator.setOutputFileName(smapFileName);
+
+ File smapFile = null;
+
+ try {
+ smapFile = smapGenerator.saveToFile(smapFileName);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Unexpected IO exception: " + e);
+ }
+
+ log.display("Add for class " + className + " following SDE: ");
+ log.display(smapGenerator.getString());
+
+ try {
+ InstallSDE.install(patchedClassFile, smapFile, false);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Unexpected IO exception: " + e);
+ }
+ }
+
+ // common for SDE tests debuggee name
+ protected String debuggeeClassName() {
+ if (classpath == null) {
+ throw new TestBug("Debugger requires 'testClassPath' parameter");
+ }
+
+ return SDEDebuggee.class.getName() + " -testClassPath " + testWorkDir;
+ }
+
+ // parses common for all SDE - tests parameters
+ protected String[] doInit(String args[], PrintStream out) {
+ args = super.doInit(args, out);
+
+ if (classpath == null) {
+ throw new TestBug("Debugger requires 'testClassPath' parameter");
+ }
+ if (testWorkDir == null) {
+ throw new TestBug("Debugger requires 'testWorkDir' parameter");
+ }
+
+ return args;
+ }
+
+ // single input line is mapped to the single output line, test stratum has
+ // single source
+ protected Map<String, LocationsData> prepareDefaultPatchedClassFile_Type1(String className, int testStratumCount,
+ boolean setJavaStratumDefault) {
+ /*
+ * "Java" "TestStratum"
+ *
+ * <init>
+ * 32 --> 1000, source1
+ * 33 --> 1001, source1
+ * ...
+ * ...
+ * 39 --> 1007, source1
+ *
+ * sde_testMethod1
+ *
+ * 43 --> 1100, source1
+ * 44 --> 1101, source1
+ * ...
+ * ...
+ * 50 --> 1107, source1
+ *
+ * sde_testMethod1
+ * 54 --> 1200, source1
+ * 55 --> 1201, source1
+ * ...
+ * ...
+ * 61 --> 1207, source1
+ */
+
+ Map<String, LocationsData> testStratumData = new TreeMap<String, LocationsData>();
+
+ String smapFileName = "TestSMAP.smap";
+ SmapGenerator smapGenerator = new SmapGenerator();
+
+ for (int i = 0; i < testStratumCount; i++) {
+ String stratumName = testStratumName + (i + 1);
+
+ LocationsData locationsData = new LocationsData(stratumName);
+
+ String sourceName = testStratumSourceName + (i + 1);
+ String sourcePath = testStratumSourcePath + (i + 1);
+
+ locationsData.paths.add(sourcePath);
+
+ SmapStratum smapStratum = new SmapStratum(stratumName);
+
+ List<DebugLocation> sourceLocations = new ArrayList<DebugLocation>();
+
+ int baseLineNumber = 1000 * (i + 1);
+
+ for (int j = 0; j < 8; j++) {
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "<init>", baseLineNumber + j, INIT_LINE + j));
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "sde_testMethod1", baseLineNumber + 100 + j, METHOD1_LINE + j));
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "sde_testMethod2", baseLineNumber + 200 + j, METHOD2_LINE + j));
+ }
+
+ locationsData.sourceLocations.put(sourceName, sourceLocations);
+ locationsData.allLocations.addAll(sourceLocations);
+
+ testStratumData.put(stratumName, locationsData);
+
+ smapStratum.addFile(sourceName, sourcePath);
+
+ for (DebugLocation debugLocation : sourceLocations) {
+ smapStratum.addLineData(debugLocation.inputLine, sourceName, 1, debugLocation.outputLine, 1);
+ }
+
+ // if setJavaStratumDefault == false do first test stratum default
+ if (!(setJavaStratumDefault) && (i == 0)) {
+ locationsData.isDefault = true;
+ smapGenerator.addStratum(smapStratum, true);
+ } else
+ smapGenerator.addStratum(smapStratum, false);
+ }
+
+ savePathcedClassFile(className, smapGenerator, smapFileName);
+
+ addJavaLocations(testStratumData, setJavaStratumDefault);
+
+ return testStratumData;
+ }
+
+ // single input line is mapped to the single output line, test stratum has 3
+ // sources
+ protected Map<String, LocationsData> prepareDefaultPatchedClassFile_Type2(String className, int testStratumCount) {
+ /*
+ * "Java" "TestStratum"
+ *
+ * <init>
+ * 32 --> 1000, source1, path1
+ * 33 --> 1001, source2, path2
+ * 34 --> 1002, source3, path3
+ * ...
+ * ...
+ *
+ * sde_testMethod1
+ * 43 --> 1100, source1, path1
+ * 44 --> 1101, source2, path2
+ * 45 --> 1102, source3, path3
+ * ...
+ * ...
+ *
+ * sde_testMethod2
+ * 54 --> 1200, source1, path1
+ * 55 --> 1201, source2, path2
+ * 56 --> 1207, source3, path3
+ * ...
+ * ...
+ */
+
+ Map<String, LocationsData> testStratumData = new TreeMap<String, LocationsData>();
+
+ String smapFileName = "TestSMAP.smap";
+ SmapGenerator smapGenerator = new SmapGenerator();
+
+ for (int i = 0; i < testStratumCount; i++) {
+ String stratumName = testStratumName + (i + 1);
+ SmapStratum smapStratum = new SmapStratum(stratumName);
+
+ LocationsData locationsData = new LocationsData(stratumName);
+
+ String sourceName1 = testStratumSourceName + (i + 1) + "_1";
+ String sourcePath1 = testStratumSourcePath + (i + 1) + "_1";
+ locationsData.paths.add(sourcePath1);
+ smapStratum.addFile(sourceName1, sourcePath1);
+
+ String sourceName2 = testStratumSourceName + (i + 1) + "_2";
+ String sourcePath2 = testStratumSourcePath + (i + 1) + "_2";
+ locationsData.paths.add(sourcePath2);
+ smapStratum.addFile(sourceName2, sourcePath2);
+
+ String sourceName3 = testStratumSourceName + (i + 1) + "_3";
+ String sourcePath3 = testStratumSourcePath + (i + 1) + "_3";
+ locationsData.paths.add(sourcePath3);
+ smapStratum.addFile(sourceName3, sourcePath3);
+
+ List<DebugLocation> source1Locations = new ArrayList<DebugLocation>();
+ List<DebugLocation> source2Locations = new ArrayList<DebugLocation>();
+ List<DebugLocation> source3Locations = new ArrayList<DebugLocation>();
+
+ for (int j = 0; j < 8; j++) {
+ if (j % 3 == 0) {
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "<init>", 1000 + j, INIT_LINE + j));
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "sde_testMethod1", 1101 + j, METHOD1_LINE + j));
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "sde_testMethod2", 1201 + j, METHOD2_LINE + j));
+ } else if (j % 3 == 1) {
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "<init>", 1000 + j, INIT_LINE + j));
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "sde_testMethod1", 1101 + j, METHOD1_LINE + j));
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "sde_testMethod2", 1201 + j, METHOD2_LINE + j));
+ } else {
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "<init>", 1000 + j, INIT_LINE + j));
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "sde_testMethod1", 1101 + j, METHOD1_LINE + j));
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "sde_testMethod2", 1201 + j, METHOD2_LINE + j));
+ }
+ }
+
+ locationsData.sourceLocations.put(sourceName1, source1Locations);
+ locationsData.sourceLocations.put(sourceName2, source2Locations);
+ locationsData.sourceLocations.put(sourceName3, source3Locations);
+
+ locationsData.allLocations.addAll(source1Locations);
+ locationsData.allLocations.addAll(source2Locations);
+ locationsData.allLocations.addAll(source3Locations);
+
+ for (DebugLocation debugLocation : locationsData.allLocations) {
+ smapStratum.addLineData(
+ debugLocation.inputLine,
+ debugLocation.sourceName,
+ 1,
+ debugLocation.outputLine,
+ 1);
+ }
+
+ smapGenerator.addStratum(smapStratum, false);
+
+ testStratumData.put(stratumName, locationsData);
+ }
+
+ savePathcedClassFile(className, smapGenerator, smapFileName);
+
+ addJavaLocations(testStratumData, true);
+
+ return testStratumData;
+ }
+
+ // single input line is mapped to two output lines
+ protected Map<String, LocationsData> prepareDefaultPatchedClassFile_Type3(String className, int testStratumCount,
+ boolean setJavaStratumDefault) {
+ /*
+ * "Java" "TestStratum"
+ *
+ * <init>
+ * 32 --> 1001, source1
+ * 34 --> 1002, source1
+ * 36 --> 1003, source1
+ * 38 --> 1004, source1
+ *
+ * sde_testMethod1
+ * 43 --> 1101, source1
+ * 45 --> 1102, source1
+ * 47 --> 1103, source1
+ * 49 --> 1104, source1
+ *
+ * sde_testMethod2
+ * 54 --> 1201, source1
+ * 56 --> 1202, source1
+ * 58 --> 1203, source1
+ * 60 --> 1204, source1
+ */
+
+ Map<String, LocationsData> testStratumData = new TreeMap<String, LocationsData>();
+
+ String smapFileName = "TestSMAP.smap";
+ SmapGenerator smapGenerator = new SmapGenerator();
+
+ for (int i = 0; i < testStratumCount; i++) {
+ String stratumName = testStratumName + (i + 1);
+ LocationsData locationsData = new LocationsData(stratumName);
+
+ String sourceName = testStratumSourceName + (i + 1);
+ String sourcePath = testStratumSourcePath + (i + 1);
+ locationsData.paths.add(sourcePath);
+
+ SmapStratum smapStratum = new SmapStratum(stratumName);
+
+ List<DebugLocation> sourceLocations = new ArrayList<DebugLocation>();
+
+ int baseLineNumber = 1000 * (i + 1);
+
+ for (int j = 0; j < 4; j++) {
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "<init>", baseLineNumber + j, INIT_LINE + j * 2));
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "sde_testMethod1", baseLineNumber + 100 + j, METHOD1_LINE + j * 2));
+ sourceLocations.add(new DebugLocation(sourceName, sourcePath,
+ "sde_testMethod2", baseLineNumber + 200 + j, METHOD2_LINE + j * 2));
+ }
+
+ locationsData.allLocations.addAll(sourceLocations);
+ locationsData.sourceLocations.put(sourceName, sourceLocations);
+
+ testStratumData.put(stratumName, locationsData);
+
+ smapStratum.addFile(sourceName, sourcePath);
+
+ for (DebugLocation debugLocation : locationsData.allLocations) {
+ smapStratum.addLineData(debugLocation.inputLine, sourceName, 1, debugLocation.outputLine, 1);
+ }
+
+ // if setJavaStratumDefault == false do first stratum default
+ if (!setJavaStratumDefault && (i == 0)) {
+ locationsData.isDefault = true;
+ smapGenerator.addStratum(smapStratum, true);
+ } else
+ smapGenerator.addStratum(smapStratum, false);
+ }
+
+ savePathcedClassFile(className, smapGenerator, smapFileName);
+
+ addJavaLocations(testStratumData, setJavaStratumDefault);
+
+ return testStratumData;
+ }
+
+ // 3 different test stratums define disjoint locations sets
+ protected Map<String, LocationsData> prepareDefaultPatchedClassFile_Type4(String className) {
+ /*
+ * "Java" "TestStratum1" "TestStratum2" "TestStratum3"
+ *
+ * <init>
+ * 32 --> 1000
+ * ...
+ * ...
+ * 39 --> 1007
+ *
+ * sde_testMethod1
+ * 43 --> 1100
+ * ...
+ * ...
+ * 50 --> 1107
+ *
+ * sde_testMethod2
+ * 54 --> 1200
+ * ...
+ * ...
+ * 61 --> 1207
+ */
+ Map<String, LocationsData> testStratumData = new TreeMap<String, LocationsData>();
+
+ String smapFileName = "TestSMAP.smap";
+
+ SmapGenerator smapGenerator = new SmapGenerator();
+
+ String stratumName = testStratumName + "1";
+ LocationsData locationsData = new LocationsData(stratumName);
+ List<DebugLocation> sourceLocations = new ArrayList<DebugLocation>();
+ String methodName = "<init>";
+ for (int i = 0; i < 8; i++) {
+ sourceLocations.add(new DebugLocation(
+ testStratumSourceName, testStratumSourcePath, methodName,
+ 1000 + i, INIT_LINE + i));
+ }
+ locationsData.allLocations.addAll(sourceLocations);
+ locationsData.sourceLocations.put(testStratumSourceName, sourceLocations);
+ testStratumData.put(stratumName, locationsData);
+
+ stratumName = testStratumName + "2";
+ locationsData = new LocationsData(stratumName);
+ sourceLocations = new ArrayList<DebugLocation>();
+ methodName = "sde_testMethod1";
+ for (int i = 0; i < 8; i++) {
+ sourceLocations.add(new DebugLocation(
+ testStratumSourceName, testStratumSourcePath, methodName,
+ 1100 + i, METHOD1_LINE + i));
+ }
+ locationsData.allLocations.addAll(sourceLocations);
+ locationsData.sourceLocations.put(testStratumSourceName, sourceLocations);
+ testStratumData.put(stratumName, locationsData);
+
+ stratumName = testStratumName + "3";
+ locationsData = new LocationsData(stratumName);
+ sourceLocations = new ArrayList<DebugLocation>();
+ methodName = "sde_testMethod2";
+ for (int i = 0; i < 8; i++) {
+ sourceLocations.add(new DebugLocation(testStratumSourceName, testStratumSourcePath,
+ methodName, 1200 + i, METHOD2_LINE + i));
+ }
+ locationsData.allLocations.addAll(sourceLocations);
+ locationsData.sourceLocations.put(testStratumSourceName, sourceLocations);
+ testStratumData.put(stratumName, locationsData);
+
+ for (String stratum : testStratumData.keySet()) {
+ SmapStratum smapStratum = new SmapStratum(stratum);
+ smapStratum.addFile(testStratumSourceName, testStratumSourcePath);
+
+ for (DebugLocation debugLocation : testStratumData.get(stratum).allLocations)
+ smapStratum.addLineData(
+ debugLocation.inputLine,
+ debugLocation.sourceName,
+ 1,
+ debugLocation.outputLine,
+ 1);
+
+ smapGenerator.addStratum(smapStratum, false);
+ }
+
+ savePathcedClassFile(className, smapGenerator, smapFileName);
+
+ return testStratumData;
+ }
+
+ // single input line is mapped to the single output line, test stratum has 3
+ // sources,
+ // lines in each method has same numbers, each method has locations in 3
+ // sources
+ protected Map<String, LocationsData> prepareDefaultPatchedClassFile_Type5(String className, int testStratumCount) {
+ /*
+ * "Java" "TestStratum"
+ *
+ * <init>
+ * 32 --> 1000, source1, path1
+ * 33 --> 1000, source2, path2
+ * 34 --> 1000, source3, path3
+ * ...
+ * ...
+ *
+ * sde_testMethod1
+ * 43 --> 1100, source1, path1
+ * 44 --> 1100, source2, path2
+ * 45 --> 1100, source3, path3
+ * ...
+ * ...
+ *
+ * sde_testMethod2
+ * 54 --> 1200, source1, path1
+ * 55 --> 1200, source2, path2
+ * 56 --> 1200, source3, path3
+ * ...
+ * ...
+ */
+
+ Map<String, LocationsData> testStratumData = new TreeMap<String, LocationsData>();
+
+ String smapFileName = "TestSMAP.smap";
+ SmapGenerator smapGenerator = new SmapGenerator();
+
+ for (int i = 0; i < testStratumCount; i++) {
+ String stratumName = testStratumName + (i + 1);
+ SmapStratum smapStratum = new SmapStratum(stratumName);
+
+ LocationsData locationsData = new LocationsData(stratumName);
+
+ String sourceName1 = testStratumSourceName + (i + 1) + "_1";
+ String sourcePath1 = testStratumSourcePath + (i + 1) + "_1";
+ locationsData.paths.add(sourcePath1);
+ smapStratum.addFile(sourceName1, sourcePath1);
+
+ String sourceName2 = testStratumSourceName + (i + 1) + "_2";
+ String sourcePath2 = testStratumSourcePath + (i + 1) + "_2";
+ locationsData.paths.add(sourcePath2);
+ smapStratum.addFile(sourceName2, sourcePath2);
+
+ String sourceName3 = testStratumSourceName + (i + 1) + "_3";
+ String sourcePath3 = testStratumSourcePath + (i + 1) + "_3";
+ locationsData.paths.add(sourcePath3);
+ smapStratum.addFile(sourceName3, sourcePath3);
+
+ List<DebugLocation> source1Locations = new ArrayList<DebugLocation>();
+ List<DebugLocation> source2Locations = new ArrayList<DebugLocation>();
+ List<DebugLocation> source3Locations = new ArrayList<DebugLocation>();
+
+ for (int j = 0; j < 8; j++) {
+ if (j % 3 == 0) {
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "<init>", 1000, INIT_LINE + j));
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "sde_testMethod1", 1100, METHOD1_LINE + j));
+ source1Locations.add(new DebugLocation(sourceName1, sourcePath1,
+ "sde_testMethod2", 1200, METHOD2_LINE + j));
+ } else if (j % 3 == 1) {
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "<init>", 1000, INIT_LINE + j));
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "sde_testMethod1", 1100, METHOD1_LINE + j));
+ source2Locations.add(new DebugLocation(sourceName2, sourcePath2,
+ "sde_testMethod2", 1200, METHOD2_LINE + j));
+ } else {
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "<init>", 1000, INIT_LINE + j));
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "sde_testMethod1", 1100, METHOD1_LINE + j));
+ source3Locations.add(new DebugLocation(sourceName3, sourcePath3,
+ "sde_testMethod2", 1200, METHOD2_LINE + j));
+ }
+ }
+
+ locationsData.sourceLocations.put(sourceName1, source1Locations);
+ locationsData.sourceLocations.put(sourceName2, source2Locations);
+ locationsData.sourceLocations.put(sourceName3, source3Locations);
+
+ locationsData.allLocations.addAll(source1Locations);
+ locationsData.allLocations.addAll(source2Locations);
+ locationsData.allLocations.addAll(source3Locations);
+
+ for (DebugLocation debugLocation : locationsData.allLocations) {
+ smapStratum.addLineData(
+ debugLocation.inputLine,
+ debugLocation.sourceName,
+ 1,
+ debugLocation.outputLine,
+ 1);
+ }
+
+ smapGenerator.addStratum(smapStratum, false);
+
+ testStratumData.put(stratumName, locationsData);
+ }
+
+ savePathcedClassFile(className, smapGenerator, smapFileName);
+
+ return testStratumData;
+ }
+
+ public static File copyFile(File srcFile, String newFileName) throws IOException {
+ FileChannel inChannel = new FileInputStream(srcFile).getChannel();
+
+ File newFile = new File(newFileName);
+ newFile.createNewFile();
+ FileChannel outChannel = new FileOutputStream(newFile).getChannel();
+
+ outChannel.transferFrom(inChannel, 0, inChannel.size());
+
+ outChannel.close();
+ inChannel.close();
+
+ return newFile;
+ }
+
+ // find all locations of method with given name
+ // (used to check result of 'Method.allLineLocations()')
+ static protected List<DebugLocation> locationsOfMethod(List<DebugLocation> debugLocations, String methodName) {
+ List<DebugLocation> result = new ArrayList<DebugLocation>();
+
+ for (DebugLocation debugLocation : debugLocations) {
+ if (debugLocation.methodName.equals(methodName))
+ result.add(debugLocation);
+ }
+
+ return result;
+ }
+
+ // find all locations for given line and source name
+ // (used to check result of 'Method.locationsOfLine()' and
+ // 'ReferenceType.locationsOfLine()')
+ static protected List<DebugLocation> locationsOfLine(List<DebugLocation> debugLocations, String sourceName,
+ int lineNumber) {
+ List<DebugLocation> result = new ArrayList<DebugLocation>();
+
+ for (DebugLocation debugLocation : debugLocations) {
+ if (debugLocation.isConform(sourceName, lineNumber))
+ result.add(debugLocation);
+ }
+
+ return result;
+ }
+
+ // find locations unique by line number and source name
+ // (used in 'check_ReferenceType_locationsOfLine' and
+ // 'check_Method_locationsOfLine' to find all line numbers available for
+ // ReferenceType or Method)
+ static protected Set<DebugLocation> allUniqueLocations(List<DebugLocation> debugLocations) {
+ Set<DebugLocation> result = new TreeSet<DebugLocation>();
+
+ for (DebugLocation debugLocation : debugLocations) {
+ if (!result.contains(debugLocation)) {
+ result.add(debugLocation);
+ }
+ }
+
+ return result;
+ }
+
+ // check is list of Locations contains only expected locations
+ protected void compareLocations(List<Location> locations, List<DebugLocation> expectedLocations, String stratum) {
+ boolean success = true;
+
+ List<Location> tempLocations = new LinkedList<Location>(locations);
+
+ List<DebugLocation> tempExpectedLocations = new LinkedList<DebugLocation>(expectedLocations);
+
+ for(Iterator<Location> locationsIterator = tempLocations.iterator(); locationsIterator.hasNext();) {
+ boolean isExpected = false;
+ Location location = locationsIterator.next();
+
+ for(Iterator<DebugLocation> expectedLocationsIterator = tempExpectedLocations.iterator(); expectedLocationsIterator.hasNext();) {
+ DebugLocation expectedLocation = expectedLocationsIterator.next();
+ if (expectedLocation.compare(location, stratum)) {
+ isExpected = true;
+ locationsIterator.remove();
+ expectedLocationsIterator.remove();
+ break;
+ }
+ }
+ if (!isExpected) {
+ success = false;
+ log.complain("Location " + location + " were not found in expected locations");
+ }
+ }
+
+ if (tempLocations.size() != 0) {
+ success = false;
+ setSuccess(false);
+ log.complain("Not all locations were found in expected");
+ }
+
+ if (tempExpectedLocations.size() != 0) {
+ success = false;
+ setSuccess(false);
+ log.complain("Following expected locations were not found in received");
+ for (DebugLocation expectedLocation : tempExpectedLocations) {
+ log.complain(expectedLocation.toString());
+ }
+ }
+
+ if (!success) {
+ setSuccess(false);
+ log.complain("Expected and actual locations differ");
+
+ log.complain("Actual locations: ");
+ for (Location location : locations) {
+ log.complain(locationToString(location, stratum));
+ }
+
+ log.complain("Expected locations: ");
+ for (DebugLocation expectedLocation : expectedLocations) {
+ log.complain(expectedLocation.toString());
+ }
+ }
+ }
+
+ // test all SDE related methods of ReferenceType
+ protected void checkReferenceType(String stratum, ReferenceType referenceType, List<String> expectedSourceNames,
+ List<String> expectedSourcePaths, List<DebugLocation> expectedLocations) {
+ log.display("Check sourceNames");
+ check_ReferenceType_sourceNames(referenceType, stratum, expectedSourceNames);
+ log.display("Check sourcePaths");
+ check_ReferenceType_sourcePaths(referenceType, stratum, expectedSourcePaths);
+ log.display("Check allLocations");
+ check_ReferenceType_allLineLocations(referenceType, stratum, expectedLocations);
+ log.display("Check locationsOfLine");
+ check_ReferenceType_locationsOfLine(referenceType, stratum, false, expectedLocations);
+
+ for (Method method : referenceType.methods()) {
+ List<DebugLocation> expectedLocationsOfMethod = locationsOfMethod(expectedLocations, method.name());
+
+ log.display("Check allLineLocations for method '" + method.name() + "'");
+ check_Method_allLineLocations(method, stratum, expectedLocationsOfMethod);
+ log.display("Check locationsOfLine for method '" + method.name() + "'");
+ check_Method_locationsOfLine(method, stratum, false, expectedLocationsOfMethod);
+ }
+ }
+
+ // check is 'ReferenceType.sourceNames' returns only expected sources
+ protected void check_ReferenceType_sourceNames(ReferenceType referenceType, String stratum,
+ List<String> expectedSourceNames) {
+ try {
+ if (stratum == null) {
+ String sourceName = referenceType.sourceName();
+ String expectedSourceName = expectedSourceNames.get(0);
+
+ if (!sourceName.equals(expectedSourceName)) {
+ setSuccess(false);
+ log.complain("Unexpected result of ReferenceType.sourceName(): " + sourceName + ", expected is "
+ + expectedSourceName);
+ }
+ } else {
+ boolean success = true;
+
+ List<String> sourceNames = referenceType.sourceNames(stratum);
+
+ if (!expectedSourceNames.containsAll(sourceNames)) {
+ success = false;
+ log.complain("ReferenceType.sourceNames() returns unexpected names");
+ }
+
+ if (!sourceNames.containsAll(expectedSourceNames)) {
+ success = false;
+ log.complain("Not all expected source names was returned by ReferenceType.sourceNames()");
+ }
+
+ if (!success) {
+ log.complain("Expected source names:");
+ for (String name : expectedSourceNames)
+ log.complain(name);
+ log.complain("Actual source names:");
+ for (String name : sourceNames)
+ log.complain(name);
+ }
+ }
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+
+ // check is 'ReferenceType.sourcePaths' returns only expected paths
+ protected void check_ReferenceType_sourcePaths(ReferenceType referenceType, String stratum,
+ List<String> expectedSourcePaths) {
+ try {
+ boolean success = true;
+
+ List<String> sourcePaths = referenceType.sourcePaths(stratum);
+
+ if (!expectedSourcePaths.containsAll(sourcePaths)) {
+ success = false;
+ log.complain("ReferenceType.sourcePaths() returns unexpected paths");
+ }
+
+ if (!sourcePaths.containsAll(expectedSourcePaths)) {
+ success = false;
+ log.complain("Not all expected paths was returned by ReferenceType.sourcePaths()");
+ }
+
+ if (!success) {
+ log.complain("Expected paths:");
+ for (String path : expectedSourcePaths)
+ log.complain(path);
+ log.complain("Actual paths:");
+ for (String path : sourcePaths)
+ log.complain(path);
+ }
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+
+ // check that method 'ReferenceType.allLineLocations' returns only expected
+ // locations
+ protected void check_ReferenceType_allLineLocations(ReferenceType referenceType, String stratum,
+ List<DebugLocation> expectedLocations) {
+ try {
+ List<Location> locations = referenceType.allLineLocations();
+ compareLocations(locations, expectedLocations, stratum);
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ }
+
+ // check that method 'Method.allLineLocations' returns only expected
+ // locations
+ protected void check_Method_allLineLocations(Method method, String stratum,
+ List<DebugLocation> expectedLocationsOfMethod) {
+ try {
+ List<Location> methodAllLineLocations = method.allLineLocations();
+ compareLocations(methodAllLineLocations, expectedLocationsOfMethod, stratum);
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+
+ // for each line available for method check result of
+ // 'Method.locationsOfLine'
+ protected void check_Method_locationsOfLine(Method method, String stratum, boolean allSources,
+ List<DebugLocation> expectedLocationsOfMethod) {
+ try {
+ for (DebugLocation uniqueLocation : allUniqueLocations(expectedLocationsOfMethod)) {
+ String sourceName = allSources ? null : uniqueLocation.sourceName;
+
+ List<DebugLocation> expectedLocationsOfLine = locationsOfLine(
+ expectedLocationsOfMethod,
+ sourceName,
+ uniqueLocation.inputLine);
+
+ List<Location> locationsOfLine = (stratum == null) ? method.locationsOfLine(uniqueLocation.inputLine)
+ : method.locationsOfLine(stratum, sourceName, uniqueLocation.inputLine);
+
+ compareLocations(locationsOfLine, expectedLocationsOfLine, stratum);
+ }
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+
+ // for each line available for ReferenceType check result of
+ // 'ReferenceType.locationsOfLine'
+ protected void check_ReferenceType_locationsOfLine(ReferenceType referenceType, String stratum, boolean allSources,
+ List<DebugLocation> expectedLocations) {
+ try {
+ for (DebugLocation uniqueLocation : allUniqueLocations(expectedLocations)) {
+ String sourceName = allSources ? null : uniqueLocation.sourceName;
+
+ List<DebugLocation> expectedLocationsOfLine = locationsOfLine(
+ expectedLocations,
+ sourceName,
+ uniqueLocation.inputLine);
+
+ List<Location> locations = (stratum == null) ? referenceType.locationsOfLine(uniqueLocation.inputLine)
+ : referenceType.locationsOfLine(stratum, sourceName, uniqueLocation.inputLine);
+
+ compareLocations(locations, expectedLocationsOfLine, stratum);
+ }
+ } catch (AbsentInformationException e) {
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ }
+
+ // check that method 'ReferenceType.availableStrata' returns only expected
+ // stratums
+ protected void check_ReferenceType_availableStrata(ReferenceType referenceType, List<String> expectedStrata) {
+ boolean success = true;
+
+ List<String> strata = referenceType.availableStrata();
+
+ if (!expectedStrata.containsAll(strata)) {
+ success = false;
+ log.complain("ReferenceType.availableStrata() returns unexpected values");
+ }
+
+ if (!strata.containsAll(expectedStrata)) {
+ success = false;
+ log.complain("Not all expected stratums was returned by ReferenceType.availableStrata()");
+ }
+
+ if (!success) {
+ log.complain("Expected stratums:");
+ for (String name : expectedStrata)
+ log.complain(name);
+ log.complain("Actual stratums:");
+ for (String name : strata)
+ log.complain(name);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapGenerator.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi.sde;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a source map (SMAP), which serves to associate lines
+ * of the input source to lines in the generated output source in the
+ * final .class file, according to the JSR-045 spec.
+ */
+public class SmapGenerator {
+
+ //*********************************************************************
+ // Overview
+
+ /*
+ * The SMAP syntax is reasonably straightforward. The purpose of this
+ * class is currently twofold:
+ * - to provide a simple but low-level Java interface to build
+ * a logical SMAP
+ * - to serialize this logical SMAP for eventual inclusion directly
+ * into a .class file.
+ */
+
+
+ //*********************************************************************
+ // Private state
+
+ private String outputFileName;
+ private String defaultStratum = "Java";
+ private List<SmapStratum> strata = new ArrayList<SmapStratum>();
+ private List<String> embedded = new ArrayList<String>();
+ private boolean doEmbedded = true;
+
+ //*********************************************************************
+ // Methods for adding mapping data
+
+ /**
+ * Sets the filename (without path information) for the generated
+ * source file. E.g., "foo$jsp.java".
+ */
+ public synchronized void setOutputFileName(String x) {
+ outputFileName = x;
+ }
+
+ /**
+ * Adds the given SmapStratum object, representing a Stratum with
+ * logically associated FileSection and LineSection blocks, to
+ * the current SmapGenerator. If <tt>default</tt> is true, this
+ * stratum is made the default stratum, overriding any previously
+ * set default.
+ *
+ * @param stratum the SmapStratum object to add
+ * @param defaultStratum if <tt>true</tt>, this SmapStratum is considered
+ * to represent the default SMAP stratum unless
+ * overwritten
+ */
+ public synchronized void addStratum(SmapStratum stratum,
+ boolean defaultStratum) {
+ strata.add(stratum);
+ if (defaultStratum)
+ this.defaultStratum = stratum.getStratumName();
+ }
+
+ /**
+ * Adds the given string as an embedded SMAP with the given stratum name.
+ *
+ * @param smap the SMAP to embed
+ * @param stratumName the name of the stratum output by the compilation
+ * that produced the <tt>smap</tt> to be embedded
+ */
+ public synchronized void addSmap(String smap, String stratumName) {
+ embedded.add("*O " + stratumName + "\n"
+ + smap
+ + "*C " + stratumName + "\n");
+ }
+
+ /**
+ * Instructs the SmapGenerator whether to actually print any embedded
+ * SMAPs or not. Intended for situations without an SMAP resolver.
+ *
+ * @param status If <tt>false</tt>, ignore any embedded SMAPs.
+ */
+ public void setDoEmbedded(boolean status) {
+ doEmbedded = status;
+ }
+
+ public File saveToFile(String fileName)
+ throws IOException
+ {
+ File file = new File(fileName);
+
+ file.createNewFile();
+
+ FileOutputStream outStream = new FileOutputStream(file);
+ outStream.write(getString().getBytes());
+ outStream.close();
+
+ return file;
+ }
+
+ //*********************************************************************
+ // Methods for serializing the logical SMAP
+
+ public synchronized String getString() {
+ // check state and initialize buffer
+ if (outputFileName == null)
+ throw new IllegalStateException();
+ StringBuffer out = new StringBuffer();
+
+ // start the SMAP
+ out.append("SMAP\n");
+ out.append(outputFileName + '\n');
+ out.append(defaultStratum + '\n');
+
+ // include embedded SMAPs
+ if (doEmbedded) {
+ int nEmbedded = embedded.size();
+ for (int i = 0; i < nEmbedded; i++) {
+ out.append(embedded.get(i));
+ }
+ }
+
+ // print our StratumSections, FileSections, and LineSections
+ int nStrata = strata.size();
+ for (int i = 0; i < nStrata; i++) {
+ SmapStratum s = (SmapStratum) strata.get(i);
+ out.append(s.getString());
+ }
+
+ // end the SMAP
+ out.append("*E\n");
+
+ return out.toString();
+ }
+
+ public String toString() { return getString(); }
+
+ //*********************************************************************
+ // For testing (and as an example of use)...
+
+ public static void main(String args[]) {
+ SmapGenerator g = new SmapGenerator();
+ g.setOutputFileName("foo.java");
+ SmapStratum s = new SmapStratum("JSP");
+ s.addFile("foo.jsp");
+ s.addFile("bar.jsp", "/foo/foo/bar.jsp");
+ s.addLineData(1, "foo.jsp", 1, 1, 1);
+ s.addLineData(2, "foo.jsp", 1, 6, 1);
+ s.addLineData(3, "foo.jsp", 2, 10, 5);
+ s.addLineData(20, "bar.jsp", 1, 30, 1);
+ g.addStratum(s, true);
+ System.out.print(g);
+
+ System.out.println("---");
+
+ SmapGenerator embedded = new SmapGenerator();
+ embedded.setOutputFileName("blargh.tier2");
+ s = new SmapStratum("Tier2");
+ s.addFile("1.tier2");
+ s.addLineData(1, "1.tier2", 1, 1, 1);
+ embedded.addStratum(s, true);
+ g.addSmap(embedded.toString(), "JSP");
+ System.out.println(g);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/SmapStratum.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jdi.sde;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the line and file mappings associated with a JSR-045
+ * "stratum".
+ */
+public class SmapStratum
+{
+
+ //*********************************************************************
+ // Class for storing LineInfo data
+
+ /**
+ * Represents a single LineSection in an SMAP, associated with
+ * a particular stratum.
+ */
+ public static class LineInfo {
+ private int inputStartLine = -1;
+ private int outputStartLine = -1;
+ private int lineFileID = 0;
+ private int inputLineCount = 1;
+ private int outputLineIncrement = 1;
+ private boolean lineFileIDSet = false;
+
+ /** Sets InputStartLine. */
+ public void setInputStartLine(int inputStartLine) {
+ if (inputStartLine < 0)
+ throw new IllegalArgumentException("" + inputStartLine);
+ this.inputStartLine = inputStartLine;
+ }
+
+ /** Sets OutputStartLine. */
+ public void setOutputStartLine(int outputStartLine) {
+ if (outputStartLine < 0)
+ throw new IllegalArgumentException("" + outputStartLine);
+ this.outputStartLine = outputStartLine;
+ }
+
+ /**
+ * Sets lineFileID. Should be called only when different from
+ * that of prior LineInfo object (in any given context) or 0
+ * if the current LineInfo has no (logical) predecessor.
+ * <tt>LineInfo</tt> will print this file number no matter what.
+ */
+ public void setLineFileID(int lineFileID) {
+ if (lineFileID < 0)
+ throw new IllegalArgumentException("" + lineFileID);
+ this.lineFileID = lineFileID;
+ this.lineFileIDSet = true;
+ }
+
+ /** Sets InputLineCount. */
+ public void setInputLineCount(int inputLineCount) {
+ if (inputLineCount < 0)
+ throw new IllegalArgumentException("" + inputLineCount);
+ this.inputLineCount = inputLineCount;
+ }
+
+ /** Sets OutputLineIncrement. */
+ public void setOutputLineIncrement(int outputLineIncrement) {
+ if (outputLineIncrement < 0)
+ throw new IllegalArgumentException("" + outputLineIncrement);
+ this.outputLineIncrement = outputLineIncrement;
+ }
+
+ /**
+ * Retrieves the current LineInfo as a String, print all values
+ * only when appropriate (but LineInfoID if and only if it's been
+ * specified, as its necessity is sensitive to context).
+ */
+ public String getString() {
+ if (inputStartLine == -1 || outputStartLine == -1)
+ throw new IllegalStateException();
+ StringBuffer out = new StringBuffer();
+ out.append(inputStartLine);
+ if (lineFileIDSet)
+ out.append("#" + lineFileID);
+ if (inputLineCount != 1)
+ out.append("," + inputLineCount);
+ out.append(":" + outputStartLine);
+ if (outputLineIncrement != 1)
+ out.append("," + outputLineIncrement);
+ out.append('\n');
+ return out.toString();
+ }
+
+ public String toString() {
+ return getString();
+ }
+ }
+
+ //*********************************************************************
+ // Private state
+
+ private String stratumName;
+ private List<String> fileNameList;
+ private List<String> filePathList;
+ private List<LineInfo> lineData;
+ private int lastFileID;
+
+ //*********************************************************************
+ // Constructor
+
+ /**
+ * Constructs a new SmapStratum object for the given stratum name
+ * (e.g., JSP).
+ *
+ * @param stratumName the name of the stratum (e.g., JSP)
+ */
+ public SmapStratum(String stratumName) {
+ this.stratumName = stratumName;
+ fileNameList = new ArrayList<String>();
+ filePathList = new ArrayList<String>();
+ lineData = new ArrayList<LineInfo>();
+ lastFileID = 0;
+ }
+
+ //*********************************************************************
+ // Methods to add mapping information
+
+ /**
+ * Adds record of a new file, by filename.
+ *
+ * @param filename the filename to add, unqualified by path.
+ */
+ public void addFile(String filename) {
+ addFile(filename, filename);
+ }
+
+ /**
+ * Adds record of a new file, by filename and path. The path
+ * may be relative to a source compilation path.
+ *
+ * @param filename the filename to add, unqualified by path
+ * @param filePath the path for the filename, potentially relative
+ * to a source compilation path
+ */
+ public void addFile(String filename, String filePath) {
+ int pathIndex = filePathList.indexOf(filePath);
+ if (pathIndex == -1) {
+ fileNameList.add(filename);
+ filePathList.add(filePath);
+ }
+ }
+
+ /**
+ * Adds complete information about a simple line mapping. Specify
+ * all the fields in this method; the back-end machinery takes care
+ * of printing only those that are necessary in the final SMAP.
+ * (My view is that fields are optional primarily for spatial efficiency,
+ * not for programmer convenience. Could always add utility methods
+ * later.)
+ *
+ * @param inputStartLine starting line in the source file
+ * (SMAP <tt>InputStartLine</tt>)
+ * @param inputFileName the filepath (or name) from which the input comes
+ * (yields SMAP <tt>LineFileID</tt>) Use unqualified names
+ * carefully, and only when they uniquely identify a file.
+ * @param inputLineCount the number of lines in the input to map
+ * (SMAP <tt>LineFileCount</tt>)
+ * @param outputStartLine starting line in the output file
+ * (SMAP <tt>OutputStartLine</tt>)
+ * @param outputLineIncrement number of output lines to map to each
+ * input line (SMAP <tt>OutputLineIncrement</tt>). <i>Given the
+ * fact that the name starts with "output", I continuously have
+ * the subconscious urge to call this field
+ * <tt>OutputLineExcrement</tt>.</i>
+ */
+ public void addLineData(
+ int inputStartLine,
+ String inputFileName,
+ int inputLineCount,
+ int outputStartLine,
+ int outputLineIncrement) {
+ // check the input - what are you doing here??
+ int fileIndex = fileNameList.indexOf(inputFileName);
+ if (fileIndex == -1) // still
+ throw new IllegalArgumentException(
+ "inputFileName: " + inputFileName);
+
+ //Jasper incorrectly SMAPs certain Nodes, giving them an
+ //outputStartLine of 0. This can cause a fatal error in
+ //optimizeLineSection, making it impossible for Jasper to
+ //compile the JSP. Until we can fix the underlying
+ //SMAPping problem, we simply ignore the flawed SMAP entries.
+ if (outputStartLine == 0)
+ return;
+
+ // build the LineInfo
+ LineInfo li = new LineInfo();
+ li.setInputStartLine(inputStartLine);
+ li.setInputLineCount(inputLineCount);
+ li.setOutputStartLine(outputStartLine);
+ li.setOutputLineIncrement(outputLineIncrement);
+ if (fileIndex != lastFileID)
+ li.setLineFileID(fileIndex);
+ lastFileID = fileIndex;
+
+ // save it
+ lineData.add(li);
+ }
+
+ //*********************************************************************
+ // Methods to retrieve information
+
+ /**
+ * Returns the name of the stratum.
+ */
+ public String getStratumName() {
+ return stratumName;
+ }
+
+ /**
+ * Returns the given stratum as a String: a StratumSection,
+ * followed by at least one FileSection and at least one LineSection.
+ */
+ public String getString() {
+ // check state and initialize buffer
+ if (fileNameList.size() == 0 || lineData.size() == 0)
+ return null;
+
+ StringBuffer out = new StringBuffer();
+
+ // print StratumSection
+ out.append("*S " + stratumName + "\n");
+
+ // print FileSection
+ out.append("*F\n");
+ int bound = fileNameList.size();
+ for (int i = 0; i < bound; i++) {
+ if (filePathList.get(i) != null) {
+ out.append("+ " + i + " " + fileNameList.get(i) + "\n");
+ // Source paths must be relative, not absolute, so we
+ // remove the leading "/", if one exists.
+ String filePath = (String)filePathList.get(i);
+ if (filePath.startsWith("/")) {
+ filePath = filePath.substring(1);
+ }
+ out.append(filePath + "\n");
+ } else {
+ out.append(i + " " + fileNameList.get(i) + "\n");
+ }
+ }
+
+ // print LineSection
+ out.append("*L\n");
+ bound = lineData.size();
+ for (int i = 0; i < bound; i++) {
+ LineInfo li = (LineInfo)lineData.get(i);
+ out.append(li.getString());
+ }
+
+ return out.toString();
+ }
+
+ public String toString() {
+ return getString();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/sde/TestClass1.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+
+// THIS TEST IS LINE NUMBER SENSITIVE
+
+package nsk.share.jdi.sde;
+
+// Class contains 3 methods with several locations, do not edit this file because of line numbers are hardcoded in tests
+public class TestClass1 {
+ public TestClass1()
+ {
+ super(); // SDEDebugger.INIT_LINE
+ int i = 0;
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ }
+
+ public void sde_testMethod1()
+ {
+ int i = 0; // SDEDebugger.METHOD1_LINE
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ }
+
+ public void sde_testMethod2()
+ {
+ int i = 0; // SDEDebugger.METHOD2_LINE
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/JNIreferences.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2006, 2018, 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.
+ */
+#include "jni.h"
+#include <stdlib.h>
+#include "nsk_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_PTR
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG_2(x, y) y
+#define JNI_ENV_ARG_3(x, y, z) y, z
+#define JNI_ENV_ARG_4(x, y, z, a) y, z, a
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG_2(x,y) x, y
+#define JNI_ENV_ARG_3(x, y, z) x, y, z
+#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+static jobject* globalReferences = NULL;
+static jweak* weakReferences = NULL;
+
+JNIEXPORT jint JNICALL
+Java_nsk_share_ReferringObject_createJNIGlobalReferenceNative(JNIEnv *env,
+ jobject thisObject, jobject object, jint maxJNIGlobalReferences)
+{
+ jint i;
+ jint result = -1;
+
+ if(globalReferences == NULL)
+ {
+ globalReferences = (jobject*)malloc(sizeof(jobject) * maxJNIGlobalReferences);
+
+ if(globalReferences == NULL)
+ {
+ NSK_COMPLAIN0("malloc return NULL\n");
+ return -1;
+ }
+
+ for(i = 0; i < maxJNIGlobalReferences; i++)
+ {
+ globalReferences[i] = NULL;
+ }
+ }
+
+ for(i = 0; i < maxJNIGlobalReferences; i++)
+ {
+ jobject reference = globalReferences[i];
+
+ if(reference == NULL)
+ {
+ reference = JNI_ENV_PTR(env)->NewGlobalRef(JNI_ENV_ARG_2(env, object));
+
+ if(reference == NULL)
+ {
+ NSK_COMPLAIN0("NewGlobalRef return NULL\n");
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewGlobalRef return NULL"));
+ }
+
+ globalReferences[i] = reference;
+
+ result = i;
+
+ break;
+ }
+ }
+
+ return result;
+}
+
+JNIEXPORT void JNICALL
+Java_nsk_share_ReferringObject_deleteJNIGlobalReferenceNative(JNIEnv *env,
+ jobject thisObject, jint index)
+{
+ jobject reference = globalReferences[index];
+
+ if(reference == NULL)
+ {
+ NSK_COMPLAIN1("globalReferences[%d] = NULL, possible wrong index is passed\n", index);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "Requested globalReferences[] element is NULL, possible wrong index is passed"));
+ }
+
+ JNI_ENV_PTR(env)->DeleteGlobalRef(JNI_ENV_ARG_2(env, reference));
+
+ globalReferences[index] = NULL;
+}
+
+
+JNIEXPORT void JNICALL
+Java_nsk_share_ReferringObject_createJNILocalReferenceNative(JNIEnv *env,
+ jobject thisObject, jobject object, jobject createWicket, jobject deleteWicket)
+{
+ jobject reference = JNI_ENV_PTR(env)->NewLocalRef(JNI_ENV_ARG_2(env, object));
+ jclass klass;
+
+ if(reference == NULL)
+ {
+ NSK_COMPLAIN0("NewLocalRef return NULL\n");
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewLocalRef return NULL"));
+ }
+
+ klass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, createWicket));
+
+ // notify another thread that JNI local reference has been created
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, createWicket, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "unlock", "()V"))));
+
+ // wait till JNI local reference can be released (it will heppen then we will leave the method)
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, deleteWicket, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "waitFor", "()V"))));
+}
+
+JNIEXPORT jint JNICALL
+Java_nsk_share_ReferringObject_createJNIWeakReferenceNative(JNIEnv *env,
+ jobject thisObject, jobject object, jint maxJNIWeakReferences)
+{
+ jint i;
+ jint result = -1;
+
+ if(weakReferences == NULL)
+ {
+ weakReferences = (jweak*)malloc(sizeof(jweak) * maxJNIWeakReferences);
+
+ if(weakReferences == NULL)
+ {
+ NSK_COMPLAIN0("malloc return NULL\n");
+
+ return -1;
+ }
+
+ for(i = 0; i < maxJNIWeakReferences; i++)
+ {
+ weakReferences[i] = NULL;
+ }
+ }
+
+ for(i = 0; i < maxJNIWeakReferences; i++)
+ {
+ jobject reference = weakReferences[i];
+
+ if(reference == NULL)
+ {
+ reference = JNI_ENV_PTR(env)->NewWeakGlobalRef(JNI_ENV_ARG_2(env, object));
+
+ if(reference == NULL)
+ {
+ NSK_COMPLAIN0("NewWeakGlobalRef return NULL\n");
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "NewWeakGlobalRef return NULL"));
+ }
+
+ weakReferences[i] = reference;
+
+ result = i;
+
+ break;
+ }
+ }
+
+ return result;
+}
+
+JNIEXPORT void JNICALL
+Java_nsk_share_ReferringObject_deleteJNIWeakReferenceNative(JNIEnv *env,
+ jobject thisObject, jint index)
+{
+ jweak reference = weakReferences[index];
+
+ if(reference == NULL)
+ {
+ NSK_COMPLAIN1("weakReferences[%d] = NULL, possible wrong index is passed\n", index);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "Requested weakReferences[] element is NULL, possible wrong index is passed"));
+ }
+
+ if(JNI_ENV_PTR(env)->IsSameObject(JNI_ENV_ARG_3(env, reference, NULL)) == JNI_TRUE)
+ {
+ NSK_COMPLAIN0("TEST BUG: Weak reference was collected\n");
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestBug")), "TEST BUG: Weak reference was collected"));
+ }
+
+ JNI_ENV_PTR(env)->DeleteWeakGlobalRef(JNI_ENV_ARG_2(env, reference));
+
+ weakReferences[index] = NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/README Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,61 @@
+Copyright (c) 2003, 2018, 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.
+
+---------------------------------------------------------------------------------
+
+This directory contains source files of testbase_nsk JNI framework,
+which provides support for JNI tests and accessing JNI environment.
+
+ Source files:
+ jni_tools.h
+ jni_tools.c
+
+ Naming conventions:
+ macroses: NSK_JNI_*
+ functions: nsk_JNI_*
+
+---------------------------------------------------------------------------------
+
+jni_tools.h
+
+Provides functions and macroses for invocation of JNI functions
+and checking JNI errors and pending exceptions:
+
+ NSK_JNI_VERIFY(jni, action)
+ NSK_JNI_VERIFY_NEGATIVE(jni, action)
+
+Typical example of usage of NSK_JNI_VERIFY and NSK_CPP_STUB macroses
+for invokation of JNI functions:
+
+ // jni->FindClass(jni, class_name)
+ if (!NSK_JNI_VERIFY(jni,
+ NSK_CPP_STUB2(FindClass, jni, class_name) != NULL)) {
+ return JNI_ERR;
+ }
+
+or with saving obtained data:
+
+ // cls = jni->FindClass(jni, class_name)
+ if (!NSK_JNI_VERIFY(jni, (cls =
+ NSK_CPP_STUB2(FindClass, jni, class_name)) != NULL)) {
+ return JNI_ERR;
+ }
+
+---------------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+/*************************************************************/
+#if (defined(WIN32) || defined(_WIN32))
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+/*************************************************************/
+
+#include "jni.h"
+
+/*************************************************************/
+
+#include "nsk_tools.h"
+#include "jni_tools.h"
+
+/*************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+int nsk_jni_check_exception(JNIEnv* jni, const char file[], int line)
+{
+ jthrowable throwable;
+
+ NSK_TRACE(throwable = NSK_CPP_STUB1(ExceptionOccurred, jni));
+ if (throwable != NULL) {
+ nsk_lcomplain(file, line, "Exception in JNI call (cleared):\n");
+ NSK_TRACE(NSK_CPP_STUB1(ExceptionDescribe, jni));
+ NSK_TRACE(NSK_CPP_STUB1(ExceptionClear, jni));
+ return NSK_TRUE;
+ }
+ return NSK_FALSE;
+}
+
+int nsk_jni_lverify(int positive, JNIEnv* jni, int status,
+ const char file[], int line, const char format[], ...)
+{
+ int failure=0;
+ int negative = !positive;
+ va_list ap;
+ va_start(ap,format);
+
+ nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap);
+ if (status == negative) {
+ nsk_lvcomplain(file,line,format,ap);
+ nsk_printf("# verified JNI assertion is FALSE\n");
+ failure=1;
+ }
+
+ failure = nsk_jni_check_exception(jni, file, line) || failure;
+
+ va_end(ap);
+ return !failure;
+}
+
+int nsk_jni_lverify_void(JNIEnv* jni, const char file[], int line,
+ const char format[], ...)
+{
+ int failure=0;
+ va_list ap;
+ va_start(ap,format);
+
+ nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap);
+ failure = nsk_jni_check_exception(jni, file, line);
+
+ if (failure)
+ nsk_lvcomplain(file,line,format,ap);
+
+ va_end(ap);
+ return !failure;
+}
+
+char *jlong_to_string(jlong value, char *string) {
+ char buffer[32];
+ char *pbuf, *pstr;
+
+ pstr = string;
+ if (value == 0) {
+ *pstr++ = '0';
+ } else {
+ if (value < 0) {
+ *pstr++ = '-';
+ value = -value;
+ }
+ pbuf = buffer;
+ while (value != 0) {
+ *pbuf++ = '0' + (char)(value % 10);
+ value = value / 10;
+ }
+ while (pbuf != buffer) {
+ *pstr++ = *--pbuf;
+ }
+ }
+ *pstr = '\0';
+
+ return string;
+}
+
+char *julong_to_string(julong value, char *string) {
+ char buffer[32];
+ char *pbuf, *pstr;
+
+ pstr = string;
+ if (value == 0) {
+ *pstr++ = '0';
+ } else {
+ pbuf = buffer;
+ while (value != 0) {
+ *pbuf++ = '0' + (char)(value % 10);
+ value = value / 10;
+ }
+ while (pbuf != buffer) {
+ *pstr++ = *--pbuf;
+ }
+ }
+ *pstr = '\0';
+
+ return string;
+}
+
+void mssleep(long millis) {
+#if (defined(WIN32) || defined(_WIN32))
+ Sleep(millis);
+#else
+ /* Using select for portable sleep */
+ /* Not using usleep because of it's possible interaction with SIGALRM */
+ struct timeval timeout;
+ timeout.tv_sec = millis / 1000;
+ timeout.tv_usec = (millis % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &timeout);
+#endif
+}
+
+void
+jni_print_vmargs(JavaVMInitArgs vmargs)
+{
+ int i = 0;
+
+ printf("JavaVMInitArgs:\n");
+ printf(" version = %d\n", vmargs.version);
+ printf(" ignoreUnrecognized = %d\n", vmargs.ignoreUnrecognized);
+
+ printf(" vmargs.nOptions = %d\n", vmargs.nOptions);
+ for (i = 0; i < vmargs.nOptions; i++) {
+ printf(" options[%d].optionString = %s\n", i, vmargs.options[i].optionString);
+ printf(" options[%d].extraInfo = %p\n", i, vmargs.options[i].extraInfo);
+ }
+}
+
+JavaVMOption*
+jni_create_vmoptions(int size, char *args[], int argsCnt)
+{
+ int i;
+ JavaVMOption *options = NULL;
+
+ if (size <= 0)
+ return options;
+
+ options = (JavaVMOption*)calloc(size, sizeof(JavaVMOption));
+
+ for (i=0; i<argsCnt; i++)
+ options[i].optionString = args[i];
+
+ return options;
+}
+
+/*************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jni/jni_tools.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+#ifndef NSK_JNI_TOOLS_DEFINED
+#define NSK_JNI_TOOLS_DEFINED
+
+/*************************************************************/
+
+#include "jni.h"
+
+/*************************************************************/
+
+#include "nsk_tools.h"
+
+/*************************************************************/
+
+/* printf format specifier for jlong */
+#ifdef _WIN32
+
+#define LL "I64"
+#include <STDDEF.H>
+
+#else // !_WIN32
+
+#include <stdint.h>
+
+#ifdef _LP64
+#define LL "l"
+#else
+#define LL "ll"
+#endif
+
+#endif // !_WIN32
+
+/**
+ * Additional Java basic types
+ */
+
+#ifdef _WIN32
+ typedef unsigned __int64 julong;
+#else
+ typedef unsigned long long julong;
+#endif
+
+/*************************************************************/
+
+/**
+ * Execute action with JNI call, check result for true and
+ * pending exception and complain error if required.
+ * Also trace action execution if tracing mode enabled.
+ */
+#define NSK_JNI_VERIFY(jni, action) \
+ (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \
+ nsk_jni_lverify(NSK_TRUE,jni,action,__FILE__,__LINE__,"%s\n",#action))
+
+/**
+ * Execute action with JNI call, check result for false and
+ * pending exception and complain error if required.
+ * Also trace action execution if tracing mode enabled.
+ */
+#define NSK_JNI_VERIFY_NEGATIVE(jni,action) \
+ (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \
+ nsk_jni_lverify(NSK_FALSE,jni,action,__FILE__,__LINE__,"%s\n",#action))
+
+/**
+ * Execute action with JNI call, check result for
+ * pending exception and complain error if required.
+ * Also trace action execution if tracing mode enabled.
+ */
+#define NSK_JNI_VERIFY_VOID(jni,action) \
+ (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \
+ action, \
+ nsk_jni_lverify_void(jni, __FILE__,__LINE__,"%s\n",#action))
+
+/*************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+/**
+ * If positive, assert status is true; or
+ * if !positive, assert status is not true.
+ * Assert means: complain if the assertion is false.
+ * Return the assertion value, either NSK_TRUE or NSK_FALSE.
+ * Anyway, trace if "nsk_tools" mode is verbose and
+ * print information about pending exceptions if status is false.
+ */
+int nsk_jni_lverify(int positive, JNIEnv* jni, int status,
+ const char file[], int line, const char format[], ...);
+
+/**
+ * If positive, assert status is true; or
+ * if !positive, assert status is not true.
+ * Assert means: complain if the assertion is false.
+ * Return the assertion value, either NSK_TRUE or NSK_FALSE.
+ * Anyway, trace if "nsk_tools" mode is verbose and
+ * print information about pending exceptions if status is false.
+ */
+int nsk_jni_lverify_void(JNIEnv* jni, const char file[], int line,
+ const char format[], ...);
+
+/**
+ * Checks if pending exception exists and then prints error message
+ * with exception description, clears pending exception amd return 1.
+ * Otherwise, does noting and returns 0,
+ */
+int nsk_jni_check_exception(JNIEnv* jni, const char file[], int line);
+
+/**
+ * Convert the digits of the given value argument to a null-terminated
+ * character string and store the result (up to 32 bytes) in string.
+ * If value is negative, the first character of the stored string is
+ * the minus sign (-). The function returns a pointer to the begining
+ * of the result string.
+ */
+char *jlong_to_string(jlong value, char *string);
+
+/**
+ * Convert the digits of the given value argument to a null-terminated
+ * character string and store the result (up to 32 bytes) in string.
+ * The function returns a pointer to the begining of the result string.
+ */
+char *julong_to_string(julong value, char *string);
+
+/**
+ * Sleep for given number of milliseconds.
+ */
+void mssleep(long millis);
+
+/**
+ * Create JavaVMOption array of size 'size' and fills
+ * first argsCnt elements from args[].
+ * Callee is responsible to free JavaVMOption*.
+ * No other memory deallocations are required.
+ */
+JavaVMOption* jni_create_vmoptions(int size, char *args[], int argsCnt);
+
+/**
+ * Print JavaVMInitArgs values to stdout.
+ */
+void jni_print_vmargs(JavaVMInitArgs vmargs);
+
+/*************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2006, 2018, 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.
+ */
+
+// THIS TEST IS LINE NUMBER SENSITIVE
+
+package nsk.share.jpda;
+
+import java.io.*;
+import java.util.*;
+import nsk.share.*;
+import nsk.share.test.*;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+/*
+ * Class can be used as base debuggee class in jdi and jdwp tests.
+ * Class contains common method for initializing log, pipe, vm, and several common auxiliary methods. Subclass should implement parseCommand() and, if needed, doInit(parse command line parameters)
+ * !!! Edit carefully, value of 'DEFAULT_BREAKPOINT_LINE' is hardcoded !!!
+ */
+public class AbstractDebuggeeTest {
+ protected DebugeeArgumentHandler argHandler;
+
+ protected IOPipe pipe;
+
+ protected Log log;
+
+ protected boolean callExit = true;
+
+ private boolean success = true;
+
+ protected void setSuccess(boolean value) {
+ success = value;
+ }
+
+ public boolean getSuccess() {
+ return success;
+ }
+
+ public final static int DEFAULT_BREAKPOINT_LINE = 63;
+
+ public final static String DEFAULT_BREAKPOINT_METHOD_NAME = "breakpointMethod";
+
+ public void breakpointMethod() {
+ log.display("In breakpoint method: 'AbstractDebuggeeTest.breakpointMethod()'"); // DEFAULT_BREAKPOINT_LINE
+ }
+
+ protected Map<String, ClassUnloader> loadedClasses = new TreeMap<String, ClassUnloader>();
+
+ public final static String COMMAND_FORCE_BREAKPOINT = "forceBreakpoint";
+
+ //load class with given name with possibility to unload it
+ static public final String COMMAND_LOAD_CLASS = "loadClass";
+
+ // unload class with given name(it is possible for classes loaded via loadTestClass method)
+ // command:className[:<unloadResult>], <unloadResult> - one of UNLOAD_RESULT_TRUE or UNLOAD_RESULT_FALSE
+ static public final String COMMAND_UNLOAD_CLASS = "unloadClass";
+
+ // Optional arguments of COMMAND_UNLOAD_CLASS
+ // (is after unloading class should be really unloaded, default value is UNLOAD_RESULT_TRUE)
+ static public final String UNLOAD_RESULT_TRUE = "unloadResultTrue";
+
+ static public final String UNLOAD_RESULT_FALSE = "unloadResultFalse";
+
+ static public final String COMMAND_CREATE_STATETESTTHREAD = "createStateTestThread";
+
+ static public final String COMMAND_NEXTSTATE_STATETESTTHREAD = "stateTestThreadNextState";
+
+ //force GC using AbstractDebuggeeTest.eatMemory()
+ static public final String COMMAND_FORCE_GC = "forceGC";
+ // GCcount is used to get information about GC activity during test
+ static public final String COMMAND_GC_COUNT = "GCcount";
+ private int lastGCCount;
+
+
+ static public final String stateTestThreadName = "stateTestThread";
+
+ static public final String stateTestThreadClassName = StateTestThread.class.getName();
+
+ // path to classes intended for loading/unloading
+ protected String classpath;
+
+ // classloader loads only test classes from nsk.*
+ public static class TestClassLoader extends CustomClassLoader {
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ if (name.startsWith("nsk."))
+ return findClass(name);
+ else
+ return super.loadClass(name);
+ }
+ }
+
+ protected StressOptions stressOptions;
+ protected Stresser stresser;
+
+ // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments
+ // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options)
+ // support -testClassPath parameter: path to find classes for custom classloader
+ protected String[] doInit(String[] args) {
+ stressOptions = new StressOptions(args);
+ stresser = new Stresser(stressOptions);
+
+ ArrayList<String> standardArgs = new ArrayList<String>();
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-testClassPath") && (i < args.length - 1)) {
+ classpath = args[i + 1];
+ i++;
+ } else
+ standardArgs.add(args[i]);
+ }
+
+ return standardArgs.toArray(new String[] {});
+ }
+
+ public void loadTestClass(String className) {
+ if (classpath == null) {
+ throw new TestBug("Debuggee requires 'testClassPath' parameter");
+ }
+
+ try {
+ ClassUnloader classUnloader = new ClassUnloader();
+
+ classUnloader.setClassLoader(new TestClassLoader());
+ classUnloader.loadClass(className, classpath);
+ loadedClasses.put(className, classUnloader);
+ } catch (ClassNotFoundException e) {
+ log.complain("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")");
+ e.printStackTrace(log.getOutStream());
+ throw new TestBug("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")");
+ }
+ }
+
+ public static final int MAX_UNLOAD_ATTEMPS = 5;
+
+ public void unloadTestClass(String className, boolean expectedUnloadingResult) {
+ ClassUnloader classUnloader = loadedClasses.get(className);
+
+ int unloadAttemps = 0;
+
+ if (classUnloader != null) {
+ boolean wasUnloaded = false;
+
+ while (!wasUnloaded && (unloadAttemps++ < MAX_UNLOAD_ATTEMPS)) {
+ wasUnloaded = classUnloader.unloadClass();
+ }
+
+ if (wasUnloaded)
+ loadedClasses.remove(className);
+ else {
+ log.display("Class " + className + " was not unloaded");
+ }
+
+ if (wasUnloaded != expectedUnloadingResult) {
+ setSuccess(false);
+
+ if (wasUnloaded)
+ log.complain("Class " + className + " was unloaded!");
+ else
+ log.complain("Class " + className + " wasn't unloaded!");
+ }
+ } else {
+ log.complain("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader");
+ throw new TestBug("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader");
+ }
+ }
+
+ static public void sleep1sec() {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ private StateTestThread stateTestThread;
+
+ public static final String COMMAND_QUIT = "quit";
+
+ public static final String COMMAND_READY = "ready";
+
+ private void createStateTestThread() {
+ if (stateTestThread != null)
+ throw new TestBug("StateTestThread already created");
+
+ stateTestThread = new StateTestThread(stateTestThreadName);
+ }
+
+ private void stateTestThreadNextState() {
+ if (stateTestThread == null)
+ throw new TestBug("StateTestThread not created");
+
+ stateTestThread.nextState();
+ }
+
+ public boolean parseCommand(String command) {
+ try {
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
+ tokenizer.whitespaceChars(':', ':');
+ tokenizer.wordChars('_', '_');
+ tokenizer.wordChars('$', '$');
+ tokenizer.wordChars('[', ']');
+
+ if (command.equals(COMMAND_FORCE_GC)) {
+ forceGC();
+ lastGCCount = getCurrentGCCount();
+ return true;
+ } else if (command.equals(COMMAND_GC_COUNT)) {
+ pipe.println(COMMAND_GC_COUNT + ":" + (getCurrentGCCount() - lastGCCount));
+ return true;
+ } else if (command.equals(COMMAND_FORCE_BREAKPOINT)) {
+ breakpointMethod();
+ return true;
+ } else if (command.equals(COMMAND_CREATE_STATETESTTHREAD)) {
+ createStateTestThread();
+
+ return true;
+ } else if (command.equals(COMMAND_NEXTSTATE_STATETESTTHREAD)) {
+ stateTestThreadNextState();
+
+ return true;
+ } else if (command.startsWith(COMMAND_LOAD_CLASS)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ loadTestClass(className);
+
+ return true;
+ } else if (command.startsWith(COMMAND_UNLOAD_CLASS)) {
+ tokenizer.nextToken();
+
+ if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
+ throw new TestBug("Invalid command format: " + command);
+
+ String className = tokenizer.sval;
+
+ boolean expectedUnloadingResult = true;
+
+ if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
+ if (tokenizer.sval.equals(UNLOAD_RESULT_TRUE))
+ expectedUnloadingResult = true;
+ else if (tokenizer.sval.equals(UNLOAD_RESULT_FALSE))
+ expectedUnloadingResult = false;
+ else
+ throw new TestBug("Invalid command format: " + command);
+ }
+
+ unloadTestClass(className, expectedUnloadingResult);
+
+ return true;
+ }
+ } catch (IOException e) {
+ throw new TestBug("Invalid command format: " + command);
+ }
+
+ return false;
+ }
+
+ protected DebugeeArgumentHandler createArgumentHandler(String args[]) {
+ return new DebugeeArgumentHandler(args);
+ }
+
+ protected void init(String args[]) {
+ argHandler = createArgumentHandler(doInit(args));
+ pipe = argHandler.createDebugeeIOPipe();
+ log = argHandler.createDebugeeLog();
+ lastGCCount = getCurrentGCCount();
+ }
+
+ public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String[] args, boolean callExit) {
+ this.argHandler = argHandler;
+ this.log = log;
+ this.pipe = pipe;
+ this.callExit = callExit;
+ doInit(args);
+ }
+
+ public void doTest(String args[]) {
+ init(args);
+ doTest();
+ }
+
+ public void doTest() {
+ do {
+ log.display("Debuggee " + getClass().getName() + " : sending the command: " + AbstractDebuggeeTest.COMMAND_READY);
+ pipe.println(AbstractDebuggeeTest.COMMAND_READY);
+
+ String command = pipe.readln();
+ log.display("Debuggee: received the command: " + command);
+
+ if (command.equals(AbstractDebuggeeTest.COMMAND_QUIT)) {
+ break;
+ } else {
+ try {
+ if (!parseCommand(command)) {
+ log.complain("TEST BUG: unknown debugger command: " + command);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ } catch (Throwable t) {
+ log.complain("Unexpected exception in debuggee: " + t);
+ t.printStackTrace(log.getOutStream());
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+ } while (true);
+
+ log.display("Debuggee: exiting");
+
+ if (callExit) {
+ if (success)
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);
+ else
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+
+ public static void eatMemory() {
+ Runtime runtime = Runtime.getRuntime();
+ long maxMemory = runtime.maxMemory();
+ int memoryChunk = (int) (maxMemory / 50);
+ try {
+ List<Object> list = new ArrayList<Object>();
+ while (true) {
+ list.add(new byte[memoryChunk]);
+ }
+ } catch (OutOfMemoryError e) {
+ // expected exception
+ }
+ }
+
+ public static int getCurrentGCCount() {
+ int result = 0;
+ List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
+ for (GarbageCollectorMXBean bean : gcBeans) {
+ result += bean.getCollectionCount();
+ }
+ return result;
+ }
+
+ public void forceGC() {
+ eatMemory();
+ }
+
+ public void voidValueMethod() {
+ }
+
+ public void unexpectedException(Throwable t) {
+ setSuccess(false);
+ t.printStackTrace(log.getOutStream());
+ log.complain("Unexpected exception: " + t);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1888 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import nsk.share.*;
+import nsk.share.jpda.*;
+
+/**
+ * <code>BindServer</code> is an utility to perform JPDA tests
+ * in remote mode across network.
+ * <p>
+ * This utility should be started on remote host. It listens for connection
+ * from JPDA tests and launches debuggee VM on this host.
+ * <p>
+ * <code>BindServer</code> works together with <code>Binder</code> used in
+ * the tests to incapsulate actions required for launching debuggee VM.
+ * See <code>ProcessBinder</code> and <code>DebugeeArgumentHandler</code>
+ * to know how run tests in local or remote mode across network or
+ * on an single host.
+ * <p>
+ * <code>BindServer</code> is started on the debuggee host.
+ * It recognizes following command line options:
+ * <ul>
+ * <li><code>-bind.file=<i>filename</i></code> - configuration file
+ * <li><code>-verbose</code> - print verbose messages
+ * </ul>
+ * <p>
+ * Only required option is <code>-bind.file</code>, which points to the file
+ * where pairs of particular pathes are presented as they are seen from
+ * both hosts along with some other <code>BindServer</code> options.
+ * See <i>execution.html</i> to read more about format of bind-file.
+ *
+ * @see DebugeeBinder
+ * @see DebugeeArgumentHandler
+ */
+public class BindServer implements Finalizable {
+
+ /** Version of <code>BindServer</code> implementation. */
+ public static final long VERSION = 2;
+
+ /** Timeout in milliseconds used for waiting for inner threads. */
+ private static long THREAD_TIMEOUT = DebugeeBinder.THREAD_TIMEOUT; // milliseconds
+
+ private static int PASSED = 0;
+ private static int FAILED = 2;
+ private static int JCK_BASE = 95;
+
+ private static int TRACE_LEVEL_PACKETS = 10;
+ private static int TRACE_LEVEL_THREADS = 20;
+ private static int TRACE_LEVEL_ACTIONS = 30;
+ private static int TRACE_LEVEL_SOCKETS = 40;
+ private static int TRACE_LEVEL_IO = 50;
+
+ private static String pathSeparator = System.getProperty("path.separator");
+ private static String fileSeparator = System.getProperty("file.separator");
+
+ private static char pathSeparatorChar = pathSeparator.charAt(0);
+ private static char fileSeparatorChar = fileSeparator.charAt(0);
+
+ private static Log log = null;
+ private static Log.Logger logger = null;
+ private static ArgumentHandler argHandler = null;
+
+ private static String pathConvertions[][] = null;
+
+ private ListeningThread listeningThread = null;
+
+ private int totalRequests = 0;
+ private int acceptedRequests = 0;
+ private int unauthorizedRequests = 0;
+ private int busyRequests = 0;
+
+ /**
+ * Start <code>BindServer</code> utility from command line.
+ * This method invokes <code>run()</code> and redirects output
+ * to <code>System.err</code>.
+ *
+ * @param argv list of command line arguments
+ */
+ public static void main (String argv[]) {
+ System.exit(run(argv,System.err) + JCK_BASE);
+ }
+
+ /**
+ * Start <code>BindServer</code> utility from JCK-compatible
+ * environment.
+ *
+ * @param argv list of command line arguments
+ * @param out outpur stream for log messages
+ *
+ * @return FAILED if error occured
+ * PASSED oterwise
+ */
+ public static int run(String argv[], PrintStream out) {
+ return new BindServer().runIt(argv, out);
+ }
+
+ /**
+ * Perform execution of <code>BindServer</code>.
+ * This method handles command line arguments, starts seperate
+ * thread for listening connection from test on remote host,
+ * and waits for command "exit" from a user.
+ * Finally it closes all conections and prints connections
+ * statiscs.
+ *
+ * @param argv list of command line arguments
+ * @param out outpur stream for log messages
+ *
+ * @return FAILED if error occured
+ * PASSED oterwise
+ */
+ private int runIt(String argv[], PrintStream out) {
+ try {
+ argHandler = new ArgumentHandler(argv);
+ } catch (ArgumentHandler.BadOption e) {
+ out.println("ERROR: " + e.getMessage());
+ return FAILED;
+ }
+
+ if (argHandler.getArguments().length > 0) {
+ out.println("ERROR: " + "Too many positional arguments in command line");
+ return FAILED;
+ }
+
+ log = new Log(out, argHandler);
+ log.enableErrorsSummary(false);
+ log.enableVerboseOnError(false);
+ logger = new Log.Logger(log, "");
+
+ Finalizer bindFinalizer = new Finalizer(this);
+ bindFinalizer.activate();
+
+ logger.trace(TRACE_LEVEL_THREADS, "BindServer: starting main thread");
+
+ logger.display("Listening to port: " + argHandler.getBindPortNumber());
+ logger.display("Authorizing host: " + argHandler.getDebuggerHost());
+
+ pathConvertions = new String[][] {
+ { "TESTED_JAVA_HOME", argHandler.getDebuggerJavaHome(), argHandler.getDebugeeJavaHome() },
+ { "TESTBASE", argHandler.getDebuggerTestbase(), argHandler.getDebugeeTestbase() },
+ { "WORKDIR", argHandler.getDebuggerWorkDir(), argHandler.getDebugeeWorkDir() }
+ };
+
+ logger.display("Translating pathes:");
+ for (int i = 0; i < pathConvertions.length; i++) {
+ logger.display(pathConvertions[i][0] + ":" +"\n"
+ + " " + pathConvertions[i][1] + "\n"
+ + " =>" + "\n"
+ + " " + pathConvertions[i][2]);
+ }
+
+ String windir = argHandler.getDebugeeWinDir();
+ if (!(windir == null || windir.equals(""))) {
+ logger.display("Using WINDIR: \n"
+ + " " + argHandler.getDebugeeWinDir());
+ }
+
+ BufferedReader stdIn = new BufferedReader(
+ new InputStreamReader(System.in));
+
+ listeningThread = new ListeningThread(this);
+ listeningThread.bind();
+ listeningThread.start();
+
+ System.out.println("\n"
+ + "BindServer started" + "\n"
+ + "Type \"exit\" to shut down BindServer"
+ + "\n");
+
+ for (;;) {
+ try {
+ String userInput = stdIn.readLine();
+ if (userInput == null || userInput.equals("exit")
+ || userInput.equals("quit")) {
+ logger.display("Shutting down BindServer");
+ stdIn.close();
+ stdIn = null;
+ break;
+ } else if (userInput.trim().equals("")) {
+ continue;
+ } else {
+ System.out.println("ERROR: Unknown command: " + userInput);
+ }
+ } catch(IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while reading console command:\n\t"
+ + e);
+ }
+ }
+
+ printSummary(System.out);
+
+ logger.trace(TRACE_LEVEL_THREADS, "BindServer: exiting main thread");
+ try {
+ finalize();
+ } catch (Throwable e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while finalization of BindServer:\n\t" + e);
+ }
+
+ return PASSED;
+ }
+
+ /**
+ * Print usefull summary statistics about connections occured.
+ *
+ * @param out output stream for printing statistics
+ */
+ private void printSummary(PrintStream out) {
+ out.println("\n"
+ + "Connections summary:" + "\n"
+ + " Tolal connections: " + totalRequests + "\n"
+ + " Accepted authorized: " + acceptedRequests + "\n"
+ + " Rejected unauthorized " + unauthorizedRequests + "\n"
+ + " Rejected being busy: " + busyRequests + "\n");
+ };
+
+ /**
+ * Check if given <code>path</code> starts with the specified prefix taking
+ * into account difference between <code>slashChar<code> used in <code>path</code>
+ * and <code>fileSeparatorChar</code> used in <code>prefix</code>.
+ *
+ * @param path path to check
+ * @param prefix prefix to compare with
+ * @param slashChar file separator used in <code>path</code>
+ */
+ private static boolean checkPathPrefix(String path, String prefix, char slashChar) {
+ int prefixLength = prefix.length();
+ if (prefixLength > path.length()) {
+ return false;
+ }
+ for (int i = 0; i < prefixLength; i++) {
+ char pathChar = path.charAt(i);
+ char prefixChar = prefix.charAt(i);
+
+ if (pathChar != prefixChar) {
+ if ((pathChar == slashChar || pathChar == fileSeparatorChar
+ || pathChar == '\\' || pathChar == '/')
+ && (prefixChar == slashChar || prefixChar == fileSeparatorChar
+ || prefixChar == '\\' || prefixChar == '/')) {
+ // do nothing
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert given path according to list of prefixes from
+ * <code>pathConvertions</code> table.
+ *
+ * @param path path for converting
+ * @param slash file separator used in <code>path</code>
+ * @param name path identifier used for error messages
+ * @param strict force throwing Failure if path is not matched
+ *
+ * @return string with the converted path
+ *
+ * @throws Failure if path does not matched for translation
+ */
+ private static String convertPath(String path, String slash, String name, boolean strict) {
+ if (path == null)
+ return null;
+
+ char slashChar = slash.charAt(0);
+
+ for (int i = 0; i < pathConvertions.length; i++) {
+ String from = pathConvertions[i][1];
+ String to = pathConvertions[i][2];
+ if (checkPathPrefix(path, from, slashChar)) {
+ return (to + path.substring(from.length())).replace(slashChar, fileSeparatorChar);
+ }
+ }
+ if (strict) {
+ throw new Failure("Path not matched for translation " + name + ":\n\t" + path);
+ }
+ return path;
+ }
+
+ /**
+ * Convert given list of pathes according to list of prefixes from
+ * <code>pathConvertions</code> table by invoking <code>convertPath()</code>
+ * for each path from the list.
+ *
+ * @param list list of pathes for converting
+ * @param slash file separator used in pathes
+ * @param name path identifier used for error messages
+ * @param strict force throwing Failure if some path is not matched
+ *
+ * @return list of strings with converted pathes
+ *
+ * @throws Failure if some path does not matched for translation
+ *
+ * @see #convertPath()
+ */
+ private static String[] convertPathes(String[] list, String slash, String name, boolean strict) {
+ String[] converted = new String[list.length];
+ for (int i = 0; i < list.length; i++) {
+ converted[i] = convertPath(list[i], slash, name, strict);
+ }
+ return converted;
+ }
+
+ /**
+ * Pause current thread for specified amount of time in milliseconds,
+ * This method uses <code>Object.wait(long)</code> method as a reliable
+ * method which prevents whole VM from suspending.
+ *
+ * @param millisecs - amount of time in milliseconds
+ */
+ private static void sleeping(int millisecs) {
+ Object obj = new Object();
+
+ synchronized(obj) {
+ try {
+ obj.wait(millisecs);
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ new Failure("Thread interrupted while sleeping:\n\t" + e);
+ }
+ }
+ }
+
+ /**
+ * Wait for given thread finished for specified timeout or
+ * interrupt this thread if not finished.
+ *
+ * @param thr thread to wait for
+ * @param millisecs timeout in milliseconds
+ */
+ private static void waitInterruptThread(Thread thr, long millisecs) {
+ if (thr != null) {
+ String name = thr.getName();
+ try {
+ if (thr.isAlive()) {
+ logger.trace(TRACE_LEVEL_THREADS, "Waiting for thread: " + name);
+ thr.join(millisecs);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure ("Thread interrupted while waiting for another thread:\n\t"
+ + e);
+ } finally {
+ if (thr.isAlive()) {
+ logger.trace(TRACE_LEVEL_THREADS, "Interrupting not finished thread: " + name);
+ thr.interrupt();
+/*
+ logger.display("Stopping not finished thread: " + thr);
+ thr.stop();
+ */
+ }
+ }
+ }
+ }
+
+ /**
+ * Wait for given thread finished for default timeout
+ * <code>THREAD_TIMEOUT</code> and
+ * interrupt this thread if not finished.
+ *
+ * @param thr thread to wait for
+ */
+ private static void waitInterruptThread(Thread thr) {
+ waitInterruptThread(thr, THREAD_TIMEOUT);
+ }
+
+ /**
+ * Close <code>BindServer</code> by finishing all threads and closing
+ * all conections.
+ */
+ public synchronized void close() {
+ if (listeningThread != null) {
+ listeningThread.close();
+ listeningThread = null;
+ }
+ }
+
+ /**
+ * Make finalization of <code>BindServer</code> object by invoking
+ * method <code>close()</code>.
+ *
+ * @see #close()
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ /**
+ * Make finalization of <code>BindServer</code> object at program exit
+ * by invoking method <code>finalize()</code>.
+ *
+ * @see #finalize()
+ */
+ public void finalizeAtExit() throws Throwable {
+ finalize();
+ logger.trace(TRACE_LEVEL_THREADS, "BindServer: finalization at exit completed");
+ }
+
+///////// Thread listening a TCP/IP socket //////////
+
+ /**
+ * An inner thread used for listening connection from remote test
+ * and starting separate serving thread for each accepted connection.
+ *
+ * @see ServingThread
+ */
+ private static class ListeningThread extends Thread {
+ private volatile boolean shouldStop = false;
+ private volatile boolean closed = false;
+
+ private BindServer owner = null;
+ private volatile ServingThread servingThread = null;
+ private volatile int taskCount = 0;
+
+ private ObjectOutputStream socOut = null;
+ private ObjectInputStream socIn = null;
+
+ private String autorizedHostName = argHandler.getDebuggerHost();
+ private InetAddress autorizedInetAddresses[] = null;
+ private int port = argHandler.getBindPortNumber();
+ private Socket socket = null;
+ private ServerSocket serverSocket = null;
+ private InetAddress clientInetAddr = null;
+ private String clientHostName = null;
+ private SocketConnection connection = null;
+
+ /**
+ * Make listening thread for given <code>BindServer</code> object
+ * as an owner and bind it to listening port by invoking method
+ * <code>bind()</code>.
+ *
+ * @see bind()
+ */
+ public ListeningThread(BindServer owner) {
+ super("ListeningThread");
+ this.owner = owner;
+ try {
+ autorizedInetAddresses = InetAddress.getAllByName(autorizedHostName);
+ } catch (UnknownHostException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Cannot resolve DEBUGGER_HOST value: " + autorizedHostName);
+ }
+ }
+
+ /**
+ * Bind ServerSocket to the specified port.
+ */
+ public void bind() {
+ for (int i = 0; !shouldStop && i < DebugeeBinder.CONNECT_TRIES; i++) {
+ try {
+ logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: binding to server socket ...");
+ // length of the queue = 2
+ serverSocket = new ServerSocket(port, 2);
+ // timeout for the ServerSocket.accept()
+ serverSocket.setSoTimeout(DebugeeBinder.CONNECT_TRY_DELAY);
+ logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: socket bound: " + serverSocket);
+ logger.display("Bound to listening port");
+ return;
+ } catch (BindException e) {
+ logger.display("Socket binding try #" + i + " failed:\n\t" + e);
+ sleeping(DebugeeBinder.CONNECT_TRY_DELAY);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while binding to socket:\n\t"
+ + e);
+ }
+ }
+ throw new Failure("Unable to bind to socket after "
+ + DebugeeBinder.CONNECT_TRIES + " tries");
+ }
+
+ /**
+ * Accept socket connection from authorized remote host and
+ * start separate <code>SrvingThread</code> to handle each connection.
+ * Connection from unauthorized hosts or connections made while
+ * current connection is alive are rejected.
+ *
+ * @see ServingThread
+ * @see #llowConnection()
+ * @see allowServing()
+ */
+ public void run() {
+ String reply = null;
+
+ logger.trace(TRACE_LEVEL_THREADS, "ListeningThread: started");
+ logger.display("Listening for connection from remote host");
+ while(!(shouldStop || isInterrupted())) {
+ try {
+ try {
+ logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: waiting for connection from test");
+ socket = serverSocket.accept();
+ logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: connection accepted");
+ } catch(InterruptedIOException e) {
+// logger.trace(TRACE_LEVEL_SOCKETS, "ListeningThread: timeout of waiting for connection from test");
+ continue;
+ }
+ owner.totalRequests++;
+ logger.display("");
+ clientInetAddr = socket.getInetAddress();
+ clientHostName = clientInetAddr.getHostName();
+ logger.display("Connection #" + owner.totalRequests
+ + " requested from host: " + clientHostName);
+ connection = new SocketConnection(logger, "BindServer");
+// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT);
+ connection.setSocket(socket);
+ socket = null;
+ if (allowConnection()) {
+ if (allowServing()) {
+ owner.acceptedRequests++;
+ reply = "host authorized: " + clientHostName;
+ logger.display("Accepting connection #" + owner.acceptedRequests
+ + ": " + reply);
+ servingThread = new ServingThread(this, connection);
+ servingThread.start();
+ cleanHostConnection();
+ } else {
+ owner.busyRequests++;
+ reply = "BindServer is busy";
+ logger.complain("Rejecting connection #" + owner.busyRequests
+ + ": " + reply);
+ connection.writeObject(new RequestFailed(reply));
+ closeHostConnection();
+ }
+ } else {
+ owner.unauthorizedRequests++;
+ reply = "host unauthorized: " + clientHostName;
+ logger.complain("Rejecting connection #" + owner.unauthorizedRequests
+ + ": " + reply);
+ connection.writeObject(new RequestFailed(reply));
+ closeHostConnection();
+ }
+ } catch (Exception e) {
+ logger.complain("Caught exception while accepting connection:\n" + e);
+ e.printStackTrace(log.getOutStream());
+ }
+ }
+ logger.trace(TRACE_LEVEL_THREADS, "ListeningThread: exiting");
+ closeConnection();
+ }
+
+ /**
+ * Check if the connection made is from authorized host.
+ *
+ * @return true if connection is allowed because host authorized
+ * false if connection is rejected because host unauthorized
+ */
+ private boolean allowConnection() {
+ // check if local host from loopback address
+ if (autorizedHostName.equals("localhost"))
+ return clientInetAddr.isLoopbackAddress();
+
+ // check if equal hostname
+ if (autorizedHostName.equals(clientHostName))
+ return true;
+
+ // check if equal host address
+ for (int i = 0; i < autorizedInetAddresses.length; i++) {
+ if (clientInetAddr.equals(autorizedInetAddresses[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if no current connection exists or it is dead.
+ * If current connection presents it will be tested by pinging
+ * remote host and aborted if host sends no reply. If an alive
+ * connection exists, new connection will be rejected.
+ *
+ * @return true if no alive connection exists
+ * false otherwise
+ */
+ private boolean allowServing() {
+ if (servingThread == null) {
+ return true;
+ }
+ if (servingThread.done) {
+ return true;
+ }
+ if (!servingThread.isConnectionAlive()) {
+ logger.display("# WARNING: Previous connection from remote host is dead: aborting connection");
+ servingThread.close();
+ servingThread = null;
+ return true;
+ }
+
+/*
+ logger.complain("Previous connection from remote host is alive: starting new connection");
+ servingThread = null;
+ return true;
+ */
+ logger.complain("Previous connection from remote host is alive: reject new connection");
+ return false;
+ }
+
+ /**
+ * Wait for this thread finished
+ * for specified timeout or interrupt it.
+ *
+ * @param millis timeout in milliseconds
+ */
+ public void waitForThread(long millis) {
+ shouldStop = true;
+ waitInterruptThread(this, millis);
+ }
+
+ /**
+ * Close socket connection from remote host.
+ */
+ private void closeHostConnection() {
+ if (connection != null) {
+ connection.close();
+ }
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ logger.complain("Caught IOException while closing socket:\n\t"
+ + e);
+ }
+ socket = null;
+ }
+ }
+
+ /**
+ * Assign <null> to connection and socket objects
+ * but do not close them.
+ */
+ private void cleanHostConnection() {
+ connection = null;
+ socket = null;
+ }
+
+ /**
+ * Close all connections and sockets.
+ */
+ private void closeConnection() {
+ closeHostConnection();
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch (IOException e) {
+ logger.complain("Caught IOException while closing ServerSocket:\n\t"
+ + e);
+ }
+ serverSocket = null;
+ }
+ }
+
+ /**
+ * Close thread by closing all connections and waiting
+ * foor thread finished.
+ *
+ * @see #closeConnection()
+ */
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+ closeHostConnection();
+ if (servingThread != null) {
+ servingThread.close();
+ servingThread = null;
+ }
+ waitForThread(THREAD_TIMEOUT);
+ closeConnection();
+ closed = true;
+ logger.trace(TRACE_LEVEL_THREADS, "ListeningThread closed");
+ }
+
+ } // ListeningThread
+
+///////// Thread working with a communication channel //////////
+
+ /**
+ * An internal thread for handling each connection from a test
+ * on remote host. It reads requests from test and starts separate
+ * <code>LaunchingThread</code> to execute each request.
+ *
+ * @see LaunchingThread
+ */
+ private static class ServingThread extends Thread {
+ private volatile boolean shouldStop = false;
+ private volatile boolean closed = false;
+ private volatile boolean done = false;
+
+ private ListeningThread owner = null;
+ private LaunchingThread launchingThread = null;
+
+ private SocketConnection connection = null;
+
+ /**
+ * Make serving thread with specified input/output connection streams
+ * and given <code>Listenerthread</code> as an owner.
+ *
+ * @param owner owner of this thread
+ * @param connection established socket connection with test
+ */
+ public ServingThread(ListeningThread owner, SocketConnection connection) {
+ super("ServingThread");
+ this.owner = owner;
+ this.connection = connection;
+ }
+
+ /**
+ * Read requests from socket connection and start <code>LaunchingThread</code>
+ * to perform each requested action.
+ */
+ public void run() {
+ logger.trace(TRACE_LEVEL_THREADS, "ServingThread: starting handling requests from debugger");
+ try {
+ // sending OK(version)
+ logger.trace(TRACE_LEVEL_ACTIONS, "ServingThread: sending initial OK(VERSION) to debugger");
+ connection.writeObject(new OK(VERSION));
+
+ // receiving TaskID(id)
+ logger.trace(TRACE_LEVEL_IO, "ServingThread: waiting for TaskID from debugger");
+ Object taskID = connection.readObject();
+ logger.trace(TRACE_LEVEL_IO, "ServingThread: received TaskID from debugger: " + taskID);
+ if (taskID instanceof TaskID) {
+ String id = ((TaskID)taskID).id;
+ owner.taskCount++;
+ logger.println("[" + owner.taskCount + "/" + owner.owner.totalRequests + "]: " + id);
+ } else {
+ throw new Failure("Unexpected TaskID received form debugger: " + taskID);
+ }
+
+ // starting launching thread
+ launchingThread = new LaunchingThread(this, connection);
+ launchingThread.start();
+
+ // receiving and handling requests
+ while(!(shouldStop || isInterrupted())) {
+ logger.trace(TRACE_LEVEL_IO, "ServingThread: waiting for request from debugger");
+ Object request = connection.readObject();
+ logger.trace(TRACE_LEVEL_IO, "ServingThread: received request from debugger: " + request);
+ if (request == null) {
+ logger.display("Connection closed");
+ break;
+ } else if (request instanceof Disconnect) {
+ logger.display("Closing connection by request");
+ request = null;
+ break;
+ } else {
+ boolean success = false;
+ long timeToFinish = System.currentTimeMillis() + THREAD_TIMEOUT;
+ while (System.currentTimeMillis() < timeToFinish) {
+ if (launchingThread.doneRequest()) {
+ success = true;
+ logger.trace(TRACE_LEVEL_ACTIONS, "ServingThread: asking launching thread to handle request: " + request);
+ launchingThread.handleRequest(request);
+ break;
+ }
+ try {
+ launchingThread.join(DebugeeBinder.TRY_DELAY);
+ } catch (InterruptedException e) {
+ throw new Failure("ServingThread interrupted while waiting for LaunchingThread:\n\t"
+ + e);
+ }
+ }
+ if (!success) {
+ logger.complain("Rejecting request because of being busy:\n" + request);
+ connection.writeObject(
+ new RequestFailed("Busy with handling previous request"));
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while handling request:\n\t" + e);
+ } finally {
+ logger.trace(TRACE_LEVEL_THREADS, "ServingThread: exiting");
+ closeConnection();
+ done = true;
+ }
+ }
+
+ /**
+ * Check if present socket connection is alive.
+ */
+ private boolean isConnectionAlive() {
+ return (connection != null && connection.isConnected());
+ }
+
+ /**
+ * Wait for this thread finished
+ * for specified timeout or interrupt it.
+ *
+ * @param millis timeout in milliseconds
+ */
+ public void waitForThread(long millis) {
+ shouldStop = true;
+ waitInterruptThread(this, millis);
+ }
+
+ /**
+ * Close socket connection from remote host.
+ */
+ private void closeConnection() {
+ if (connection != null) {
+ connection.close();
+ }
+ if (launchingThread != null) {
+ launchingThread.handleRequest(null);
+ }
+ }
+
+ /**
+ * Close thread closing socket connection and
+ * waiting for thread finished.
+ */
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+ closeConnection();
+ if (launchingThread != null) {
+ launchingThread.close();
+ launchingThread = null;
+ }
+ waitForThread(THREAD_TIMEOUT);
+ closed = true;
+ logger.trace(TRACE_LEVEL_THREADS, "ServingThread closed");
+ }
+
+ } // ServingThread
+
+///////// Thread serving a particular Binder's request //////////
+
+ /**
+ * An internal thread to execute each request from a test on remote host.
+ * Requests are coming from ServingThread by invoking handleRequest(Object)
+ * method.
+ */
+ private static class LaunchingThread extends Thread {
+ private volatile boolean shouldStop = false;
+ private volatile boolean closed = false;
+ public volatile boolean done = false;
+
+ private ServingThread owner = null;
+// private ProcessWaitingThread waitingThread = null;
+ private Process process = null;
+
+ private StreamRedirectingThread stdoutRedirectingThread = null;
+ private StreamRedirectingThread stderrRedirectingThread = null;
+
+ /** Notification about request occurence. */
+ private volatile Object notification = new Object();
+ /** Request to execute. */
+ private volatile Object request = null;
+ /** Socket stream to send replies to. */
+ private SocketConnection connection = null;
+
+ /**
+ * Make thread for executing requests from a test and
+ * send reply.
+ *
+ * @param owner owner of this thread
+ * @connection socket connection for sending replies
+ */
+ public LaunchingThread(ServingThread owner, SocketConnection connection) {
+ super("LaunchingThread");
+ this.owner = owner;
+ this.connection = connection;
+ }
+
+ /**
+ * Notify this thread that new request has come.
+ *
+ * @param request request to execute
+ */
+ public void handleRequest(Object request) {
+ synchronized (notification) {
+ this.request = request;
+ notification.notifyAll();
+ }
+ }
+
+ /**
+ * Check if request has been executed.
+ */
+ public boolean doneRequest() {
+ return done;
+ }
+
+ /**
+ * Wait for request notification from <code>ServingThread</code>
+ * and execute an action according to the request.
+ * Request <i>null</code> means thread should finish.
+ */
+ public void run() {
+ logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread: started to handle request");
+ done = true;
+ while (!isInterrupted()) {
+ // wait for new request notification
+ logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: waiting for request");
+ synchronized (notification) {
+ try {
+ notification.wait();
+ } catch (InterruptedException e) {
+ logger.complain("LaunchingThread interrupted while waiting for request:\n\t"
+ + e);
+ break;
+ }
+ }
+
+ // execute the request
+ try {
+ logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: handling request: " + request);
+ if (request == null) {
+ break;
+ } else if (request instanceof LaunchDebugee) {
+ launchDebugee((LaunchDebugee)request);
+ } else if (request instanceof WaitForDebugee) {
+ waitForDebugee((WaitForDebugee)request);
+ } else if (request instanceof DebugeeExitCode) {
+ debugeeExitCode((DebugeeExitCode)request);
+ } else if (request instanceof KillDebugee) {
+ killDebugee((KillDebugee)request);
+ } else {
+ String reason = "Unknown request: " + request;
+ logger.complain(reason);
+ sendReply(new RequestFailed(reason));
+ }
+ } catch (Exception e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while handling request:\n\t" + e);
+ }
+ done = true;
+ }
+ done = true;
+ logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread: exiting");
+ closeConnection();
+ }
+
+ /**
+ * Send given reply to remote test.
+ *
+ * @param reply reply object to send
+ */
+ public void sendReply(Object reply) throws IOException {
+ connection.writeObject(reply);
+ }
+
+ /**
+ * Send given output line to remote test.
+ *
+ * @param reply wrapper object for output line to send
+ */
+ public void sendStreamMessage(RedirectedStream wrapper) throws IOException {
+ logger.trace(TRACE_LEVEL_ACTIONS, "Sending output line wrapper to debugger: " + wrapper);
+ if (connection.isConnected()) {
+ sendReply(wrapper);
+ } else {
+ logger.complain("NOT redirected: " + wrapper.line);
+ }
+ }
+
+ /**
+ * Launch two <code>StreamRedirectingThread</code> threads to redirect
+ * stdin/stderr output of debuggee VM process via <code>BindServer</code>
+ * connection.
+ *
+ * @param process debuggee VM process
+ */
+ private void launchStreamRedirectors(Process process) {
+ stdoutRedirectingThread =
+ new StdoutRedirectingThread(this, process.getInputStream(),
+ DebugeeProcess.DEBUGEE_STDOUT_LOG_PREFIX);
+ stdoutRedirectingThread.start();
+ stderrRedirectingThread =
+ new StderrRedirectingThread(this, process.getErrorStream(),
+ DebugeeProcess.DEBUGEE_STDERR_LOG_PREFIX);
+ stderrRedirectingThread.start();
+ }
+
+ /**
+ * Execute request for launching debuggee.
+ *
+ * @param request request to execute
+ */
+ private void launchDebugee(LaunchDebugee request) throws IOException {
+ logger.trace(TRACE_LEVEL_ACTIONS, "LaunchDebugee: handle request: " + request);
+
+ if (process != null) {
+ logger.complain("Unable to launch debuggee: process already launched");
+ sendReply(new RequestFailed("Debuggee process already launched"));
+ return;
+ }
+
+ try {
+ String[] cmd = request.cmd;
+ cmd[0] = convertPath(cmd[0], request.slash, "TESTED_JAVA_HOME", true);
+ for (int i = 1; i < cmd.length; i++) {
+ cmd[i] = convertPath(cmd[i], request.slash, "JAVA_ARGS", false);
+ }
+ String workDir = convertPath(request.workDir, request.slash, "WORKDIR", true);
+ String[] classPathes = convertPathes(request.classPathes, request.slash, "CLASSPATH", true);
+ String windir = argHandler.getDebugeeWinDir();
+
+ boolean win = (!(windir == null || windir.equals("")));
+ String[] envp = new String[win ? 3 : 1] ;
+ envp[0] = "CLASSPATH=" + ArgumentParser.joinArguments(classPathes, "", pathSeparator);
+ if (win) {
+ envp[1] = "WINDIR=" + windir;
+ envp[2] = "SystemRoot=" + windir;
+ }
+
+ logger.display("Setting environment:\n"
+ + " " + ArgumentHandler.joinArguments(envp, "", "\n "));
+ logger.display("Setting work dir:\n"
+ + " " + workDir);
+ logger.display("Launching debuggee:\n"
+ + " " + ArgumentHandler.joinArguments(cmd, "\""));
+
+ process = Runtime.getRuntime().exec(cmd, envp, new File(workDir));
+ logger.display(" debuggee launched successfully");
+
+ launchStreamRedirectors(process);
+ } catch (Exception e) {
+ if (!(e instanceof Failure)) {
+ e.printStackTrace(log.getOutStream());
+ }
+ logger.complain("Caught exception while launching debuggee:\n\t" + e);
+ sendReply(new CaughtException(e));
+ return;
+ }
+
+ sendReply(new OK());
+ }
+
+ /**
+ * Execute request for waiting for debuggee exited.
+ *
+ * @param request request to execute
+ */
+ private void waitForDebugee(WaitForDebugee request) throws IOException {
+ logger.trace(TRACE_LEVEL_ACTIONS, "WaitForDebugee: handle request: " + request);
+
+ if (process == null) {
+ String reply = "No debuggee process to wait for";
+ logger.complain(reply);
+ sendReply(new RequestFailed(reply));
+ return;
+ }
+
+ logger.display("Waiting for debuggee to exit");
+/*
+ // because timeout is not supported now
+ // we do not use separate thread for waiting for process
+ // and so following lines are commented out
+
+ waitingThread = new ProcessWaitingThread();
+ logger.trace(TRACE_LEVEL_ACTIONS, "LaunchingThread: starting thread for waiting for debugee process");
+ waitingThread.start();
+ try {
+ waitingThread.join(request.timeout);
+ if (waitingThread.isAlive()) {
+ String reply = "Timeout exceeded while waiting for debuggee to exit";
+ logger.complain(reply);
+ waitingThread.interrupt();
+ sendReply(socOut, new RequestFailed(reply));
+ return;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while waiting for debuggee:\n\t" + e);
+ sendReply(new CaughtException(e));
+ return;
+ }
+ int exitStatus = waitingThread.exitStatus;
+ waitingThread = null;
+ */
+ int exitStatus;
+ try {
+ exitStatus = process.waitFor();
+ waitForRedirectors(THREAD_TIMEOUT);
+ process.destroy();
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while waiting for debuggee process to exit:\n\t"
+ + e);
+ sendReply(new CaughtException(e));
+ return;
+ }
+ logger.display(" debuggee exited with exit status: " + exitStatus);
+ sendReply(new OK(exitStatus));
+ }
+
+ /**
+ * Execute request for returning debuggee exit code.
+ *
+ * @param request request to execute
+ */
+ private void debugeeExitCode(DebugeeExitCode request) throws IOException {
+ logger.trace(TRACE_LEVEL_ACTIONS, "DebugeeExitCode: handle request: " + request);
+
+ if (process == null) {
+ String reply = "No debuggee process to get exit code for";
+ logger.complain(reply);
+ sendReply(new RequestFailed(reply));
+ return;
+ }
+
+ int exitStatus = 0;
+ try {
+ exitStatus = process.exitValue();
+ } catch (IllegalThreadStateException e) {
+ logger.display("# WARNING: Caught exception while getting exit status of debuggee:\n\t"
+ + e);
+ sendReply(new CaughtException(e));
+ return;
+ }
+ logger.trace(TRACE_LEVEL_ACTIONS, "DebugeeExitCode: return debuggee exit status: " + exitStatus);
+ sendReply(new OK(exitStatus));
+ }
+
+ /**
+ * Execute request for unconditional terminating debuggee process.
+ *
+ * @param request request to execute
+ */
+ private void killDebugee(KillDebugee request) throws IOException {
+ logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: handle request: " + request);
+
+ if (process == null) {
+ String reply = "No debuggee process to kill";
+ logger.complain(reply);
+ sendReply(new RequestFailed(reply));
+ return;
+ }
+
+ logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: killing debuggee process");
+ process.destroy();
+
+ logger.trace(TRACE_LEVEL_ACTIONS, "killDebugee: debuggee process killed");
+ sendReply(new OK());
+ }
+
+ /**
+ * Terminate debigee VM process if still alive.
+ */
+ private void terminateDebugeeAtExit() {
+ if (process != null) {
+ logger.trace(TRACE_LEVEL_ACTIONS, "Checking that debuggee process has exited correctly");
+ try {
+ int value = process.exitValue();
+ } catch (IllegalThreadStateException e) {
+ logger.complain("Debuggee process has not exited correctly: trying to kill it");
+ process.destroy();
+ try {
+ int value = process.exitValue();
+ } catch (IllegalThreadStateException ie) {
+ logger.complain("Debuggee process is alive after killing it");
+ }
+ process = null;
+ return;
+ }
+ logger.trace(TRACE_LEVEL_ACTIONS, "Debuggee process has exited correctly");
+ }
+ }
+
+ /**
+ * Wait for stream redirecting threads finished
+ * for specified timeout.
+ *
+ * @param millis timeout in milliseconds
+ */
+ private void waitForRedirectors(long millis) {
+ try {
+ if (stdoutRedirectingThread != null) {
+ stdoutRedirectingThread.join(millis);
+ }
+ if (stderrRedirectingThread != null) {
+ stderrRedirectingThread.join(millis);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while waiting for debuggee process exited:\n\t"
+ + e);
+ }
+ }
+
+ /**
+ * Wait for this thread finished
+ * for specified timeout or interrupt it.
+ *
+ * @param millis timeout in milliseconds
+ */
+ public void waitForThread(long millis) {
+ shouldStop = true;
+ handleRequest(null);
+ waitInterruptThread(this, millis);
+ }
+
+ /**
+ * Close connection with debuggee.
+ */
+ public void closeConnection() {
+ // no connections to close
+ }
+
+ /**
+ * Close thread by closing all connections with debuggee,
+ * finishing all redirectors and wait for thread finished.
+ */
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+ closeConnection();
+ terminateDebugeeAtExit();
+ if (stdoutRedirectingThread != null) {
+ stdoutRedirectingThread.close();
+ stdoutRedirectingThread = null;
+ }
+ if (stderrRedirectingThread != null) {
+ stderrRedirectingThread.close();
+ stderrRedirectingThread = null;
+ }
+ waitForThread(THREAD_TIMEOUT);
+ closed = true;
+ logger.trace(TRACE_LEVEL_THREADS, "LaunchingThread closed");
+ }
+
+ /**
+ * An inner thread for waiting for debuggee process exited
+ * and saving its exit status. (currently not used)
+ */
+/*
+ private class ProcessWaitingThread extends Thread {
+ int exitStatus = 0;
+
+ ProcessWaitingThread() {
+ super("ProcessWaitingThread");
+ }
+
+ public void run() {
+ logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread: starting waiting for process");
+ try {
+ exitStatus = process.waitFor();
+ } catch (InterruptedException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while waiting for debuggee process:\n\t"
+ + e);
+ }
+ logger.trace(TRACE_LEVEL_ACTIONS, "ProcessWaitingThread: process finished with status: " + exitStatus);
+ logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread: exiting");
+ }
+
+ public synchronized void close() {
+ logger.trace(TRACE_LEVEL_THREADS, "ProcessWaitingThread closed");
+ }
+
+ } // ProcessWaitingThread
+ */
+ } // LaunchingThread
+
+///////// Redirecting threads /////////
+
+ /**
+ * An abstract base class for internal threads which redirects stderr/stdout
+ * output from debuggee process via <code>BindServer</code> connection.
+ * <p>
+ * Two derived classes will redirect <i>stderr</i> or </i>stdout</i> stream
+ * by enwrapping stream line by <code>DebugeeStderr</code> or
+ * <code>DebugeeStderr</code> objects. They should implement only one
+ * abstract method <code>enwrapLine(String)</code> to make the difference.
+ */
+ public static abstract class StreamRedirectingThread extends Thread {
+ private volatile boolean shouldStop = false;
+ private volatile boolean closed = false;
+
+ private LaunchingThread owner = null;
+
+ private BufferedReader bin = null;
+ private String prefix = null;
+
+ /**
+ * Make a thread to enwrap and redirect lines from specified
+ * input stream with given prefix.
+ *
+ * @param owner owner of this thread
+ * @param is input stream to redirect lines from
+ * @param prefix prefix to add to each line
+ */
+ public StreamRedirectingThread(LaunchingThread owner, InputStream is, String prefix) {
+ super("StreamRedirectingThread");
+ this.prefix = prefix;
+ this.owner = owner;
+ bin = new BufferedReader(new InputStreamReader(is));
+ }
+
+ /**
+ * Read lines from an input stream, enwrap them, and send to remote
+ * test via <code>BindServer</code> connection.
+ */
+ public void run() {
+ logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread: starting redirect output stream");
+ try {
+ String line;
+ logger.trace(TRACE_LEVEL_IO, "StreamRedirectingThread: waiting for line from debuggee output");
+ while(!shouldStop) {
+ line = bin.readLine();
+ if (line == null)
+ break;
+ owner.sendStreamMessage(enwrapLine(prefix + line));
+ }
+ } catch (EOFException e) {
+ logger.display("Debuggee output stream closed by process");
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.display("# WARNING: Connection to debuggee output stream aborted:\n\t" + e);
+ } catch (Exception e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while redirecting debuggee output stream:\n\t"
+ + e);
+ }
+ logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread: exiting");
+ closeConnection();
+ }
+
+ /**
+ * Envrap output line by the appropriate wrapper.
+ * @param line line to enwrap
+ */
+ protected abstract RedirectedStream enwrapLine(String line);
+
+ /**
+ * Wait for this thread finished or interrupt it.
+ *
+ * @param millis timeout in milliseconds
+ */
+ public void waitForThread(long millis) {
+ shouldStop = true;
+ waitInterruptThread(this, millis);
+ }
+
+ /**
+ * Close redirected process output stream.
+ */
+ public void closeConnection() {
+ if (closed) {
+ return;
+ }
+ if (bin != null) {
+ try {
+ bin.close();
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ logger.complain("Caught exception while closing debuggee output stream:\n\t"
+ + e);
+ }
+ bin = null;
+ }
+ closed = true;
+ logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread closed");
+ }
+
+ /**
+ * Close thread by waiting redirected stream closed
+ * and finish the thread.
+ */
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+ waitForThread(THREAD_TIMEOUT);
+ closeConnection();
+ closed = true;
+ logger.trace(TRACE_LEVEL_THREADS, "StreamRedirectingThread closed");
+ }
+
+ } // StreamRedirectingThread
+
+ /**
+ * Particalar case of <code>StreamRedirectingThread</code> to redirect
+ * <i>stderr</i> stream by enwrapping lines into <code>DebugeeStderr</code>
+ * objects.
+ */
+ private static class StderrRedirectingThread extends StreamRedirectingThread {
+
+ /**
+ * Make a thread to redirect <i>stderr</i> output stream.
+ */
+ StderrRedirectingThread(LaunchingThread owner, InputStream is, String prefix) {
+ super(owner, is, prefix);
+ setName("StderrRedirectingThread");
+ }
+
+ /**
+ * Enwrap given line into <code>DebugeeStderr</code> object.
+ */
+ protected RedirectedStream enwrapLine(String line) {
+ return new DebugeeStderr(line);
+ }
+
+ }
+
+ /**
+ * Particalar case of <code>StreamRedirectingThread</code> to redirect
+ * <i>stdout</i> stream by enwrapping lines into <code>DebugeeStdout</code>
+ * objects.
+ */
+ private static class StdoutRedirectingThread extends StreamRedirectingThread {
+
+ /**
+ * Make a thread to redirect <i>stdout</i> output stream.
+ */
+ StdoutRedirectingThread(LaunchingThread owner, InputStream is, String prefix) {
+ super(owner, is, prefix);
+ setName("StdoutRedirectingThread");
+ }
+
+ /**
+ * Enwrap given line into <code>DebugeeStdout</code> object.
+ */
+ protected RedirectedStream enwrapLine(String line) {
+ return new DebugeeStdout(line);
+ }
+
+ }
+
+///////// BinderServer's packets //////////
+
+ /**
+ * Base serializable object to transmit request or reply
+ * via <code>BindServer</code> connection.
+ */
+ public static class Packet implements Serializable {}
+
+ ///////// Binder's requests //////////
+
+ /**
+ * Base class to represent request to <code>BindServer</code>.
+ */
+ public static abstract class Request extends Packet {}
+
+ /**
+ * This class implements task identification command.
+ */
+ public static class TaskID extends Request {
+ public String id;
+
+ public TaskID(String id) {
+ this.id = id;
+ }
+
+ public String toString() {
+ return "TaskID: id=" + id;
+ }
+ }
+
+ /**
+ * This class implements a request for launching a debugee.
+ */
+ public static class LaunchDebugee extends Request {
+ public String slash; // slash symbol used on debugger host
+ public String[] cmd; // command line arguments as seen on debugger host
+ public String workDir; // path to working directory as seen on debugger host
+ public String[] classPathes; // list of class pathes as seen on debugger host
+
+ public LaunchDebugee(String[] cmd, String slash, String workDir,
+ String[] pathes, String[] classPathes,
+ String[] libPathes) {
+ this.cmd = cmd;
+ this.slash = slash;
+ this.workDir = workDir;
+ this.classPathes = classPathes;
+ }
+
+ public String toString() {
+ return "LaunchDebugee:"
+ + "\n\tcommand=" + ArgumentParser.joinArguments(cmd, "\"")
+ + "\n\tWORKDIR=" + workDir
+ + "\n\tCLASSPATH=" + ArgumentParser.joinArguments(classPathes, "", ":")
+ + "\n\tslash=" + slash;
+ }
+ }
+
+ /**
+ * This class implements a request for waiting for debugee
+ * termination.
+ */
+ public static class WaitForDebugee extends Request {
+ public long timeout = 0; // timeout in minutes for waiting
+
+ public WaitForDebugee(long value) {
+ timeout = value;
+ }
+
+ public String toString() {
+ return "WaitForDebugee: timeout=" + timeout;
+ }
+ }
+
+ /**
+ * This class implements a request for exit code of
+ * debugee process.
+ */
+ public static class DebugeeExitCode extends Request {
+ public String toString() {
+ return "SebugeeExitCode";
+ }
+ }
+
+ /**
+ * This class implements a request for killing debugee process.
+ */
+ public static class KillDebugee extends Request {
+ public String toString() {
+ return "KillDebugee";
+ }
+ }
+
+ /**
+ * This class implements a request to disconnect connection with test.
+ */
+ public static class Disconnect extends Request {
+ public String toString() {
+ return "Disconnect";
+ }
+ }
+
+ ///////// BindServer's responses //////////
+
+ /**
+ * Base class to represent response from <code>BindServer</code>.
+ */
+ public static abstract class Response extends Packet {}
+
+ /**
+ * This class implements a response that a previoulsy received
+ * request has been successfully performed.
+ */
+ public static class OK extends Response {
+ public long info = BindServer.VERSION; // optional additional info
+
+ public OK() {
+ }
+
+ public OK(long value) {
+ info = value;
+ }
+
+ public String toString() {
+ return "OK(" + info + ")";
+ }
+ }
+
+ /**
+ * This class implements a response that the BindServer is
+ * unable to serve a previoulsy received request.
+ */
+ public static class RequestFailed extends Response {
+ public String reason; // the short explanation of failure
+
+ public RequestFailed(String reason) {
+ this.reason = reason;
+ }
+
+ public String toString() {
+ return "RequestFailed(" + reason + ")";
+ }
+ }
+
+ /**
+ * This class implements a response that the BindServer is
+ * unable to serve a previoulsy received request because of
+ * caught exception.
+ */
+ public static class CaughtException extends RequestFailed {
+ public CaughtException(Exception cause) {
+ super("Caught exception: " + cause);
+ }
+ }
+
+ ///////// Wrappers for redirected messages //////////
+
+ /**
+ * Base class to represent wrappers for redirected streams.
+ */
+ public static class RedirectedStream extends Packet {
+ public String line; // line containing line from redirected stream
+
+ public RedirectedStream(String str) {
+ line = str;
+ }
+
+ public String toString() {
+ return "RedirectedStream(" + line + ")";
+ }
+ }
+
+ /**
+ * This class enwraps redirected line of <i>stdout</i> stream.
+ */
+ public static class DebugeeStdout extends RedirectedStream {
+
+ public DebugeeStdout(String str) {
+ super(str);
+ }
+
+ public String toString() {
+ return "DebugeeStdout(" + line + ")";
+ }
+ }
+
+ /**
+ * This class enwraps redirected line of <i>stderr</i> stream.
+ */
+ public static class DebugeeStderr extends RedirectedStream {
+ public DebugeeStderr(String str) {
+ super(str);
+ }
+
+ public String toString() {
+ return "DebugeeStderr(" + line + ")";
+ }
+ }
+
+/////// ArgumentHandler for BindServer command line /////////
+
+ /**
+ * This class is used to parse arguments from command line
+ * and specified <i>bind-file</i>,
+ */
+ private static class ArgumentHandler extends ArgumentParser {
+
+ protected Properties fileOptions;
+
+ /**
+ * Make parser object for command line arguments.
+ *
+ * @param args list of command line arguments
+ */
+ public ArgumentHandler(String[] args) {
+ super(args);
+ }
+
+ /**
+ * Check if given command line option is aloowed.
+ *
+ * @param option option name
+ * @param value option value
+ */
+ protected boolean checkOption(String option, String value) {
+ if (option.equals("bind.file")) {
+ // accept any file name
+ return true;
+ }
+ return super.checkOption(option, value);
+ }
+
+ /**
+ * Check if all recignized options are compatible.
+ */
+ protected void checkOptions() {
+ if (getBindFileName() == null) {
+ throw new BadOption("Option -bind.file is requred ");
+ }
+ super.checkOptions();
+ }
+
+ /**
+ * Check if value of this option points to a existing directory.
+ *
+ * @param option option name
+ * @param dir option value
+ */
+ private void checkDir(String option, String dir) {
+ File file = new File(dir);
+ if (!file.exists()) {
+ throw new BadOption(option + " does not exist: " + dir);
+ }
+ if (!file.isAbsolute()) {
+ throw new BadOption(option + " is not absolute pathname: " + dir);
+ }
+ if (!file.isDirectory()) {
+ throw new BadOption(option + " is not directory: " + dir);
+ }
+ }
+
+ /**
+ * Check if option from <i>bind-file</i> is allowed.
+ *
+ * @param option option name
+ * @param value option value
+ */
+ protected boolean checkAdditionalOption(String option, String value) {
+
+ if (option.equals("DEBUGGER_HOST")) {
+ // accept any hostname
+ return true;
+ }
+
+ if (option.equals("BINDSERVER_PORT")) {
+ // accept only integer value
+ try {
+ int port = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new Failure("Not integer value of bind-file option " + option
+ + ": " + value);
+ }
+ return true;
+ }
+
+ if (option.equals("DEBUGGER_TESTED_JAVA_HOME")
+ || option.equals("DEBUGGER_WORKDIR")
+ || option.equals("DEBUGGER_TESTBASE")) {
+ if (value == null || value.equals("")) {
+ throw new BadOption("Empty value of bind-file option " + option);
+ }
+ return true;
+ }
+
+ if (option.equals("DEBUGGEE_TESTED_JAVA_HOME")
+ || option.equals("DEBUGGEE_WORKDIR")
+ || option.equals("DEBUGGEE_TESTBASE")) {
+ if (value == null || value.equals("")) {
+ throw new BadOption("Empty value of bind-file option " + option);
+ }
+ checkDir(option, value);
+ return true;
+ }
+
+ if (option.equals("DEBUGGEE_WINDIR")) {
+ if (!(value == null || value.equals(""))) {
+ checkDir(option, value);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if all recignized options form <i>bind-file</i> are compatible.
+ */
+ protected void checkAdditionalOptions() {
+
+ if (getDebuggerJavaHome() == null) {
+ throw new BadOption("Option DEBUGGER_JAVA_HOME missed from bind-file");
+ }
+ if (getDebuggerWorkDir() == null) {
+ throw new BadOption("Option DEBUGGER_WORKDIR missed from bind-file");
+ }
+ if (getDebuggerTestbase() == null) {
+ throw new BadOption("Option DEBUGGER_TESTBASE missed from bind-file");
+ }
+
+ if (getDebugeeJavaHome() == null) {
+ throw new BadOption("Option DEBUGGEE_JAVA_HOME missed from bind-file");
+ }
+ if (getDebugeeWorkDir() == null) {
+ throw new BadOption("Option DEBUGGEE_WORKDIR missed from bind-file");
+ }
+ if (getDebugeeTestbase() == null) {
+ throw new BadOption("Option DEBUGGEE_TESTBASE missed from bind-file");
+ }
+ }
+
+ /**
+ * Parse options form specified <i>bind-file</i>.
+ */
+ protected void parseAdditionalOptions() {
+ Enumeration keys = fileOptions.keys();
+ while (keys.hasMoreElements()) {
+ String option = (String)keys.nextElement();
+ String value = fileOptions.getProperty(option);
+ if (! checkAdditionalOption(option, value)) {
+ throw new BadOption("Unrecognized bind-file option: " + option);
+ }
+ }
+ checkAdditionalOptions();
+ }
+
+ /**
+ * Parse all options from command line and specified <i>bind-file</i>.
+ */
+ protected void parseArguments() {
+ super.parseArguments();
+ String fileName = getBindFileName();
+ try {
+ FileInputStream bindFile = new FileInputStream(fileName);
+ fileOptions = new Properties();
+ fileOptions.load(bindFile);
+ bindFile.close();
+ } catch(FileNotFoundException e) {
+ throw new BadOption("Unable to open bind-file " + fileName + ": " + e);
+ } catch(IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while reading bind-file:\n" + e);
+ }
+ parseAdditionalOptions();
+ }
+
+ /** Return name of specified <i>bind-file<i>. */
+ public String getBindFileName() {
+ return options.getProperty("bind.file");
+ }
+
+ /** Return specified debuggee host name . */
+ public String getDebuggerHost() {
+ return fileOptions.getProperty("DEBUGGER_HOST", "localhost");
+ }
+
+ /** Return string representation of port number for <code>BindServer<code> connection. */
+ public String getBindPort() {
+ return fileOptions.getProperty("BINDSERVER_PORT", "9000");
+ }
+
+ /** Return specified port number for <code>BindServer<code> connection. */
+ public int getBindPortNumber() {
+ try {
+ return Integer.parseInt(getBindPort());
+ } catch (NumberFormatException e) {
+ throw new Failure("Not integer value of BindServer port");
+ }
+ }
+
+ /** Return specified path to tested JDK used for debuggee VM. */
+ public String getDebugeeJavaHome() {
+ return fileOptions.getProperty("DEBUGGEE_TESTED_JAVA_HOME");
+ }
+
+ /** Return specified path to tested JDK used for debugger. */
+ public String getDebuggerJavaHome() {
+ return fileOptions.getProperty("DEBUGGER_TESTED_JAVA_HOME");
+ }
+
+ /** Return specified path to working dir from debuggee host. */
+ public String getDebugeeWorkDir() {
+ return fileOptions.getProperty("DEBUGGEE_WORKDIR");
+ }
+
+ /** Return specified path to working dir from debugger host. */
+ public String getDebuggerWorkDir() {
+ return fileOptions.getProperty("DEBUGGER_WORKDIR");
+ }
+
+ /** Return specified path to testbase dir from debuggee host. */
+ public String getDebugeeTestbase() {
+ return fileOptions.getProperty("DEBUGGEE_TESTBASE");
+ }
+
+ /** Return specified path to testbase dir from debugger host. */
+ public String getDebuggerTestbase() {
+ return fileOptions.getProperty("DEBUGGER_TESTBASE");
+ }
+
+ /** Return specified path to system directory on Wimdows platform. */
+ public String getDebugeeWinDir() {
+ return fileOptions.getProperty("DEBUGGEE_WINDIR");
+ }
+
+ } // ArgumentHandler
+
+} // BindServer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ConversionUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jpda;
+
+/*
+Static methods checking whether given primitive type value can be
+converted to another primitive type without information loss
+
+Note:
+the spec defines following 2 types of primitive values conversions:
+
+Widening primitive conversions (don't loose information, but may lose precision):
+ * byte to short, int, long, float, or double
+ * short to int, long, float, or double
+ * char to int, long, float, or double
+ * int to long, float, or double
+ * long to float or double
+ * float to double
+
+Narrowing primitive conversions (may loose information and may loose precision):
+ * byte to char
+ * short to byte or char
+ * char to byte or short
+ * int to byte, short, or char
+ * long to byte, short, char, or int
+ * float to byte, short, char, int, or long
+ * double to byte, short, char, int, long, or float
+
+Examples:
+ Conversions (int)1234567890 -> (float)1.23456794E9 and (float)1.5 -> (int)1 loose precision.
+ Conversion (byte)-1 -> (char) ffff and (double)Double.MAX_VALUE -> (int)Integer.MAX_VALUE loose information.
+
+(See the "JavaTM Language Specification" section 5.2 for more information
+on assignment compatibility)
+ */
+public class ConversionUtils {
+
+ /*
+ * Methods checking that value can be converted to the value of the
+ * same type (like 'informationLossByteToByte') were added to simplify
+ * clients coding (when this methods exist clients shouldn't handle this case
+ * in a specific way)
+ */
+
+ /*
+ * Byte
+ */
+ public static boolean informationLossByteToByte(Byte value) {
+ return false;
+ }
+
+ public static boolean informationLossByteToShort(Byte value) {
+ return false;
+ }
+
+ public static boolean informationLossByteToChar(Byte value) {
+ return (value.byteValue() > Character.MAX_VALUE) || (value.byteValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossByteToInt(Byte value) {
+ return false;
+ }
+
+ public static boolean informationLossByteToLong(Byte value) {
+ return false;
+ }
+
+ public static boolean informationLossByteToFloat(Byte value) {
+ return false;
+ }
+
+ public static boolean informationLossByteToDouble(Byte value) {
+ return false;
+ }
+
+ /*
+ * Short
+ */
+ public static boolean informationLossShortToShort(Short value) {
+ return false;
+ }
+
+ public static boolean informationLossShortToByte(Short value) {
+ return (value.shortValue() > Byte.MAX_VALUE) || (value.shortValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossShortToChar(Short value) {
+ return (value.shortValue() > Character.MAX_VALUE) || (value.shortValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossShortToInt(Short value) {
+ return false;
+ }
+
+ public static boolean informationLossShortToLong(Short value) {
+ return false;
+ }
+
+ public static boolean informationLossShortToFloat(Short value) {
+ return false;
+ }
+
+ public static boolean informationLossShortToDouble(Short value) {
+ return false;
+ }
+
+ /*
+ * Char
+ */
+ public static boolean informationLossCharToChar(Character value) {
+ return false;
+ }
+
+ public static boolean informationLossCharToByte(Character value) {
+ return (value.charValue() > Byte.MAX_VALUE) || (value.charValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossCharToShort(Character value) {
+ return (value.charValue() > Short.MAX_VALUE) || (value.charValue() < Short.MIN_VALUE);
+ }
+
+ public static boolean informationLossCharToInt(Character value) {
+ return false;
+ }
+
+ public static boolean informationLossCharToLong(Character value) {
+ return false;
+ }
+
+ public static boolean informationLossCharToFloat(Character value) {
+ return false;
+ }
+
+ public static boolean informationLossCharToDouble(Character value) {
+ return false;
+ }
+
+ /*
+ * Integer
+ */
+ public static boolean informationLossIntToInt(Integer value) {
+ return false;
+ }
+
+ public static boolean informationLossIntToByte(Integer value) {
+ return (value.intValue() > Byte.MAX_VALUE) || (value.intValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossIntToShort(Integer value) {
+ return (value.intValue() > Short.MAX_VALUE) || (value.intValue() < Short.MIN_VALUE);
+ }
+
+ public static boolean informationLossIntToChar(Integer value) {
+ return (value.intValue() > Character.MAX_VALUE) || (value.intValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossIntToLong(Integer value) {
+ return false;
+ }
+
+ public static boolean informationLossIntToFloat(Integer value) {
+ return false;
+ }
+
+ public static boolean informationLossIntToDouble(Integer value) {
+ return false;
+ }
+
+ /*
+ * Long
+ */
+ public static boolean informationLossLongToLong(Long value) {
+ return false;
+ }
+
+ public static boolean informationLossLongToByte(Long value) {
+ return (value.longValue() > Byte.MAX_VALUE) || (value.longValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossLongToShort(Long value) {
+ return (value.longValue() > Short.MAX_VALUE) || (value.longValue() < Short.MIN_VALUE);
+ }
+
+ public static boolean informationLossLongToChar(Long value) {
+ return (value.longValue() > Character.MAX_VALUE) || (value.longValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossLongToInt(Long value) {
+ return (value.longValue() > Integer.MAX_VALUE) || (value.longValue() < Integer.MIN_VALUE);
+ }
+
+ public static boolean informationLossLongToFloat(Long value) {
+ return false;
+ }
+
+ public static boolean informationLossLongToDouble(Long value) {
+ return false;
+ }
+
+ /*
+ * Float
+ */
+ public static boolean informationLossFloatToFloat(Float value) {
+ return false;
+ }
+
+ public static boolean informationLossFloatToByte(Float value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.floatValue() > Byte.MAX_VALUE) || (value.floatValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossFloatToShort(Float value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.floatValue() > Short.MAX_VALUE) || (value.floatValue() < Short.MIN_VALUE);
+ }
+
+ public static boolean informationLossFloatToChar(Float value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.floatValue() > Character.MAX_VALUE) || (value.floatValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossFloatToInt(Float value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.floatValue() > Integer.MAX_VALUE) || (value.floatValue() < Integer.MIN_VALUE)
+ || ((int)value.floatValue() != value.floatValue());
+ }
+
+ public static boolean informationLossFloatToLong(Float value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.floatValue() > Long.MAX_VALUE) || (value.floatValue() < Long.MIN_VALUE)
+ || ((long)value.floatValue() != value.floatValue());
+ }
+
+ public static boolean informationLossFloatToDouble(Float value) {
+ return false;
+ }
+
+
+ /*
+ * Double
+ */
+ public static boolean informationLossDoubleToDouble(Double value) {
+ return false;
+ }
+
+ public static boolean informationLossDoubleToByte(Double value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.doubleValue() > Byte.MAX_VALUE) || (value.doubleValue() < Byte.MIN_VALUE);
+ }
+
+ public static boolean informationLossDoubleToShort(Double value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.doubleValue() > Short.MAX_VALUE) || (value.doubleValue() < Short.MIN_VALUE);
+ }
+
+ public static boolean informationLossDoubleToChar(Double value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.doubleValue() > Character.MAX_VALUE) || (value.doubleValue() < Character.MIN_VALUE);
+ }
+
+ public static boolean informationLossDoubleToInt(Double value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.doubleValue() > Integer.MAX_VALUE) || (value.doubleValue() < Integer.MIN_VALUE);
+ }
+
+ public static boolean informationLossDoubleToLong(Double value) {
+ if (value.isInfinite())
+ return true;
+
+ if (value.isNaN())
+ return true;
+
+ return (value.doubleValue() > Long.MAX_VALUE) || (value.doubleValue() < Long.MIN_VALUE)
+ || ((long)value.doubleValue() != value.doubleValue());
+ }
+
+ public static boolean informationLossDoubleToFloat(Double value) {
+ if (value.isInfinite())
+ return false;
+
+ if (value.isNaN())
+ return false;
+
+ float f = (float) value.doubleValue();
+
+ return f != value.doubleValue();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeArgumentHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,828 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import nsk.share.*;
+
+import java.io.*;
+import java.net.ServerSocket;
+
+/**
+ * Parser for JPDA test's launching and connection arguments.
+ * <p>
+ * <Code>DebugeeArgumentHandler</code> handles specific JDI/JDWP/JDB tests
+ * command line arguments related to launching and connection parameters
+ * for debugee VM in addition to general arguments recognized by
+ * <code>ArgumentParser</code>.
+ * <p>
+ * Following is the list of specific options for
+ * <code>DebugeeAgrumentHandler</code>:
+ * <ul>
+ * <li> <code>-test.host=</code><<i>host</i>> -
+ * address of a host where test executes
+ * <li> <code>-debugee.host=</code><<i>host</i>> -
+ * address of a host where debugee VM executes
+ * <li> <code>-connector=[attaching|listening]</code> -
+ * connector type to connect to debugee VM
+ * <li> <code>-transport=[socket|shmem]</code> -
+ * transport type to connect to debugee VM
+ * <li> <code>-transport.port=</code><<i>port</i>> -
+ * port number for <code>socket</code> transport
+ * <li> <code>-transport.shname=</code><<i>name</i>> -
+ * shared memory name for <code>shmem</code> transport
+ * <li> <code>-transport.address=</code><<i>dynamic</i>> -
+ * use dynamically allocated unique transport address for JDWP connection
+ * ignoring settings for <code>-transport.port</code> and <code>-transport.shname</code>
+ * (this works only with <code>-connector=listening</code> and <code>-transport=socket</code>)
+ * <li> <code>-debugee.suspend=[yes|no|default]</code> -
+ * should debugee start in suspend mode or not
+ * <li> <code>-debugee.launch=[local|remote|manual]</code> -
+ * launch and bind to debugee VM locally, remotely (via BindSever) or manually
+ * <li> <code>-debugee.vmhome=</code><<i>path</i>> -
+ * path to JDK used for launching debugee VM
+ * <li> <code>-debugee.vmkind=</code><<i>name</i>> -
+ * name of debugee VM launcher executable
+ * <li> <code>-debugee.vmkeys=</code><<i>string</i>> -
+ * additional options for launching debugee VM
+ * <li> <code>-jvmdi.strict=[yes|no|default]</code> -
+ * using JVMDI strict mode
+ * <li> <code>-pipe.port=</code><<i>port</i>> -
+ * port number for internal IOPipe connection
+ * <li> <code>-bind.port=</code><<i>port</i>> -
+ * port number for BindServer connection
+ * </ul>
+ * <p>
+ * See also list of basic options recognized by
+ * <code>ArgumentParser</code>.
+ * <p>
+ * See also comments to <code>ArgumentParser</code> for list of general
+ * recognized options and how to work with command line arguments and options.
+ *
+ * @see ArgumentParser
+ * @see nsk.share.jdi.ArgumentHandler
+ * @see nsk.share.jdwp.ArgumentHandler
+ */
+public class DebugeeArgumentHandler extends ArgumentParser {
+
+ public static final String DEFAULT_PIPE_PORT = "7123";
+ public static final String DEFAULT_TRANSPORT_PORT = "8123";
+ public static final String DEFAULT_BIND_PORT = "9123";
+
+
+ /**
+ * Keep a copy of raw command-line arguments and parse them;
+ * but throw an exception on parsing error.
+ *
+ * @param args Array of the raw command-line arguments.
+ *
+ * @throws BadOption If unknown option or illegal
+ * option value found
+ *
+ * @see #setRawArguments(String[])
+ */
+ public DebugeeArgumentHandler(String args[]) {
+ super(args);
+ }
+
+ /**
+ * Return name of the host where test executes, specified by
+ * <code>-test.host</code> command line option or
+ * "<i>localhost</i>" string by default.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String getTestHost() {
+ return options.getProperty("test.host", "localhost");
+ }
+
+ /**
+ * Return name of host where the debugee VM is executed, specified by
+ * <code>-debugee.host</code> command line option or value of
+ * getTestHost() by default.
+ *
+ * @see #getTestHost()
+ * @see #setRawArguments(String[])
+ */
+ public String getDebugeeHost() {
+ return options.getProperty("debugee.host", getTestHost());
+ }
+
+ private boolean transportPortInited = false;
+ /**
+ * Return string representation of port number for socket transport,
+ * specified by <code>-tranport.port</code> command line option or
+ * "<code>DEFAULT_TRANSPORT_PORT</code>" string by default.
+ *
+ * @see #getTransportPortIfNotDynamic()
+ * @see #getTransportPortNumber()
+ * @see #setTransportPortNumber(int)
+ * @see #setRawArguments(String[])
+ */
+ synchronized public String getTransportPort() {
+ String port = options.getProperty("transport.port");
+ if (port == null) {
+ if (!transportPortInited) {
+ port = findFreePort();
+ if (port == null) {
+ port = DEFAULT_TRANSPORT_PORT;
+ }
+ options.setProperty("transport.port", port);
+ transportPortInited = true;
+ }
+ }
+ return port;
+ }
+
+ /**
+ * Return string representation of port number for socket transport,
+ * specified by <code>-tranport.port</code> command line option or
+ * "<code>DEFAULT_TRANSPORT_PORT</code>" string by default in case transport address is
+ * not dynamic.
+ * Otherwise null is returned.
+ *
+ * @see #getTransportPort()
+ * @see #getTransportPortNumber()
+ * @see #setTransportPortNumber(int)
+ * @see #setRawArguments(String[])
+ */
+ public String getTransportPortIfNotDynamic() {
+ return ( isTransportAddressDynamic() ?
+ null : getTransportPort() );
+ }
+
+ /**
+ * Return string port number for socket transport,
+ * specified by <code>-debugee.port</code> command line option or
+ * <code>DEFAULT_TRANSPORT_PORT</code> port number by default.
+ *
+ * @see #getTransportPort()
+ * @see #getTransportPortIfNotDynamic()
+ * @see #setTransportPortNumber(int)
+ * @see #setRawArguments(String[])
+ */
+ public int getTransportPortNumber() {
+ String value = getTransportPort();
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not integer value of \"-transport.port\" argument: " + value);
+ }
+ }
+
+ /**
+ * Add or replace value of option <code>-transport.port</code> in options list
+ * with the specified port number.
+ *
+ * @see #getTransportPortNumber()
+ * @see #setRawArguments(String[])
+ */
+ public void setTransportPortNumber(int port) {
+ String value = Integer.toString(port);
+ setOption("-", "transport.port", value);
+ }
+
+ /**
+ * Return shared name for shmem transport, specified by
+ * <code>-transport.shname</code> command line option, or
+ * "<i>nskjpdatestchannel</i>" + a process unique string by default.
+ *
+ * @see #setTransportSharedName(String)
+ * @see #setRawArguments(String[])
+ */
+ // Use a unique id for this process by default. This makes sure that
+ // tests running concurrently do not use the same shared name.
+ private static String defaultTransportSharedName
+ = "nskjpdatestchannel" + ProcessHandle.current().pid();
+ public String getTransportSharedName() {
+ return options.getProperty("transport.shname", defaultTransportSharedName);
+ }
+
+ /**
+ * Add or replace value of option <code>-transport.shname</code> in options list
+ * with the specified name.
+ *
+ * @see #getTransportSharedName()
+ * @see #setRawArguments(String[])
+ */
+ public void setTransportSharedName(String name) {
+ setOption("-", "transport.shname", name);
+ }
+
+ /**
+ * Return <i>true</i> if <code>-transport.address=dynamic</code> command line option
+ * is specified.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public boolean isTransportAddressDynamic() {
+ String value = options.getProperty("transport.address", null);
+ if (value != null && value.equals("dynamic"))
+ return true;
+ return false;
+ }
+
+ /**
+ * Return suspend mode for launching debugee VM, specified by
+ * <code>-debugee.suspend</code> command line option, or
+ * "<i>default</i>" string by default.
+ *
+ * @see #isDefaultDebugeeSuspendMode()
+ * @see #willDebugeeSuspended()
+ * @see #setRawArguments(String[])
+ */
+ public String getDebugeeSuspendMode() {
+ return options.getProperty("debugee.suspend", "default");
+ }
+
+ /**
+ * Return <i>true</i> if default suspend mode is used
+ * for launching debugee VM.
+ *
+ * @see #getDebugeeSuspendMode()
+ * @see #willDebugeeSuspended()
+ */
+ public boolean isDefaultDebugeeSuspendMode() {
+ String mode = getDebugeeSuspendMode();
+ return mode.equals("default");
+ }
+
+ /**
+ * Return <i>true</i> if debugee VM will be suspended after launching,
+ * either according to specified suspend mode or by default.
+ *
+ * @see #getDebugeeSuspendMode()
+ * @see #isDefaultDebugeeSuspendMode()
+ */
+ public boolean willDebugeeSuspended() {
+ if (isLaunchedLocally()) {
+ String mode = getDebugeeSuspendMode();
+ return mode.equals("no");
+ }
+ return true;
+ }
+
+ private boolean pipePortInited = false;
+ /**
+ * Return string representation of the port number for IOPipe connection,
+ * specified by <code>-pipe.port</code> command line option, or
+ * "<i>DEFAULT_PIPE_PORT</i>" string by default.
+ *
+ * @see #getPipePortNumber()
+ * @see #setPipePortNumber(int)
+ * @see #setRawArguments(String[])
+ */
+ synchronized public String getPipePort() {
+ String port = options.getProperty("pipe.port");
+ if (port == null) {
+ if (!pipePortInited) {
+ port = findFreePort();
+ if (port == null) {
+ port = DEFAULT_PIPE_PORT;
+ }
+ pipePortInited = true;
+ options.setProperty("pipe.port", port);
+ }
+ }
+ return port;
+ }
+
+ /**
+ * Return port number for IOPipe connection,
+ * specified by <code>-pipe.port</code> command line option, or
+ * <i>DEFAULT_PIPE_PORT</i> port number by default.
+ *
+ * @see #getPipePort()
+ * @see #setPipePortNumber(int)
+ * @see #setRawArguments(String[])
+ */
+ public int getPipePortNumber() {
+ String value = getPipePort();
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not integer value of \"-pipe.port\" argument: " + value);
+ }
+ }
+
+ /**
+ * Add or replace value of option <code>-pipe.port</code> in options list
+ * with the specified port number.
+ *
+ * @see #getPipePortNumber()
+ * @see #setRawArguments(String[])
+ */
+ public void setPipePortNumber(int port) {
+ String value = Integer.toString(port);
+ setOption("-", "pipe.port", value);
+ }
+
+ /**
+ * Return debugee VM launching mode, specified by
+ * <code>-launch.mode</code> command line option, or
+ * "<i>local</i>" string by default.
+ *
+ * Possible values for this option are:
+ * <ul>
+ * <li> "<code>local</code>"
+ * <li> "<code>remote</code>"
+ * <li> "<code>manual</code>"
+ * </ul>
+ *
+ * @see #isLaunchedLocally()
+ * @see #isLaunchedRemotely()
+ * @see #isLaunchedManually()
+ * @see #setRawArguments(String[])
+ */
+ public String getLaunchMode() {
+ return options.getProperty("debugee.launch", "local");
+ }
+
+ /**
+ * Return <i>true</i> if debugee should be launched locally.
+ *
+ * @see #getLaunchMode()
+ */
+ public boolean isLaunchedLocally() {
+ return getLaunchMode().equals("local");
+ }
+
+ /**
+ * Return <i>true</i> if debugee should be launched remotely via
+ * BindServer.
+ *
+ * @see #getLaunchMode()
+ */
+ public boolean isLaunchedRemotely() {
+ return getLaunchMode().equals("remote");
+ }
+
+ /**
+ * Return <i>true</i> if debugee should be launched manually by user.
+ *
+ * @see #getLaunchMode()
+ */
+ public boolean isLaunchedManually() {
+ return getLaunchMode().equals("manual");
+ }
+
+ /**
+ * Return additional options for launching debugee VM, specified by
+ * <code>-launch.options</code> command line option, or
+ * empty string by default.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String getLaunchOptions() {
+ String result = options.getProperty("debugee.vmkeys", "").trim();
+ if (result.startsWith("\"") && result.endsWith("\"")) {
+ result = result.substring(1, result.length() - 1);
+ }
+ return result;
+ }
+
+ /**
+ * Return name of debugee VM launcher executable, specified by
+ * <code>-launch.vmexec</code> command line option, or
+ * "<i>java</i>" string by default.
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String getLaunchExecName() {
+ return options.getProperty("debugee.vmkind", "java");
+ }
+
+ /**
+ * Return full path to debugee VM launcher executable.
+ *
+ * @see #getLaunchExecName()
+ * @see #getLaunchExecPath(String)
+ * @see #getDebugeeJavaHome()
+ */
+ public String getLaunchExecPath() {
+ String java_home = getDebugeeJavaHome();
+ return getLaunchExecPath(java_home);
+ }
+
+ /**
+ * Return full path to VM launcher executable using givet JAVA_HOME path.
+ *
+ * @see #getLaunchExecName()
+ */
+ public String getLaunchExecPath(String java_home) {
+ String filesep = System.getProperty("file.separator");
+ return java_home + filesep + "bin" + filesep + getLaunchExecName();
+ }
+
+ /**
+ * Return full JAVA_HOME path for debugee VM.
+ *
+ * @see #getLaunchExecName()
+ */
+ public String getDebugeeJavaHome() {
+ String java_home = System.getProperty("java.home");
+ return options.getProperty("debugee.vmhome", java_home);
+ }
+
+ /**
+ * Return true if default debuggee VM launcher executable is used.
+ *
+ * @see #getLaunchExecName()
+ */
+ public boolean isDefaultLaunchExecName() {
+ String vmkind = options.getProperty("debugee.vmkind", null);
+ return (vmkind == null);
+ }
+
+ /**
+ * Return true if default JAVA_HOME path for debuggee VM is used.
+ *
+ * @see #getDebugeeJavaHome()
+ */
+ public boolean isDefaultDebugeeJavaHome() {
+ String java_home = options.getProperty("debugee.vmhome", null);
+ return (java_home == null);
+ }
+
+ private boolean bindPortInited = false;
+ /**
+ * Return string representation of the port number for BindServer connection,
+ * specified by <code>-bind.port</code> command line option, or
+ * "<i>DEFAULT_BIND_PORT</i>" string by default.
+ *
+ * @see #getBindPortNumber()
+ * @see #setRawArguments(String[])
+ */
+ public String getBindPort() {
+ String port = options.getProperty("bind.port");
+ if (port == null) {
+ if (!bindPortInited) {
+ port = findFreePort();
+ if (port == null) {
+ port = DEFAULT_BIND_PORT;
+ }
+ options.setProperty("bind.port", port);
+ bindPortInited = true;
+ }
+ }
+ return port;
+ }
+
+ /**
+ * Return port number for BindServer connection,
+ * specified by <code>-bind.port</code> command line option, or
+ * "<i>DEFAULT_BIND_PORT</i>" port number by default.
+ *
+ * @see #getBindPort()
+ * @see #setRawArguments(String[])
+ */
+ public int getBindPortNumber() {
+ String value = getBindPort();
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new TestBug("Not integer value of \"bind.port\" argument: " + value);
+ }
+ }
+
+ /**
+ * Return JVMDI strict mode for launching debugee VM, specified by.
+ * <code>-jvmdi.strict</code> command line option, or
+ * "<i>default</i>" string by default.
+ *
+ * Possible values for this option are:
+ * <ul>
+ * <li> "<code>yes</code>"
+ * <li> "<code>no</code>"
+ * <li> "<code>default</code>"
+ * </ul>
+ *
+ * @see #setRawArguments(String[])
+ */
+ public String getJVMDIStrictMode() {
+ return options.getProperty("jvmdi.strict", "default");
+ }
+
+ /**
+ * Return <i>true</i> if JVMDI strict mode for launching debugeeVM is used^
+ * either by specifying in command line or by default.
+ *
+ * @see #getJVMDIStrictMode()
+ * @see #isDefaultJVMDIStrictMode()
+ * @see #setRawArguments(String[])
+ */
+ public boolean isJVMDIStrictMode() {
+ String mode = getJVMDIStrictMode();
+ return mode.equals("yes");
+ }
+
+ /**
+ * Return <i>true</i> if JVMDI default strict mode for launching debugee VM is used.
+ *
+ * @see #getJVMDIStrictMode()
+ * @see #isJVMDIStrictMode()
+ * @see #setRawArguments(String[])
+ */
+ public boolean isDefaultJVMDIStrictMode() {
+ String mode = getJVMDIStrictMode();
+ return mode.equals("default");
+ }
+
+ /**
+ * Return type of JDI connector used for connecting to debugee VM, specified by
+ * <code>-connector</code> command line option, or
+ * "<i>listening</i>" string by default.
+ *
+ * Possible values for this option are:
+ * <ul>
+ * <li> "<code>attaching</code>"
+ * <li> "<code>listening</code>"
+ * </ul>
+ *
+ * @see #isAttachingConnector()
+ * @see #isListeningConnector()
+ * @see #setRawArguments(String[])
+ */
+ public String getConnectorType() {
+ return options.getProperty("connector", "listening");
+ }
+
+ /**
+ * Return <i>true</i> if type of the used JDI connector is <code>attaching</code>.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isAttachingConnector() {
+ return getConnectorType().equals("attaching");
+ }
+
+ /**
+ * Return <i>true</i> if type of the used JDI connector is <code>listening</code>.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isListeningConnector() {
+ return getConnectorType().equals("listening");
+ }
+
+ /**
+ * Return <i>true</i> if connector type is not actually specified.
+ * In this case getConnectorType() returns some default connector type.
+ *
+ * @see #getConnectorType()
+ */
+ public boolean isDefaultConnector() {
+ return options.getProperty("connector") == null;
+ }
+
+ /**
+ * Return type of JDWP transport for connecting to debugee VM, specified by
+ * <code>-transport</code> command line option, or
+ * "<i>socket</i>" string by default.
+ *
+ * Possible values for this option are:
+ * <ul>
+ * <li> "<code>socket</code>"
+ * <li> "<code>shmem</code>"
+ * </ul>
+ *
+ * @see #getTransportName()
+ * @see #isSocketTransport()
+ * @see #isShmemTransport()
+ * @see #setRawArguments(String[])
+ */
+ public String getTransportType() {
+ return options.getProperty("transport", "socket");
+ }
+
+ /**
+ * Return transport name corresponding to the used JDWP transport type.
+ *
+ * @see #getTransportType()
+ */
+ public String getTransportName() {
+ if (isSocketTransport()) {
+ return "dt_socket";
+ } else if (isShmemTransport()) {
+ return "dt_shmem";
+ } else {
+ throw new TestBug("Undefined transport type");
+ }
+ }
+
+ /**
+ * Return <i>true</i> if the used JDWP transport type is <code>socket</code>,
+ * either by specifying in command line or as a platform default transport.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isSocketTransport() {
+ String transport = getTransportType();
+ return transport.equals("socket");
+ }
+
+ /**
+ * Return <i>true</i> if the used JDWP transport type is <code>shmem</code>,
+ * either by specifying in command line or as a platform default transport.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isShmemTransport() {
+ String transport = getTransportType();
+ return transport.equals("shmem");
+ }
+
+ /**
+ * Return <i>true</i> if transport type is not actually specified.
+ * In this case getTransportType() returns some default transport kind.
+ *
+ * @see #getTransportType()
+ */
+ public boolean isDefaultTransport() {
+ return options.getProperty("transport") == null;
+ }
+
+ /**
+ * Create <code>Log</code> for debugee application using command line options.
+ */
+ public Log createDebugeeLog() {
+ return new Log(System.err, this);
+ };
+
+ /**
+ * Create IOPipe for debugee application using command line options.
+ */
+ public IOPipe createDebugeeIOPipe() {
+ return createDebugeeIOPipe(createDebugeeLog());
+ };
+
+ /**
+ * Create IOPipe for debugee application using connection
+ * parameters from the command line and specify Log.
+ */
+ public IOPipe createDebugeeIOPipe(Log log) {
+ return new IOPipe(this, log);
+ };
+
+ /**
+ * Check if an option is aloowed and has proper value.
+ * This method is invoked by <code>parseArgumentss()</code>
+ *
+ * @param option option name
+ * @param value string representation of value
+ * (could be an empty string too)
+ * null if this option has no value
+ * @return <i>true</i> if option is allowed and has proper value
+ * <i>false</i> if otion is not admissible
+ *
+ * @throws <i>BadOption</i> if option has an illegal value
+ *
+ * @see #parseArguments()
+ */
+ protected boolean checkOption(String option, String value) {
+
+ if(option.equals("traceAll"))
+ return true;
+
+ // option with any string value
+ if (option.equals("debugee.vmkeys")) {
+ return true;
+ }
+
+ // option with any nonempty string value
+ if (option.equals("test.host")
+ || option.equals("debugee.host")
+ || option.equals("debugee.vmkind")
+ || option.equals("debugee.vmhome")
+ || option.equals("transport.shname")) {
+ if (value.length() <= 0) {
+ throw new BadOption(option + ": cannot be an empty string");
+ }
+ return true;
+ }
+
+ // option with positive integer port value
+ if (option.equals("transport.port")
+ || option.equals("bind.port")
+ || option.equals("pipe.port")) {
+ try {
+ int number = Integer.parseInt(value);
+ if (number < 0) {
+ throw new BadOption(option + ": must be a positive integer");
+ }
+ } catch (NumberFormatException e) {
+ throw new BadOption(option + ": must be an integer");
+ }
+ return true;
+ }
+
+ // options with enumerated values
+
+ if (option.equals("debugee.suspend")) {
+ if ((!value.equals("yes"))
+ && (!value.equals("no"))
+ && (!value.equals("default"))) {
+ throw new BadOption(option + ": must be one of: "
+ + "yes, no, default");
+ }
+ return true;
+ }
+
+ if (option.equals("debugee.launch")) {
+ if ((!value.equals("local"))
+ && (!value.equals("remote"))
+ && (!value.equals("manual"))) {
+ throw new BadOption(option + ": must be one of: "
+ + "local, remote, manual " + value);
+ }
+ return true;
+ }
+
+ if (option.equals("jvmdi.strict")) {
+ if ((!value.equals("yes"))
+ && (!value.equals("no"))
+ && (!value.equals("default"))) {
+ throw new BadOption(option + ": must be one of: "
+ + "yes, no, default");
+ }
+ return true;
+ }
+
+ if (option.equals("transport")) {
+ if ((!value.equals("socket"))
+ && (!value.equals("shmem"))) {
+ throw new BadOption(option + ": must be one of: "
+ + "socket, shmem");
+ }
+ return true;
+ }
+
+ if (option.equals("connector")) {
+ if ((!value.equals("attaching"))
+ && (!value.equals("listening"))) {
+ throw new BadOption(option + ": value must be one of: "
+ + "attaching, listening");
+ }
+ return true;
+ }
+
+ if (option.equals("transport.address")) {
+ if (!value.equals("dynamic")) {
+ throw new BadOption(option + ": must be only: "
+ + "dynamic");
+ }
+ return true;
+ }
+
+ return super.checkOption(option, value);
+ }
+
+ /**
+ * Check if the values of all options are consistent.
+ * This method is invoked by <code>parseArguments()</code>
+ *
+ * @throws <i>BadOption</i> if options have inconsistent values
+ *
+ * @see #parseArguments()
+ */
+ protected void checkOptions() {
+ super.checkOptions();
+ }
+
+ private String findFreePort() {
+ ServerSocket ss = null;
+ try {
+ ss = new ServerSocket(0);
+ return String.valueOf(ss.getLocalPort());
+ } catch (IOException e) {
+ return null;
+ } finally {
+ try {
+ ss.close();
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+
+} // DebugeeArgumentHandler
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeBinder.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import nsk.share.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * This class provides debugger with ability to launch
+ * debuggee VM and to make connection to it using JDI connector or
+ * JDWP transport.
+ * <p>
+ * The present version of <code>Binder</code> allows
+ * to launch debuggee VM either on local machine (<i>local</i> launch mode),
+ * or on remote host using <code>BindServer</code> utility
+ * (<i>remote</i> launch mode). Also there is an ability to launch
+ * debuggee VM manually as a separate process on local or remote machine
+ * (<i>manual</i> launch mode), which is usefull for debugging.
+ * All these launching modes are specified by command line option
+ * <code>-debugee.launch</code> recognized by <code>DebugeeArgumentHandler</code>.
+ * <p>
+ * <code>Binder</code> also makes it possible to establish TCP/IP
+ * connection between debugger and debuggee throw <code>IOPipe</code>
+ * object. This connection allows debugger to communicate with debuggee
+ * by exchanging with synchronization messages and data.
+ * <p>
+ * To launch debuggee VM and bind to it use <code>bindToDebugee()</code>
+ * method. This method construct mirror of debugee VM, represented by
+ * object of <code>DebugeeProcess</code> class or derived. This mirror object
+ * allows to control debuggee VM.
+ * <p>
+ * See also <code>nsk.share.jdi.Binder</code> and <code>nsk.share.jdwp.Binder</code>
+ * classes which provide launching and binding to debuggee VM using specific
+ * JDI and JDWP features.
+ *
+ * @see DebugeeArgumentHandler
+ * @see DebugeeProcess
+ * @see IOPipe
+ * @see BindServer
+ *
+ * @see nsk.share.jdi.Binder
+ * @see nsk.share.jdwp.Binder
+ */
+public class DebugeeBinder extends Log.Logger implements Finalizable {
+
+ private static final boolean IS_WINDOWS = System.getProperty("os.name")
+ .toLowerCase()
+ .startsWith("win");
+
+ public static int TRY_DELAY = 1000; // milliseconds
+
+ public static int CONNECT_TIMEOUT = 1 * 60 * 1000; // milliseconds
+ public static int CONNECT_TRY_DELAY = 2 * 1000; // milliseconds
+ public static int CONNECT_TRIES = CONNECT_TIMEOUT / CONNECT_TRY_DELAY;
+
+ public static int THREAD_TIMEOUT = 2 * CONNECT_TRY_DELAY; // milliseconds
+ public static int PING_TIMEOUT = 30 * 1000; // milliseconds
+
+ public static int SOCKET_TIMEOUT = 2 * 1000; // milliseconds
+ public static int SOCKET_LINGER = 1; // milliseconds
+
+ private static int TRACE_LEVEL_PACKETS = 10;
+ private static int TRACE_LEVEL_THREADS = 20;
+ private static int TRACE_LEVEL_ACTIONS = 30;
+ private static int TRACE_LEVEL_SOCKETS = 40;
+ private static int TRACE_LEVEL_IO = 50;
+
+ /**
+ * Default message prefix for <code>Binder</code> object.
+ */
+ public static final String LOG_PREFIX = "binder> ";
+
+ private DebugeeArgumentHandler argumentHandler = null;
+
+ /**
+ * Get version string.
+ */
+ public static String getVersion () {
+ return "@(#)Binder.java %I% %E%";
+ }
+
+ // -------------------------------------------------- //
+
+ private BindServerListener bindServerListener = null;
+ private ServerSocket pipeServerSocket = null;
+
+ // -------------------------------------------------- //
+
+ /**
+ * Incarnate new Binder obeying the given
+ * <code>argumentHandler</code>; and assign the given
+ * <code>log</code>.
+ */
+ public DebugeeBinder (DebugeeArgumentHandler argumentHandler, Log log) {
+ super(log, LOG_PREFIX);
+ this.argumentHandler = argumentHandler;
+ Finalizer finalizer = new Finalizer(this);
+ finalizer.activate();
+ }
+
+ /**
+ * Get argument handler of this binder object.
+ */
+ DebugeeArgumentHandler getArgumentHandler() {
+ return argumentHandler;
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Wait for given thread finished for THREAD_TIMEOUT timeout and
+ * interrupt this thread if not finished.
+ *
+ * @param thr thread to wait for
+ * @param logger to write log messages to
+ */
+ public static void waitForThread(Thread thr, Log.Logger logger) {
+ waitForThread(thr, THREAD_TIMEOUT, logger);
+ }
+
+ /**
+ * Wait for given thread finished for specified timeout and
+ * interrupt this thread if not finished.
+ *
+ * @param thr thread to wait for
+ * @param millisecs timeout in milliseconds
+ * @param logger to write log messages to
+ */
+ public static void waitForThread(Thread thr, long millisecs, Log.Logger logger) {
+ if (thr != null) {
+ if (thr.isAlive()) {
+ try {
+ logger.trace(TRACE_LEVEL_THREADS, "Waiting for thread: " + thr.getName());
+ thr.join(millisecs);
+ } catch (InterruptedException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure ("Thread interrupted while waiting for another thread:\n\t"
+ + e);
+ } finally {
+ if (thr.isAlive()) {
+ logger.trace(TRACE_LEVEL_THREADS, "Interrupting not finished thread: " + thr);
+ thr.interrupt();
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Make preperation for IOPipe connection before starting debugee VM process.
+ * May change options in the passed <code>argumentHandler</code>.
+ */
+ protected void prepareForPipeConnection(DebugeeArgumentHandler argumentHandler) {
+ if (argumentHandler.isTransportAddressDynamic()) {
+ try {
+ pipeServerSocket = new ServerSocket();
+ pipeServerSocket.setReuseAddress(false);
+ pipeServerSocket.bind(null);
+
+ } catch (IOException e) {
+ e.printStackTrace(getOutStream());
+ throw new Failure("Caught IOException while binding for IOPipe connection: \n\t"
+ + e);
+ }
+
+ int port = pipeServerSocket.getLocalPort();
+ argumentHandler.setPipePortNumber(port);
+ }
+ }
+
+ /**
+ * Return already bound ServerSocket for IOPipe connection or null.
+ */
+ protected ServerSocket getPipeServerSocket() {
+ return pipeServerSocket;
+ }
+
+ /**
+ * Close ServerSocket used for IOPipeConnection if any.
+ */
+ private void closePipeServerSocket() {
+ if (pipeServerSocket != null) {
+ try {
+ pipeServerSocket.close();
+ } catch (IOException e) {
+ println("# WARNING: Caught IOException while closing ServerSocket used for IOPipe connection: \n\t"
+ + e);
+ }
+ }
+ }
+
+ // -------------------------------------------------- //
+
+ /**
+ * Make environment for launching JVM process.
+ */
+ public String[] makeProcessEnvironment() {
+/*
+ String env = new String[0];
+ return env;
+ */
+ return null;
+ }
+
+ /**
+ * Launch process by the specified command line.
+ *
+ * @throws IOException if I/O error occured while launching process
+ */
+ public Process launchProcess(String cmdLine) throws IOException {
+ String env[] = makeProcessEnvironment();
+ return Runtime.getRuntime().exec(cmdLine, env);
+ }
+
+ /**
+ * Launch process by the arguments array.
+ *
+ * @throws IOException if I/O error occured while launching process
+ */
+ public Process launchProcess(String[] args) throws IOException {
+ String env[] = makeProcessEnvironment();
+ return Runtime.getRuntime().exec(args, env);
+ }
+
+ /**
+ * Make string representation of debuggee VM transport address according
+ * to current command line options.
+ */
+ public String makeTransportAddress() {
+ String address = null;
+ if (argumentHandler.isSocketTransport()) {
+ if (argumentHandler.isListeningConnector()) {
+ address = argumentHandler.getTestHost()
+ + ":" + argumentHandler.getTransportPort();
+ } else {
+ address = argumentHandler.getTransportPort();
+ }
+ } else if (argumentHandler.isShmemTransport() ) {
+ address = argumentHandler.getTransportSharedName();
+ } else {
+ throw new TestBug("Undefined transport type: "
+ + argumentHandler.getTransportType());
+ }
+ return address;
+ }
+
+ /**
+ * Make command line to launch debugee VM as a string using given quote symbol,
+ * using specified <code>transportAddress</code> for JDWP connection.
+ */
+ public String makeCommandLineString(String classToExecute, String transportAddress, String quote) {
+ String[] args = makeCommandLineArgs(classToExecute, transportAddress);
+ return ArgumentParser.joinArguments(args, quote);
+ }
+
+ /**
+ * Make command line to launch debugee VM as a string using given quote symbol.
+ */
+ public String makeCommandLineString(String classToExecute, String quote) {
+ return makeCommandLineString(classToExecute, makeTransportAddress(), quote);
+ }
+
+ /**
+ * Make command line to launch debugee VM as a string using default quote symbol,
+ * using specified <code>transportAddress</code> for JDWP connection.
+ */
+/*
+ public String makeCommandLineString(String classToExecute, String transportAddress) {
+ return makeCommandLineString(classToExecute, transportAddress, "\"");
+ }
+ */
+
+ /**
+ * Make command line to launch debugee VM as a string using default quote symbol.
+ */
+/*
+ public String makeCommandLineString(String classToExecute) {
+ return makeCommandLineString(classToExecute, makeTransportAddress());
+ }
+ */
+
+ /**
+ * Make command line to launch debugee VM as an array of arguments,
+ * using specified <code>transportAddress</code> for JDWP connection.
+ */
+ public String[] makeCommandLineArgs(String classToExecute, String transportAddress) {
+ Vector<String> args = new Vector<String>();
+
+ args.add(argumentHandler.getLaunchExecPath());
+
+ String javaOpts = argumentHandler.getLaunchOptions();
+ if (javaOpts != null && javaOpts.length() > 0) {
+ StringTokenizer st = new StringTokenizer(javaOpts);
+
+ while (st.hasMoreTokens()) {
+ args.add(st.nextToken());
+ }
+ }
+
+/*
+ String classPath = System.getProperty("java.class.path");
+ args.add("-classpath")
+ args.add(classPath);
+ */
+
+ args.add("-Xdebug");
+
+ String server;
+ if (argumentHandler.isAttachingConnector()) {
+ server = "y";
+ } else {
+ server = "n";
+ }
+
+ String jdwpArgs = "-Xrunjdwp:"
+ + "server=" + server
+ + ",transport=" + argumentHandler.getTransportName()
+ + ",address=" + transportAddress;
+
+ if (! argumentHandler.isDefaultJVMDIStrictMode()) {
+ if (argumentHandler.isJVMDIStrictMode())
+ jdwpArgs += ",strict=y";
+ else
+ jdwpArgs += ",strict=n";
+ }
+
+ args.add(jdwpArgs);
+
+ if (classToExecute != null) {
+ StringTokenizer st = new StringTokenizer(classToExecute);
+
+ while (st.hasMoreTokens()) {
+ args.add(st.nextToken());
+ }
+ }
+
+ String[] rawArgs = argumentHandler.getRawArguments();
+ for (int i = 0; i < rawArgs.length; i++) {
+ String rawArg = rawArgs[i];
+ // " has to be escaped on windows
+ if (IS_WINDOWS) {
+ rawArg = rawArg.replace("\"", "\\\"");
+ }
+ args.add(rawArg);
+ }
+
+ String[] argsArray = new String[args.size()];
+ for (int i = 0; i < args.size(); i++) {
+ argsArray[i] = (String) args.elementAt(i);
+ }
+
+ return argsArray;
+ }
+
+ /**
+ * Make command line to launch debugee VM as an array of arguments.
+ */
+ public String[] makeCommandLineArgs(String classToExecute) {
+ return makeCommandLineArgs(classToExecute, makeTransportAddress());
+ }
+
+ /**
+ * Make connection to remote BindServer and start BindServerListener thread.
+ *
+ * @throws IOException if I/O error occured while connecting
+ */
+ public void connectToBindServer(String taskID) {
+ if (bindServerListener != null) {
+ throw new Failure("Connection to BindServer already exists");
+ }
+ try {
+ bindServerListener = new BindServerListener(this);
+ bindServerListener.setDaemon(true);
+ bindServerListener.connect(taskID);
+ bindServerListener.start();
+ } catch (IOException e) {
+ e.printStackTrace(getOutStream());
+ throw new Failure("Caught exception while connecting to BindServer:\n\t" + e);
+ }
+ }
+
+ /**
+ * Split string into list of substrings using specified separator.
+ */
+ private static String[] splitString(String givenString, String separator) {
+ Vector<String> tmpList = new Vector<String>();
+ StringTokenizer tokenizer = new StringTokenizer(givenString, separator);
+ while(tokenizer.hasMoreTokens()) {
+ tmpList.add(tokenizer.nextToken());
+ }
+ String[] list = new String[tmpList.size()];
+ for (int i = 0; i < tmpList.size(); i++) {
+ list[i] = tmpList.elementAt(i);
+ }
+ return list;
+ }
+
+ /**
+ * Send command to remote <code>BindServer</code> and receive reply.
+ *
+ * @throws IOException if I/O error occured while launching process
+ */
+ public synchronized Object sendRemoteCommand(Object command) {
+ try {
+ bindServerListener.sendCommand(command);
+ Object reply = bindServerListener.getReply();
+ return reply;
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Unexpected exception while sending command to BindServer:\n\t"
+ + e);
+ }
+ }
+
+ /**
+ * Launch remote process using request to <code>BindServer</code>.
+ *
+ * @throws IOException if I/O error occured
+ */
+ public void launchRemoteProcess(String[] args) throws IOException {
+ String pathSeparator = System.getProperty("path.separator");
+ BindServer.LaunchDebugee command =
+ new BindServer.LaunchDebugee(args,
+ System.getProperty("file.separator"),
+ System.getProperty("user.dir"),
+ splitString(System.getProperty("java.library.path"), pathSeparator),
+ splitString(System.getProperty("java.class.path"), pathSeparator),
+ splitString(System.getProperty("java.library.path"), pathSeparator));
+
+ Object reply = sendRemoteCommand(command);
+ if (reply instanceof BindServer.OK) {
+ // do nothing
+ } else if (reply instanceof BindServer.RequestFailed) {
+ BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
+ throw new Failure("BindServer error: " + castedReply.reason);
+ } else {
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+ }
+
+ /**
+ * Return exit status of the remotely launched process
+ * using request to <code>BindServer</code>.
+ */
+ public int getRemoteProcessStatus () {
+ Object reply = sendRemoteCommand(new BindServer.DebugeeExitCode());
+ if (reply instanceof BindServer.OK) {
+ BindServer.OK castedReply = (BindServer.OK)reply;
+ return (int)castedReply.info;
+ } else if (reply instanceof BindServer.CaughtException) {
+ BindServer.CaughtException castedReply = (BindServer.CaughtException)reply;
+ throw new IllegalThreadStateException(castedReply.reason);
+ } else if (reply instanceof BindServer.RequestFailed) {
+ BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
+ throw new Failure("BindServer error: " + castedReply.reason);
+ } else {
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+ }
+
+ /**
+ * Check whether the remotely launched process has been terminated
+ * using request to <code>BindServer</code>.
+ */
+ public boolean isRemoteProcessTerminated () {
+ try {
+ int value = getRemoteProcessStatus();
+ return true;
+ } catch (IllegalThreadStateException e) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------- //
+
+ /**
+ * Kill the remotely launched process
+ * using request to <code>BindServer</code>.
+ */
+ public void killRemoteProcess () {
+ Object reply = sendRemoteCommand(new BindServer.KillDebugee());
+ if (reply instanceof BindServer.OK) {
+ return;
+ } else if (reply instanceof BindServer.RequestFailed) {
+ BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
+ throw new Failure("BindServer error: " + castedReply.reason);
+ } else {
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+ }
+
+ /**
+ * Wait until the remotely launched process exits or crashes
+ * using request to <code>BindServer</code>.
+ */
+ public int waitForRemoteProcess () {
+
+ Object reply = sendRemoteCommand(new BindServer.WaitForDebugee(0));
+ if (reply instanceof BindServer.OK) {
+ BindServer.OK castedReply = (BindServer.OK)reply;
+ return (int)castedReply.info;
+ } else if (reply instanceof BindServer.RequestFailed) {
+ BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
+ throw new Failure("BindServer error: " + castedReply.reason);
+ } else {
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+ }
+
+ /**
+ * Close binder by closing all started threads.
+ */
+ public void close() {
+ if (bindServerListener != null) {
+ bindServerListener.close();
+ }
+ closePipeServerSocket();
+ }
+
+ /**
+ * Finalize binder by invoking <code>close()</code>.
+ *
+ * @throws Throwable if any throwable exception is thrown during finalization
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ /**
+ * Finalize binder at exit by invoking <code>finalize()</code>.
+ *
+ * @throws Throwable if any throwable exception is thrown during finalization
+ */
+ public void finalizeAtExit() throws Throwable {
+ finalize();
+ }
+
+ /**
+ * Separate thread for listening connection from <code>BindServer</code>.
+ */
+ private class BindServerListener extends Thread {
+ private SocketConnection connection = null;
+ private Log.Logger logger = null;
+
+ /** List of received responses from <code>BindServer</code>. */
+ private LinkedList<BindServer.Response> replies = new LinkedList<BindServer.Response>();
+
+ /**
+ * Make thread.
+ */
+ public BindServerListener(Log.Logger logger) {
+ this.logger = logger;
+ }
+
+ /**
+ * Establish connection to <code>BindServer</code>.
+ */
+ public void connect(String taskID) throws IOException {
+ String host = argumentHandler.getDebugeeHost();
+ int port = argumentHandler.getBindPortNumber();
+ display("Connecting to BindServer: " + host + ":" + port);
+ connection = new SocketConnection(logger, "BindServer");
+// connection.setPingTimeout(DebugeeBinder.PING_TIMEOUT);
+ connection.attach(host, port);
+ handshake(taskID);
+ }
+
+ /**
+ * Receive OK(version) from BindServer and check received version number.
+ */
+ private void handshake(String taskID) {
+ // receive OK(version)
+ trace(TRACE_LEVEL_ACTIONS, "Waiting for initial OK(version) from BindServer");
+ Object reply = connection.readObject();
+ trace(TRACE_LEVEL_ACTIONS, "Got initial OK(version) from BindServer: " + reply);
+ if (reply instanceof BindServer.RequestFailed) {
+ BindServer.RequestFailed castedReply = (BindServer.RequestFailed)reply;
+ trace(TRACE_LEVEL_ACTIONS, "Reply is RequestFailed: throw Failure");
+ throw new Failure("BindServer error: " + castedReply.reason);
+ } else if (reply instanceof BindServer.OK) {
+ BindServer.OK castedReply = (BindServer.OK)reply;
+ trace(TRACE_LEVEL_ACTIONS, "Reply is OK: check BindServer version");
+ if (castedReply.info != BindServer.VERSION) {
+ throw new Failure("Wrong version of BindServer: " + castedReply.info
+ + " (expected: " + BindServer.VERSION + ")");
+ }
+ display("Connected to BindServer: version " + castedReply.info);
+ } else {
+ trace(TRACE_LEVEL_ACTIONS, "Reply is unknown: throw Failure");
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+
+ // send TaskID(id)
+ try {
+ trace(TRACE_LEVEL_ACTIONS, "Sending TaskID(id) to BindServer");
+ sendCommand(new BindServer.TaskID(taskID));
+ trace(TRACE_LEVEL_ACTIONS, "Sent TaskID(id) to BindServer");
+ } catch (IOException e) {
+ throw new Failure("Caught IOException while sending TaskID(id) to BindServer:\n\t"
+ + e);
+ }
+ }
+
+ /**
+ * Check if thread is connected to <code>BindServer</code>.
+ */
+ public boolean isConnected() {
+ return (connection != null && connection.isConnected());
+ }
+
+ /**
+ * Send a command to </code>BindServer</code>.
+ */
+ public synchronized void sendCommand(Object command) throws IOException {
+ connection.writeObject(command);
+ }
+
+ /**
+ * Receive response from <code>BindServer</code>.
+ */
+ public Object getReply() {
+ synchronized (replies) {
+ while (replies.isEmpty()) {
+ if (!isConnected()) {
+ throw new Failure("No reply from BindServer: connection lost");
+ }
+ try {
+ replies.wait(TRY_DELAY);
+ } catch (InterruptedException e) {
+ e.printStackTrace(getOutStream());
+ throw new Failure("Thread interrupted while waiting for reply from BindServer:\n\t"
+ + e);
+ }
+ }
+ Object reply = replies.removeFirst();
+ if (reply == null) {
+ throw new Failure("No reply from BindServer: connection lost");
+ }
+ return reply;
+ }
+ }
+
+ /**
+ * Add response object to the list of received responses.
+ */
+ private void addReply(BindServer.Response reply) {
+ synchronized (replies) {
+ replies.add(reply);
+ replies.notifyAll();
+ }
+ }
+
+ /**
+ * Read packets from <code>BindServer<code> connection and
+ * notify waiting thread if response or IOPipe message received.
+ * Received lines of redirected streams are put into log.
+ */
+ public void run() {
+ trace(TRACE_LEVEL_THREADS, "BindServerListener thread started");
+ try {
+ for (;;) {
+ Object reply = connection.readObject();
+ if (reply == null) {
+ break;
+ } else if (reply instanceof BindServer.Disconnect) {
+ reply = null;
+ trace(TRACE_LEVEL_ACTIONS, "Packet is Disconnect: close connection");
+ break;
+ } else if (reply instanceof BindServer.RedirectedStream) {
+ BindServer.RedirectedStream castedReply = (BindServer.RedirectedStream)reply;
+ trace(TRACE_LEVEL_ACTIONS, "Packet is RedirectedStream: put message into log");
+ log.println(castedReply.line);
+ } else if (reply instanceof BindServer.Response) {
+ BindServer.Response castedReply = (BindServer.Response)reply;
+ trace(TRACE_LEVEL_ACTIONS, "Packet is reply: notify all threads waiting for reply");
+ addReply(castedReply);
+ } else {
+ trace(TRACE_LEVEL_ACTIONS, "Packet is unknown: throw Failure");
+ throw new Failure("Wrong reply from BindServer: " + reply);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(getOutStream());
+ complain("Caught exception while reading packets from BindServer:\n\t" + e);
+ } finally {
+ closeConnection();
+ addReply(null);
+ trace(TRACE_LEVEL_THREADS, "BindServerListener thread finished");
+ }
+ }
+
+ /**
+ * Send Disconnect command to </code>BindServer</code>.
+ */
+ public void disconnect() {
+ if (connection == null) return;
+ try {
+ sendCommand(new BindServer.Disconnect());
+ } catch (IOException e) {
+ display("Caught IOException while requesting disconnection with BindServer");
+ }
+ }
+
+ /**
+ * Close socket connection.
+ */
+ public void closeConnection() {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+
+ /**
+ * Wait for thread finished in the specified timeout or interrupt it.
+ */
+ public void waitForThread(long millis) {
+ DebugeeBinder.waitForThread(this, millis, logger);
+ }
+
+ /**
+ * Close this thread by waiting for it finishes or interrupt it
+ * and close socket connection.
+ */
+ public void close() {
+ disconnect();
+ waitForThread(DebugeeBinder.THREAD_TIMEOUT);
+ closeConnection();
+ }
+
+ } // BindServerListener
+
+} // DebugeeBinder
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/DebugeeProcess.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import nsk.share.*;
+import java.io.*;
+import java.net.*;
+
+/**
+ * This class is used to control debugee VM process.
+ * <p>
+ * Object of this class is constructed by <code>DebugeeBinder</code>
+ * and is used as a mirror of debugee VM process.
+ * It provides abilities to launch such process,
+ * redirect standard output streams, wait for process terminates
+ * or kill the process, and so on.
+ * <p>
+ * This is an abstract class that declares abstract methods to control
+ * debugee VM process.
+ * Derived classes should implement these methods corresponding to the mode
+ * that the process should be started in (locally, remotely or manually).
+ * <p>
+ * Particular derived classes <code>nsk.share.jdi.Debugee</code> and
+ * <code>nsk.share.jdwp.Debugee</code> provides additional abilities
+ * to control debugee VM using JDI or JDWP specific features.
+ *
+ * @see DebugeeBinder
+ *
+ * @see nsk.share.jdi.Debugee
+ * @see nsk.share.jdwp.Debugee
+ */
+abstract public class DebugeeProcess extends FinalizableObject {
+
+ /** Default prefix for log messages. */
+ public static final String LOG_PREFIX = "binder> ";
+ public static final String DEBUGEE_STDOUT_LOG_PREFIX = "debugee.stdout> ";
+ public static final String DEBUGEE_STDERR_LOG_PREFIX = "debugee.stderr> ";
+
+ /** Messages prefix. */
+ protected String prefix = LOG_PREFIX;
+
+ /** Binder that creates this debugee process. */
+ protected DebugeeBinder binder = null;
+
+ /** Messages log from binder. */
+ protected Log log = null;
+
+ /** Communicational channel between debuger and debugee. */
+ protected IOPipe pipe = null;
+
+ /** Argument handler from binder. */
+ protected DebugeeArgumentHandler argumentHandler = null;
+
+ /** Need or not to check debuggee process termination at exit. */
+ protected boolean checkTermination = false;
+
+ /** Debugee VM process or <i>null</i> if not available. */
+ protected Process process = null;
+
+ /** Make new <code>Debugee</code> object for the given binder. */
+ protected DebugeeProcess (DebugeeBinder binder) {
+ this.binder = binder;
+ this.log = binder.getLog();
+ }
+
+ /**
+ * Return already bound ServerSocket for IOPipe connection or null.
+ */
+ protected ServerSocket getPipeServerSocket() {
+ return binder.getPipeServerSocket();
+ }
+
+ /** Return <code>DebugeeArgumentHandler</code> of the debugee object. */
+ public DebugeeArgumentHandler getArgumentHandler() {
+ return binder.getArgumentHandler();
+ }
+
+ /** Return <code>Log</code> of the debugee object. */
+ public Log getLog() {
+ return log;
+ }
+
+ /** Return <code>Process</code> object associated with debugee VM or <i>null</i>. */
+ public Process getProcess() {
+ return process;
+ }
+
+ // --------------------------------------------------- //
+
+ /** Created and return new IOPipe channel to the debugee VM. */
+ public IOPipe createIOPipe() {
+ if (pipe != null) {
+ throw new TestBug("IOPipe channel is already created");
+ }
+ pipe = new IOPipe(this);
+ return pipe;
+ }
+
+ /** Return IOPipe channel or null if not yet ctreated. */
+ public IOPipe getIOPipe() {
+ return pipe;
+ }
+
+ /** Receive and return signal from the debugee VM via IOPipe channel.
+ *
+ * @throws TestBug if IOPipe channel is not created
+ */
+ public String receiveSignal() {
+ if ( pipe == null )
+ throw new TestBug("IOPipe channel is not initialized");
+ return pipe.readln();
+ }
+
+ /** Receive an expected <code>signal</code> from the debugee VM via IOPipe channel.
+ *
+ * @throws Failure if received signal is not equal to the expected one
+ * @throws TestBug if IOPipe channel is not created
+ */
+ public void receiveExpectedSignal(String signal) {
+ String line = receiveSignal();
+ if (line == null || !line.equals(signal))
+ throw new Failure("Received unexpected signal from debugee: " + line);
+ display("Received expected signal from debugee: " + signal);
+ }
+
+ /** Send <code>signal</code> to the debugee VM via IOPipe channel.
+ *
+ * @throws TestBug if IOPipe channel is not defined created.
+ */
+ public void sendSignal(String signal) {
+ if (pipe == null)
+ throw new TestBug("IOPipe channel is not initialized");
+ pipe.println(signal);
+ }
+
+
+ // --------------------------------------------------- //
+
+ /** Wait until the debugee VM shutdown or crash. */
+ abstract protected int waitForDebugee () throws InterruptedException;
+
+ /** Kill the debugee VM. */
+ abstract protected void killDebugee ();
+
+ /** Check whether the debugee VM has been terminated. */
+ abstract public boolean terminated ();
+
+ /** Return the debugee VM exit status. */
+ abstract public int getStatus ();
+
+ /** Get a pipe to write to the debugee's stdin stream. */
+ abstract protected OutputStream getInPipe ();
+
+ /** Get a pipe to read the debugee's stdout stream. */
+ abstract protected InputStream getOutPipe ();
+
+ /** Get a pipe to read the debugee's stderr stream. */
+ abstract protected InputStream getErrPipe ();
+
+ // --------------------------------------------------- //
+
+ /**
+ * Wait until the debugee VM shutdown or crash,
+ * and let finish its stdout, stderr, and stdin
+ * redirectors (if any).
+ *
+ * @return Debugee process exit code.
+ * @see #waitForRedirectors(long)
+ */
+ public int waitFor () {
+ long timeout = binder.getArgumentHandler().getWaitTime() * 60 * 1000;
+ int exitCode = 0;
+ try {
+ exitCode = waitForDebugee();
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while waiting for debuggee process: \n\t" + ie);
+ }
+ waitForRedirectors(timeout);
+ if (process != null) {
+ process.destroy();
+ }
+ return exitCode;
+ }
+
+ /**
+ * Wait until the debugee VM redirectors to complete for specified <code>timeout</code>.
+ *
+ * @see #waitFor()
+ */
+ public void waitForRedirectors (long timeout) {
+ try {
+ if (stdinRedirector != null) {
+ if (stdinRedirector.isAlive()) {
+ stdinRedirector.join(timeout);
+ if (stdinRedirector.isAlive()) {
+ log.complain("Timeout for waiting STDIN redirector exceeded");
+ stdinRedirector.interrupt();
+ }
+ }
+ stdinRedirector = null;
+ };
+ if (stdoutRedirector != null) {
+ if (stdoutRedirector.isAlive()) {
+ stdoutRedirector.join(timeout);
+ if (stdoutRedirector.isAlive()) {
+ log.complain("Timeout for waiting STDOUT redirector exceeded");
+ stdoutRedirector.interrupt();
+ }
+ }
+ stdoutRedirector = null;
+ };
+ if (stderrRedirector != null) {
+ if (stderrRedirector.isAlive()) {
+ stderrRedirector.join(timeout);
+ if (stderrRedirector.isAlive()) {
+ log.complain("Timeout for waiting STDERR redirector exceeded");
+ stderrRedirector.interrupt();
+ }
+ }
+ stderrRedirector = null;
+ };
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(log.getOutStream());
+ throw new Failure("Caught exception while waiting for debuggee output redirectors: \n\t"
+ + ie);
+ }
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Get a pipe to write to the debugee's stdin stream,
+ * or throw TestBug exception is redirected.
+ */
+ final public OutputStream getStdin () {
+ if (stdinRedirector != null)
+ throw new TestBug("Debugee's stdin is redirected");
+ return getInPipe();
+ }
+
+ /**
+ * Get a pipe to read the debugee's stdout stream,
+ * or throw TestBug exception is redirected.
+ */
+ final public InputStream getStdout () {
+ if (stdoutRedirector != null)
+ throw new TestBug("Debugee's stdout is redirected");
+ return getOutPipe();
+ }
+
+ /**
+ * Get a pipe to read the debugee's stderr stream,
+ * or throw TestBug exception is redirected.
+ */
+ final public InputStream getStderr () {
+ if (stderrRedirector != null)
+ throw new TestBug("Debugee's stderr is redirected");
+ return getErrPipe();
+ }
+
+ // --------------------------------------------------- //
+
+ private IORedirector stdoutRedirector = null;
+ private IORedirector stderrRedirector = null;
+ private IORedirector stdinRedirector = null;
+
+// /**
+// * Start a thread redirecting the given <code>in</code> stream
+// * to the debugee's stdin. If the debugee's stdin was already
+// * redirected, the TestBug exception is thrown.
+// */
+// final public void redirectStdin(InputStream in) {
+// if (stdinRedirector != null)
+// throw new TestBug("the debugee's stdin is already redirected");
+// stdinRedirector = new IORedirector(in,getInPipe());
+// stdinRedirector.setName("IORedirector for stdin");
+// stdinRedirector.setDaemon(true);
+// stdinRedirector.start();
+// }
+
+ /**
+ * Start thread redirecting the debugee's stdout to the
+ * given <code>out</code> stream. If the debugee's stdout
+ * was already redirected, the TestBug exception is thrown.
+ *
+ * @deprecated Use redirectStdout(Log, String) instead.
+ */
+ public void redirectStdout(OutputStream out) {
+ if (stdoutRedirector != null) {
+ return;
+ }
+// throw new TestBug("Debugee's stdout is already redirected");
+ stdoutRedirector = new IORedirector(getOutPipe(),out);
+ stdoutRedirector.setPrefix(DEBUGEE_STDOUT_LOG_PREFIX);
+ stdoutRedirector.setName("IORedirector for stdout");
+ stdoutRedirector.setDaemon(true);
+ stdoutRedirector.start();
+ }
+
+ /**
+ * Start thread redirecting the debugee's stdout to the
+ * given <code>Log</code>. If the debugee's stdout
+ * was already redirected, the TestBug exception is thrown.
+ */
+ public void redirectStdout(Log log, String prefix) {
+ if (stdoutRedirector != null) {
+// stdoutRedirector.setPrefix(prefix);
+ return;
+// throw new TestBug("the debugee's stdout is already redirected");
+ }
+ stdoutRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getOutPipe())), log, prefix);
+ stdoutRedirector.setName("IORedirector for stdout");
+ stdoutRedirector.setDaemon(true);
+ stdoutRedirector.start();
+ }
+
+ /**
+ * Start thread redirecting the debugee's stderr to the
+ * given <code>err</code> stream. If the debugee's stderr
+ * was already redirected, the TestBug exception is thrown.
+ *
+ * @deprecated Use redirectStderr(Log, String) instead.
+ */
+ public void redirectStderr(OutputStream err) {
+ if (stderrRedirector != null) {
+ return;
+ }
+// throw new TestBug("Debugee's stderr is already redirected");
+ stderrRedirector = new IORedirector(getErrPipe(),err);
+ stderrRedirector.setPrefix(DEBUGEE_STDERR_LOG_PREFIX);
+ stdoutRedirector.setName("IORedirector for stderr");
+ stderrRedirector.setDaemon(true);
+ stderrRedirector.start();
+ }
+
+ /**
+ * Start thread redirecting the debugee's stderr to the
+ * given <code>Log</code>. If the debugee's stderr
+ * was already redirected, the TestBug exception is thrown.
+ */
+ public void redirectStderr(Log log, String prefix) {
+ if (stderrRedirector != null) {
+// stderrRedirector.setPrefix(prefix);
+ return;
+// throw new TestBug("Debugee's stderr is already redirected");
+ }
+ stderrRedirector = new IORedirector(new BufferedReader(new InputStreamReader(getErrPipe())), log, prefix);
+ stdoutRedirector.setName("IORedirector for stderr");
+ stderrRedirector.setDaemon(true);
+ stderrRedirector.start();
+ }
+
+ /**
+ * Start thread redirecting the debugee's stdout/stderr to the
+ * given <code>Log</code> using standard prefixes.
+ * If the debugee's stdout/stderr were already redirected,
+ * the TestBug exception is thrown.
+ */
+ public void redirectOutput(Log log) {
+ redirectStdout(log, "debugee.stdout> ");
+ redirectStderr(log, "debugee.stderr> ");
+ }
+ // --------------------------------------------------- //
+
+ /**
+ * Kill the debugee VM if it is not terminated yet.
+ *
+ * @throws Throwable if any throwable exception is thrown during finalization
+ */
+ public void close() {
+ if (checkTermination) {
+ if (!terminated()) {
+ complain("Debugee VM has not exited correctly: trying to kill it");
+ killDebugee();
+ }
+ checkTermination = false;
+ }
+ }
+
+ // --------------------------------------------------- //
+
+ /**
+ * Display log message with prefix.
+ */
+ protected void display(String message) {
+ log.display(prefix + message);
+ }
+
+ /**
+ * Complain about error with specified message.
+ */
+ protected void complain(String message) {
+ log.complain(prefix + message);
+ }
+
+ /**
+ * Finalize debuggee VM wrapper by invoking <code>close()</code>.
+ *
+ * @throws Throwable if any throwable exception is thrown during finalization
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/ForceEarlyReturnTestThread.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (c) 2006, 2018, 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.
+ */
+
+// THIS TEST IS LINE NUMBER SENSITIVE
+
+package nsk.share.jpda;
+
+import java.net.*;
+import nsk.share.*;
+
+// ForceEarlyReturnTestThread intended for testing ForceEarlyReturn functionality.
+//
+// ForceEarlyReturnTestThread contains test methods with different return type
+// (types corresponds to subclasses of com.sun.jdi.Value or JDWP type identifiers).
+// Debugger VM should set breakpoint on line log("...") and when test thread stop at breakpoint call
+// forceEarlyReturn(), so instructions after breakpoint shouldn't be executed(unexpectedMethod() shouldn't be called)
+// When started thread executes all test methods in order assigned in 'testedTypesNames' array.
+// It is possible to run this thread in 'testThread' mode, in this mode thread check that values returned from
+// test methods equals to those that should be returned through forceEarlyReturn, and no
+// instructions was executed in called method after force return (finally blocks are not executed too).
+// In non-testThread mode thread check that values returned from test methods was not changed.
+public class ForceEarlyReturnTestThread
+extends Thread
+{
+ void VoidMethod()
+ {
+ try
+ {
+ log("in void method"); // breakpointLines[0]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+ }
+
+ boolean BooleanMethod()
+ {
+ try
+ {
+ log("in boolean method"); // breakpointLines[1]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedBooleanValue;
+ }
+
+ byte ByteMethod()
+ {
+ try
+ {
+ log("in byte method"); // breakpointLines[2]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedByteValue;
+ }
+
+ short ShortMethod()
+ {
+ try
+ {
+ log("in short method"); // breakpointLines[3]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedShortValue;
+ }
+
+ char CharMethod()
+ {
+ try
+ {
+ log("in char method"); // breakpointLines[4]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedCharValue;
+ }
+
+ int IntMethod()
+ {
+ try
+ {
+ log("in int method"); // breakpointLines[5]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedIntValue;
+ }
+
+ long LongMethod()
+ {
+ try
+ {
+ log("in long method"); // breakpointLines[6]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedLongValue;
+ }
+
+ float FloatMethod()
+ {
+ try
+ {
+ log("in float method"); // breakpointLines[7]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedFloatValue;
+ }
+
+ double DoubleMethod()
+ {
+ try
+ {
+ log("in double method"); // breakpointLines[8]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedDoubleValue;
+ }
+
+ Object[] ObjectArrayMethod()
+ {
+ try
+ {
+ log("in object array method"); // breakpointLines[9]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedObjectArrayValue;
+ }
+
+ String StringMethod()
+ {
+ try
+ {
+ log("in string method"); // breakpointLines[10]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedStringValue;
+ }
+
+ Thread ThreadMethod()
+ {
+ try
+ {
+ log("in thread method"); // breakpointLines[11]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedThreadValue;
+ }
+
+ ThreadGroup ThreadGroupMethod()
+ {
+ try
+ {
+ log("in thread group method"); // breakpointLines[12]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedThreadGroupValue;
+ }
+
+ Class<?> ClassObjectMethod()
+ {
+ try
+ {
+ log("in class object method"); // breakpointLines[13]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedClassObjectValue;
+ }
+
+ ClassLoader ClassLoaderMethod()
+ {
+ try
+ {
+ log("in class loader method"); // breakpointLines[14]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedClassLoaderValue;
+ }
+
+ Object ObjectMethod()
+ {
+ try
+ {
+ log("in object method"); // breakpointLines[15]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedObjectValue;
+ }
+
+ Boolean BooleanWrapperMethod()
+ {
+ try
+ {
+ log("in boolean wrapper method"); // breakpointLines[16]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedBooleanWrapperValue;
+ }
+
+ Byte ByteWrapperMethod()
+ {
+ try
+ {
+ log("in byte wrapper method"); // breakpointLines[17]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedByteWrapperValue;
+ }
+
+ Short ShortWrapperMethod()
+ {
+ try
+ {
+ log("in short wrapper method"); // breakpointLines[18]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedShortWrapperValue;
+ }
+
+ Character CharWrapperMethod()
+ {
+ try
+ {
+ log("in char wrapper method"); // breakpointLines[19]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedCharWrapperValue;
+ }
+
+ Integer IntWrapperMethod()
+ {
+ try
+ {
+ log("in int wrapper method"); // breakpointLines[20]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedIntWrapperValue;
+ }
+
+ Long LongWrapperMethod()
+ {
+ try
+ {
+ log("in long wrapper method"); // breakpointLines[21]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedLongWrapperValue;
+ }
+
+ Float FloatWrapperMethod()
+ {
+ try
+ {
+ log("in float wrapper method"); // breakpointLines[22]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedFloatWrapperValue;
+ }
+
+ Double DoubleWrapperMethod()
+ {
+ try
+ {
+ log("in double wrapper method"); // breakpointLines[23]
+ }
+ finally
+ {
+ unexpectedMethod();
+ }
+
+ unexpectedMethod();
+
+ return unexpectedDoubleWrapperValue;
+ }
+
+ private void log(String message)
+ {
+ log.display(currentThread().getName() + ": " + message);
+ }
+
+ private void logError(String message)
+ {
+ log.complain(currentThread().getName() + ": " + message);
+ }
+
+ // values which should be passed in forceEarlyReturn():
+
+ public static boolean expectedBooleanValue = Boolean.TRUE;
+ public static byte expectedByteValue = Byte.MAX_VALUE;
+ public static char expectedCharValue = Character.MAX_VALUE;
+ public static short expectedShortValue = Short.MAX_VALUE;
+ public static int expectedIntValue = Integer.MAX_VALUE;
+ public static long expectedLongValue = Long.MAX_VALUE;
+ public static float expectedFloatValue = Float.MAX_VALUE;
+ public static double expectedDoubleValue = Double.MAX_VALUE;
+ public static Object[] expectedObjectArrayValue = new Object[1000];
+ public static Thread expectedThreadValue = new Thread();
+ public static ThreadGroup expectedThreadGroupValue = new ThreadGroup("Expected thread group");
+ public static Class<?> expectedClassObjectValue = ForceEarlyReturnTestThread.class;
+ public static ClassLoader expectedClassLoaderValue = new URLClassLoader(new URL[]{});
+ public static String expectedStringValue = "EXPECTED STRING";
+ public static Object expectedObjectValue = new Object();
+ public static Boolean expectedBooleanWrapperValue = new Boolean(Boolean.TRUE);
+ public static Byte expectedByteWrapperValue = new Byte(Byte.MAX_VALUE);
+ public static Character expectedCharWrapperValue = new Character(Character.MAX_VALUE);
+ public static Short expectedShortWrapperValue = new Short(Short.MAX_VALUE);
+ public static Integer expectedIntWrapperValue = new Integer(Integer.MAX_VALUE);
+ public static Long expectedLongWrapperValue = new Long(Long.MAX_VALUE);
+ public static Float expectedFloatWrapperValue = new Float(Float.MAX_VALUE);
+ public static Double expectedDoubleWrapperValue = new Double(Double.MAX_VALUE);
+
+ // values which should be returned from test methods without forceEarlyReturn():
+
+ public static boolean unexpectedBooleanValue = Boolean.FALSE;
+ public static byte unexpectedByteValue = 0;
+ public static char unexpectedCharValue = 0;
+ public static short unexpectedShortValue = 0;
+ public static int unexpectedIntValue = 0;
+ public static long unexpectedLongValue = 0;
+ public static float unexpectedFloatValue = 0;
+ public static double unexpectedDoubleValue = 0;
+ public static Object[] unexpectedObjectArrayValue = new Object[1000];
+ public static String unexpectedStringValue = "UNEXPECTED STRING";
+ public static Thread unexpectedThreadValue = new Thread();
+ public static ThreadGroup unexpectedThreadGroupValue = new ThreadGroup("Unexpected thread group");
+ public static Class<?> unexpectedClassObjectValue = Object.class;
+ public static ClassLoader unexpectedClassLoaderValue = new URLClassLoader(new URL[]{});
+ public static Object unexpectedObjectValue = new Object();
+ public static Boolean unexpectedBooleanWrapperValue = new Boolean(Boolean.FALSE);
+ public static Byte unexpectedByteWrapperValue = new Byte((byte)0);
+ public static Character unexpectedCharWrapperValue = new Character((char)0);
+ public static Short unexpectedShortWrapperValue = new Short((short)0);
+ public static Integer unexpectedIntWrapperValue = new Integer(0);
+ public static Long unexpectedLongWrapperValue = new Long(0);
+ public static Float unexpectedFloatWrapperValue = new Float(0);
+ public static Double unexpectedDoubleWrapperValue = new Double(0);
+
+ public static int[] breakpointLines = {
+ 49,
+ 63,
+ 79,
+ 95,
+ 111,
+ 127,
+ 143,
+ 159,
+ 175,
+ 191,
+ 207,
+ 223,
+ 239,
+ 255,
+ 271,
+ 287,
+ 303,
+ 319,
+ 335,
+ 351,
+ 367,
+ 383,
+ 399,
+ 415};
+
+ /* Invalid data for ForceEarlyReturn, needed to check is ForceEarlyReturn complies with following part of specification:
+ * Object values must be assignment compatible with the method return type
+ * (This implies that the method return type must be loaded through the enclosing class's class loader).
+ * Primitive values must be either assignment compatible with the method return type or must
+ * be convertible to the variable type without loss of information.
+ */
+ public static boolean invalidVoidValue = Boolean.TRUE;
+ public static boolean invalidObjectValue = Boolean.TRUE;
+ public static byte invalidBooleanValue = Byte.MAX_VALUE;
+ public static short invalidByteValue = Short.MAX_VALUE;
+ public static char invalidShortValue = Character.MAX_VALUE;
+ public static int invalidCharValue = Integer.MAX_VALUE;
+ public static long invalidIntValue = Long.MAX_VALUE;
+ public static float invalidLongValue = Float.MAX_VALUE;
+ public static double invalidFloatValue = Double.MAX_VALUE;
+ public static Object[] invalidDoubleValue = new Object[1000];
+ public static String invalidObjectArrayValue = "EXPECTED STRING";
+ public static Thread invalidStringValue = new Thread("Invalid thread");
+ public static ThreadGroup invalidThreadValue = new ThreadGroup("Invalid thread group");
+ public static Class<?> invalidThreadGroupValue = ForceEarlyReturnTestThread.class;
+ public static ClassLoader invalidClassObjectValue = new URLClassLoader(new URL[]{});
+ public static Object invalidClassLoaderValue = new Object();
+ public static Byte invalidBooleanWrapperValue = new Byte(Byte.MAX_VALUE);
+ public static Short invalidByteWrapperValue = new Short(Short.MAX_VALUE);
+ public static Character invalidShortWrapperValue = new Character(Character.MAX_VALUE);
+ public static Integer invalidCharWrapperValue = new Integer(Integer.MAX_VALUE);
+ public static Long invalidIntWrapperValue = new Long(Long.MAX_VALUE);
+ public static Float invalidLongWrapperValue = new Float(Float.MAX_VALUE);
+ public static Double invalidFloatWrapperValue = new Double(Double.MAX_VALUE);
+ public static Object[] invalidDoubleWrapperValue = new Object[1000];
+
+ // names of tested types, this names can be used to derive names of tested methods(typeName + 'Method'),
+ // names of fields containing predefined data to be returned through ForceEarlyReturn('expected' + typeName + 'Value'),
+ // names of fields containing invalid data for ForceEarlyReturn(needed to check is ForceEarlyReturn complies with its specification('invalid' + typeName + 'Value'))
+ public static String testedTypesNames[] =
+ {
+ "Void",
+ "Boolean",
+ "Byte",
+ "Short",
+ "Char",
+ "Int",
+ "Long",
+ "Float",
+ "Double",
+ "ObjectArray",
+ "String",
+ "Thread",
+ "ThreadGroup",
+ "ClassObject",
+ "ClassLoader",
+ "Object",
+ "BooleanWrapper",
+ "ByteWrapper",
+ "ShortWrapper",
+ "CharWrapper",
+ "IntWrapper",
+ "LongWrapper",
+ "FloatWrapper",
+ "DoubleWrapper",
+ };
+
+ private Log log;
+
+ // is forceEarlyReturn would called for this thread
+ private boolean isTestThread;
+
+ // how many times call all test methods (zero means infinite execution)
+ private int iterationsNumber = 1;
+
+ // test thread wait on 'startExecutionWicket' in beginning of run()
+ private Wicket startExecutionWicket = new Wicket();
+
+ private boolean success = true;
+
+ public ForceEarlyReturnTestThread(Log log, boolean isTestThread, int iterationNumber)
+ {
+ this.log = log;
+ this.isTestThread = isTestThread;
+
+ this.iterationsNumber = iterationNumber;
+ }
+
+ private volatile boolean stopExecution;
+
+ public void stopExecution()
+ {
+ stopExecution = true;
+ }
+
+ public void startExecuion()
+ {
+ startExecutionWicket.unlockAll();
+ }
+
+ public void run()
+ {
+ // first, debuggee VM starts and suspends test threads to let debugger initialize breakpoints
+ startExecutionWicket.waitFor();
+
+ int iterationCount = 0;
+
+ // test thread executes test methods 'iterationNumber' times
+ // non-test thread execute until not interrupted
+ // (iterationsNumber = 0 means infinite execution)
+ while(!stopExecution && (!isTestThread || ((iterationsNumber == 0) || (iterationCount++ < iterationsNumber))))
+ {
+ // execute test methods in order given in 'testMethodsNames' array
+ for(int i = 0; (i < testedTypesNames.length) && !stopExecution; i++)
+ {
+ executeMethod(testedTypesNames[i] + "Method");
+
+ /*
+ * Small delay was inserted because of if test starts several ForceEarlyReturnTestThreads
+ * with parameter isTestThread = false, these threads may consume too many CPU time and test
+ * execution will be very slow
+ */
+ if (!isTestThread) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ logError("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ success = false;
+ }
+ }
+ }
+ }
+
+ log("Test thread exit");
+ }
+
+ // execute test method and check that correct value is returned
+ private void executeMethod(String methodName)
+ {
+ if(methodName.equals("VoidMethod"))
+ {
+ VoidMethod();
+ }
+ if(methodName.equals("BooleanMethod"))
+ {
+ boolean result = BooleanMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ boolean expectedResult;
+
+ expectedResult = isTestThread ? expectedBooleanValue : unexpectedBooleanValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ByteMethod"))
+ {
+ byte result = ByteMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ byte expectedResult;
+
+ expectedResult = isTestThread ? expectedByteValue : unexpectedByteValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("CharMethod"))
+ {
+ char result = CharMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ char expectedResult;
+
+ expectedResult = isTestThread ? expectedCharValue : unexpectedCharValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ShortMethod"))
+ {
+ short result = ShortMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ short expectedResult;
+
+ expectedResult = isTestThread ? expectedShortValue : unexpectedShortValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("IntMethod"))
+ {
+ int result = IntMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ int expectedResult;
+
+ expectedResult = isTestThread ? expectedIntValue : unexpectedIntValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("LongMethod"))
+ {
+ long result = LongMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ long expectedResult;
+
+ expectedResult = isTestThread ? expectedLongValue : unexpectedLongValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("FloatMethod"))
+ {
+ float result = FloatMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ float expectedResult;
+
+ expectedResult = isTestThread ? expectedFloatValue : unexpectedFloatValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("DoubleMethod"))
+ {
+ double result = DoubleMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ double expectedResult;
+
+ expectedResult = isTestThread ? expectedDoubleValue : unexpectedDoubleValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("StringMethod"))
+ {
+ String result = StringMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ String expectedResult;
+
+ expectedResult = isTestThread ? expectedStringValue : unexpectedStringValue;
+
+ if(!result.equals(expectedResult))
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ObjectMethod"))
+ {
+ Object result = ObjectMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Object expectedResult;
+
+ expectedResult = isTestThread ? expectedObjectValue : unexpectedObjectValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ObjectArrayMethod"))
+ {
+ Object[] result = ObjectArrayMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Object[] expectedResult;
+
+ expectedResult = isTestThread ? expectedObjectArrayValue : unexpectedObjectArrayValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ThreadMethod"))
+ {
+ Thread result = ThreadMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Thread expectedResult;
+
+ expectedResult = isTestThread ? expectedThreadValue : unexpectedThreadValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ThreadGroupMethod"))
+ {
+ ThreadGroup result = ThreadGroupMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ ThreadGroup expectedResult;
+
+ expectedResult = isTestThread ? expectedThreadGroupValue : unexpectedThreadGroupValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ClassObjectMethod"))
+ {
+ Class<?> result = ClassObjectMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Class<?> expectedResult;
+
+ expectedResult = isTestThread ? expectedClassObjectValue : unexpectedClassObjectValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ClassLoaderMethod"))
+ {
+ ClassLoader result = ClassLoaderMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ ClassLoader expectedResult;
+
+ expectedResult = isTestThread ? expectedClassLoaderValue : unexpectedClassLoaderValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("BooleanWrapperMethod"))
+ {
+ Boolean result = BooleanWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Boolean expectedResult;
+
+ expectedResult = isTestThread ? expectedBooleanWrapperValue : unexpectedBooleanWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ByteWrapperMethod"))
+ {
+ Byte result = ByteWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Byte expectedResult;
+
+ expectedResult = isTestThread ? expectedByteWrapperValue : unexpectedByteWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("ShortWrapperMethod"))
+ {
+ Short result = ShortWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Short expectedResult;
+
+ expectedResult = isTestThread ? expectedShortWrapperValue : unexpectedShortWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("CharWrapperMethod"))
+ {
+ Character result = CharWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Character expectedResult;
+
+ expectedResult = isTestThread ? expectedCharWrapperValue : unexpectedCharWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("IntWrapperMethod"))
+ {
+ Integer result = IntWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Integer expectedResult;
+
+ expectedResult = isTestThread ? expectedIntWrapperValue : unexpectedIntWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("LongWrapperMethod"))
+ {
+ Long result = LongWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Long expectedResult;
+
+ expectedResult = isTestThread ? expectedLongWrapperValue : unexpectedLongWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("FloatWrapperMethod"))
+ {
+ Float result = FloatWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Float expectedResult;
+
+ expectedResult = isTestThread ? expectedFloatWrapperValue : unexpectedFloatWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ if(methodName.equals("DoubleWrapperMethod"))
+ {
+ Double result = DoubleWrapperMethod();
+
+ // log(Thread.currentThread() + ": result of " + methodName + ": " + result);
+
+ Double expectedResult;
+
+ expectedResult = isTestThread ? expectedDoubleWrapperValue : unexpectedDoubleWrapperValue;
+
+ if(result != expectedResult)
+ {
+ logError("unexpected result of " + methodName + ": " + result + ", expected is: " + expectedResult);
+ success = false;
+ }
+ }
+ }
+
+ // method which shouldn't be executed in test thread
+ void unexpectedMethod()
+ {
+ if(isTestThread)
+ {
+ success = false;
+ logError("unexpected code is executed after forceEarlyReturn");
+ }
+ }
+
+ public boolean getSuccess()
+ {
+ return success;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/IOPipe.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import nsk.share.*;
+
+/**
+ * This class implements communicational channel between
+ * debugger and debugee used for synchronization and data exchange.
+ * This channel is based on TCP/IP sockets and works in all
+ * modes (local, remote and manual). In a remote mode
+ * connection to <code>BindServer</code> is used for redirecting IOPipe messages.
+ * In all other modes direct TCP/IP coonnection between two VMs is used.
+ *
+ * @see BindServer
+ */
+public class IOPipe extends SocketIOPipe {
+
+ public static final byte PORTS_COUNT = 10;
+ public static final byte NO_PORTS = 0;
+
+ public static final String PIPE_LOG_PREFIX = "IOPipe> ";
+
+ private DebugeeProcess debugee;
+
+ /**
+ * Make <code>IOPipe</code> at debugee's side.
+ *
+ * @deprecated Use DebugeeArgumentHandler.createDebugeeIOPipe(Log) instead.
+ *
+ * @see DebugeeArgumentHandler#createDebugeeIOPipe(Log)
+ */
+ public IOPipe(DebugeeArgumentHandler argumentHandler, Log log) {
+ this(log, getTestHost(argumentHandler), argumentHandler.getPipePortNumber(),
+ (long)argumentHandler.getWaitTime() * 60 * 1000, false);
+ }
+
+ /**
+ * Make <code>IOPipe</code> at debugger's side
+ * with given <code>Debugee</code> mirror.
+ *
+ * @deprecated Use Debugee.createIOPipe() instead.
+ */
+ public IOPipe(DebugeeProcess debugee) {
+ this(debugee.getLog(),
+ debugee.getArgumentHandler().getDebugeeHost(),
+ debugee.getArgumentHandler().getPipePortNumber(),
+ (long)debugee.getArgumentHandler().getWaitTime() * 60 * 1000,
+ true);
+
+ this.debugee = debugee;
+ }
+
+ /**
+ * Make general <code>IOPipe</code> object with specified parameters.
+ */
+ protected IOPipe(Log log, String host, int port, long timeout, boolean listening) {
+ super("IOPipe", log, PIPE_LOG_PREFIX, host, port, timeout, listening);
+ }
+
+ protected void connect() {
+ if (listening) {
+ setServerSocket(debugee.getPipeServerSocket());
+ setConnectingProcess(debugee.getProcess());
+ }
+
+ super.connect();
+ }
+
+ /**
+ * Get appropriate test host name relying on the provided argumnets.
+ */
+ private static String getTestHost(DebugeeArgumentHandler argumentHandler) {
+ return argumentHandler.getTestHost();
+ }
+
+} // IOPipe
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.jpda;
+
+import java.io.*;
+import java.net.*;
+
+import nsk.share.*;
+
+/**
+ * This class implements basic connection channel via TCP/IP sockets.
+ */
+class BasicSocketConnection {
+
+ protected static int TRACE_LEVEL_PACKETS = 10;
+
+ protected static int TRACE_LEVEL_THREADS = 20;
+
+ protected static int TRACE_LEVEL_ACTIONS = 30;
+
+ protected static int TRACE_LEVEL_SOCKETS = 40;
+
+ protected static int TRACE_LEVEL_IO = 50;
+
+ protected String name = null;
+
+ protected ServerSocket serverSocket = null;
+
+ protected Socket socket = null;
+
+ protected InputStream sin = null;
+
+ protected OutputStream sout = null;
+
+ protected Process connectingProcess = null;
+
+ protected volatile boolean connected = false;
+
+ protected volatile boolean closed = false;
+
+ protected volatile boolean connectionClosed = false;
+
+ protected volatile boolean shouldStop = false;
+
+ protected Log.Logger logger = null;
+
+ /**
+ * Make an empty connection with specified name.
+ *
+ * @param logger
+ * Logger object for printing log messages
+ * @param name
+ * connection name
+ */
+ public BasicSocketConnection(Log.Logger logger, String name) {
+ this.logger = logger;
+ this.name = name;
+ }
+
+ /**
+ * Try to bind connection to the local port.
+ *
+ * @param port
+ * port number to bind to
+ *
+ * @throws IOException
+ * if error occured while binding
+ */
+ protected void tryBind(int port) throws IOException {
+ logger.trace(TRACE_LEVEL_IO, "Binding for " + name + " connection to port: " + port);
+ serverSocket = new ServerSocket(port, 1);
+ logger.trace(TRACE_LEVEL_IO, "Bound for " + name + " connection to port: " + port);
+ }
+
+ /**
+ * Bind connection to the local port for specified timeout.
+ *
+ * @param port
+ * port number to bind to
+ * @param timeout
+ * binding timeout in milliseconds
+ *
+ * @throws Failure
+ * if error ocured while binding
+ */
+ protected void bind(int port, long timeout) {
+ BindException bindException = null;
+ long timeToFinish = System.currentTimeMillis() + timeout;
+ for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) {
+ try {
+ tryBind(port);
+ return;
+ } catch (BindException e) {
+ bindException = e;
+ logger.display("Attempt #" + i + " to bind to port " + port + " failed:\n\t" + e);
+ try {
+ Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ ie.printStackTrace(logger.getOutStream());
+ throw new Failure("Thread interrupted while binding for " + name + " connection to port " + port + ":\n\t" + ie);
+ }
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught IOException while binding for " + name + " connection to port " + port + ":\n\t" + e);
+ }
+ }
+ throw new Failure("Unable to bind for " + name + " connection to port " + port + " for " + timeout + "ms timeout:\n\t" + bindException);
+ }
+
+ /**
+ * Accept connection at the bound port for specified timeout.
+ *
+ * @param timeout
+ * accepting timeout in milliseconds
+ *
+ * @throws Failure
+ * if error occured while accepting connection
+ */
+ public void accept(long timeout) {
+ int port = serverSocket.getLocalPort();
+ logger.trace(TRACE_LEVEL_IO, "Listening for " + name + " connection at port: " + port);
+ socket = null;
+ try {
+ if (timeout > Integer.MAX_VALUE) {
+ throw new TestBug("Too large timeout long value: " + timeout + " (can't cast it to int)");
+ }
+
+ serverSocket.setSoTimeout((int)timeout);
+
+ long waitStartTime = System.currentTimeMillis();
+
+ /*
+ * We found that sometimes (very rarely) on Solaris ServerSocket.accept() throws InterruptedIOException
+ * even if connection timeout (specified through ServerSocket.setSoTimeout) didn't expire.
+ * Following code tries to catch such case and call ServerSocket.accept() while timeout didn't expire.
+ */
+ do {
+ try {
+ socket = serverSocket.accept();
+ logger.trace(TRACE_LEVEL_IO, "Accepted " + name + " connection at port: " + port);
+ } catch (InterruptedIOException e) {
+ long interruptTime = System.currentTimeMillis();
+ long waitTime = interruptTime - waitStartTime;
+
+ logger.display("Caught InterruptedIOException. Wait start time: " + waitStartTime + ", exception was thrown at: "
+ + interruptTime + ", wait time: " + (interruptTime - waitStartTime) + ", actual timeout: " + timeout);
+
+ // if waitTime was too small call ServerSocket.accept() one more time
+ if (!shouldStop && (waitTime < (timeout / 2))) {
+ logger.display("InterruptedIOException was thrown too early, trying to call ServerSocket.accept() one more time");
+ continue;
+ } else {
+ if (!shouldStop) {
+ logger.complain("Caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e);
+ throw new Failure("Connection for " + name +
+ " at port " + port +
+ " wasn't accepted in " + timeout + "ms");
+ } else {
+ logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")");
+ break;
+ }
+ }
+ }
+ } while (socket == null);
+
+ } catch (IOException e) {
+ if (!shouldStop) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught IOException while listening for " + name + " connection at port " + port + ":\n\t" + e);
+ } else {
+ logger.display("Listening was interrupted (caught InterruptedIOException while listening for " + name + " connection at port " + port + ":\n\t" + e + ")");
+ }
+ } finally {
+ closeServerConnection();
+ }
+
+ if (!shouldStop) {
+ if (socket == null) {
+ throw new Failure("No " + name + " connection accepted at port " + port + " for " + timeout + "ms timeout");
+ }
+
+ onConnected();
+ }
+ }
+
+ /**
+ * Attach connection to the remote host and port.
+ *
+ * @param host
+ * name of remote host to attach to
+ * @param port
+ * port number to attach to
+ *
+ * @throws Failure
+ * if error occured while attaching
+ */
+ public void attach(String host, int port) {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port);
+ socket = new Socket(host, port);
+ socket.setTcpNoDelay(true);
+ logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port);
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e);
+ }
+ if (!shouldStop) {
+ onConnected();
+ }
+ }
+
+ /**
+ * Continuously attach to the remote host for the specified timeout.
+ *
+ * @param host
+ * name of remote host to attach to
+ * @param port
+ * port number to attach to
+ * @param timeout
+ * attaching timeout in milliseconds
+ *
+ * @throws Failure
+ * if error occured while attaching
+ */
+ public void continueAttach(String host, int port, long timeout) {
+ socket = null;
+ long timeToFinish = System.currentTimeMillis() + timeout;
+ ConnectException lastException = null;
+ logger.trace(TRACE_LEVEL_IO, "Attaching for " + name + " connection to host: " + host + ":" + port);
+ try {
+ for (long i = 0; !shouldStop && (timeout == 0 || System.currentTimeMillis() < timeToFinish); i++) {
+ try {
+ socket = new Socket(host, port);
+ logger.trace(TRACE_LEVEL_IO, "Attached for " + name + " connection to host: " + host + ":" + port);
+ break;
+ } catch (ConnectException e) {
+ logger.display("Attempt #" + i + " to attach for " + name + " connection failed:\n\t" + e);
+ lastException = e;
+ // check if listening process still alive
+ if (!checkConnectingProcess()) {
+ shouldStop = true;
+ throw new Failure("Break attaching to " + name + " connection: " + "listening process exited");
+ }
+ // sleep between attempts
+ try {
+ Thread.sleep(DebugeeBinder.CONNECT_TRY_DELAY);
+ } catch (InterruptedException ie) {
+ throw new Failure("Thread interrupted while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + ie);
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught IOException while attaching for " + name + " connection to " + host + ":" + port + ":\n\t" + e);
+ }
+
+ if (!shouldStop) {
+ if (socket == null) {
+ throw new Failure("Unable to attach for " + name + " connection to " + host + ":" + port + " for " + timeout + "ms timeout:\n\t"
+ + lastException);
+ }
+
+ onConnected();
+ }
+ }
+
+ /**
+ * Set already bound serverSocket for further connection.
+ */
+ public void setServerSocket(ServerSocket serverSocket) {
+ this.serverSocket = serverSocket;
+ }
+
+ /**
+ * Set already connected socket for connection.
+ */
+ public void setSocket(Socket socket) {
+ this.socket = socket;
+ if (!shouldStop) {
+ onConnected();
+ }
+ }
+
+ /**
+ * Get socket of already established connection.
+ */
+ public Socket getSocket() {
+ return socket;
+ }
+
+ /**
+ * Return true if another connecting process is still alive.
+ */
+ public boolean checkConnectingProcess() {
+ if (connectingProcess == null) {
+ // no process to check
+ return true;
+ }
+ try {
+ int exitCode = connectingProcess.exitValue();
+ } catch (IllegalThreadStateException e) {
+ // process is still alive
+ return true;
+ }
+ // process exited
+ return false;
+ }
+
+ /**
+ * Set another connecting process to control if it is still alive.
+ */
+ public void setConnectingProcess(Process process) {
+ connectingProcess = process;
+ }
+
+ /**
+ * Check if connection is established.
+ */
+ public boolean isConnected() {
+ return connected;
+ }
+
+ /**
+ * Close socket and associated streams.
+ */
+ public void close() {
+ if (!closed) {
+ shouldStop = true;
+ closeConnection();
+ closed = true;
+ }
+ }
+
+ /**
+ * Send the specified byte throw the connection.
+ */
+ public void writeByte(byte b) throws IOException {
+ logger.trace(TRACE_LEVEL_IO, "Writing byte: " + b);
+ sout.write(b);
+ sout.flush();
+ logger.trace(TRACE_LEVEL_IO, "Wrote byte: " + b);
+ }
+
+ /**
+ * Read a byte and return it or -1.
+ */
+ public int readByte() throws IOException {
+ logger.trace(TRACE_LEVEL_IO, "Reading byte");
+ int b = sin.read();
+ logger.trace(TRACE_LEVEL_IO, "Received byte: " + b);
+ return b;
+ }
+
+ /**
+ * Perform some actions after connection established.
+ */
+ protected void onConnected() {
+ if (!shouldStop) {
+ setSocketOptions();
+ makeSocketStreams();
+ connected = true;
+ }
+ }
+
+ /**
+ * Set socket options after connection established.
+ */
+ protected void setSocketOptions() {
+ }
+
+ /**
+ * Close server socket.
+ */
+ protected void closeServerConnection() {
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ logger.trace(TRACE_LEVEL_IO, "ServerSocket closed: " + serverSocket);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing ServerSocket of " + name + " connection:\n\t" + e);
+ }
+ }
+ }
+
+ /**
+ * Close socket of connection to remote host.
+ */
+ protected void closeHostConnection() {
+ if (socket != null) {
+ try {
+ socket.close();
+ logger.trace(TRACE_LEVEL_IO, "Socket closed: " + socket);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing socket of " + name + " connection:\n\t" + e);
+ }
+ }
+ }
+
+ /**
+ * Close socket streams.
+ */
+ protected void closeSocketStreams() {
+ if (sout != null) {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + sout);
+ sout.close();
+ logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + sout);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing OutputStream of " + name + " connection:\n\t" + e);
+ }
+ }
+ if (sin != null) {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + sin);
+ sin.close();
+ logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + sin);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing InputStream of" + name + " connection:\n\t" + e);
+ }
+ }
+ }
+
+ /**
+ * Close sockets and associated streams.
+ */
+ protected void closeConnection() {
+ if (connectionClosed)
+ return;
+
+ logger.trace(TRACE_LEVEL_IO, "Closing " + name + " connection");
+ closeSocketStreams();
+ closeHostConnection();
+ closeServerConnection();
+ connectionClosed = true;
+ }
+
+ /**
+ * Make up socket streams after connection established.
+ */
+ protected void makeSocketStreams() {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Getting input/output socket streams for " + name + " connection");
+ sout = socket.getOutputStream();
+ logger.trace(TRACE_LEVEL_IO, "Got socket output stream: " + sout);
+ sin = socket.getInputStream();
+ logger.trace(TRACE_LEVEL_IO, "Got socket input stream: " + sin);
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e);
+ }
+ }
+
+} // BasicSocketConnection
+
+/**
+ * This class implements connection channel via TCP/IP sockets. After connection
+ * established special inner threads are started, which periodically test the
+ * connection by pinging each other. If ping timeout occurs connection is closed
+ * and any thread waiting for read from this connection gets exception.
+ *
+ * @see #setPingTimeout(long)
+ */
+public class SocketConnection extends BasicSocketConnection {
+
+ private static final long PING_INTERVAL = 1 * 1000; // milliseconds
+
+ private static byte DATA_BYTE = (byte) 0x03;
+
+ private static byte DISCONNECT_BYTE = (byte) 0x04;
+
+ private final Object inLock = new Object();
+ private ObjectInputStream in = null;
+
+ private final Object outLock = new Object();
+ private ObjectOutputStream out = null;
+
+ private volatile long pingTimeout = 0; // don't use ping
+
+ /**
+ * Make an empty connection with specified name.
+ *
+ * @param log
+ * Log object for printing log messages
+ * @param name
+ * connection name
+ */
+ public SocketConnection(Log log, String name) {
+ this(new Log.Logger(log, name + " connection> "), name);
+ }
+
+ /**
+ * Make an empty connection with specified name.
+ *
+ * @param logger
+ * Logger object for printing log messages
+ * @param name
+ * connection name
+ */
+ public SocketConnection(Log.Logger logger, String name) {
+ super(logger, name);
+ }
+
+ /**
+ * Set ping timeout in milliseconds (0 means don't use ping at all).
+ */
+ public void setPingTimeout(long timeout) {
+ logger.display("# WARNING: Setting ping timeout for " + name + " connection ingnored: " + timeout + " ms");
+ pingTimeout = timeout;
+ }
+
+ /**
+ * Returns value of current ping timeout in milliseconds (0 means ping is
+ * not used).
+ */
+ public long getPingTimeout() {
+ return pingTimeout;
+ }
+
+ /**
+ * Receive an object from remote host.
+ */
+ public Object readObject() {
+ if (!isConnected()) {
+ throw new Failure("Unable to read object from not established " + name + " connection");
+ }
+
+ try {
+ return doReadObject();
+ } catch (EOFException e) {
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught Exception while reading an object from " + name + " connection:\n\t" + e);
+ }
+ }
+
+ /**
+ * Send an object to remote host.
+ */
+ public void writeObject(Object object) {
+ if (!isConnected()) {
+ throw new Failure("Unable to send object throw not established " + name + " connection:\n\t" + object);
+ }
+
+ try {
+ doWriteObject(object);
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught IOException while writing an object to " + name + " connection:\n\t" + e);
+ }
+ }
+
+ /**
+ * Close socket and associated streams and finish all internal threads.
+ */
+ public void close() {
+ if (!closed) {
+ // disconnect();
+ shouldStop = true;
+ super.close();
+ closed = true;
+ }
+ }
+
+ /**
+ * Perform some actions after connection has established.
+ */
+ protected void onConnected() {
+ super.onConnected();
+ }
+
+ /**
+ * Do write an object to the connection channel.
+ */
+ private void doWriteObject(Object object) throws IOException {
+ logger.trace(TRACE_LEVEL_IO, "writing object: " + object);
+ synchronized(outLock) {
+ out.writeObject(object);
+ out.flush();
+ }
+ logger.trace(TRACE_LEVEL_PACKETS, "* sent: " + object);
+ }
+
+ /**
+ * Do read an object from the connection channel.
+ */
+ private Object doReadObject() throws IOException, ClassNotFoundException {
+ logger.trace(TRACE_LEVEL_IO, "Reading object");
+ Object object = null;
+ synchronized(inLock) {
+ object = in.readObject();
+ }
+ logger.trace(TRACE_LEVEL_PACKETS, "* recv: " + object);
+ return object;
+ }
+
+ /**
+ * Close socket streams.
+ */
+ protected void closeSocketStreams() {
+ synchronized(outLock) {
+ if (out != null) {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Closing socket output stream: " + out);
+ out.close();
+ logger.trace(TRACE_LEVEL_IO, "Output stream closed: " + out);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing ObjectOutputStream of " + name + " connection:\n\t" + e);
+ }
+ }
+ }
+ synchronized(inLock) {
+ if (in != null) {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Closing socket input stream: " + in);
+ in.close();
+ logger.trace(TRACE_LEVEL_IO, "Input stream closed: " + in);
+ } catch (IOException e) {
+ logger.display("# WARNING: " + "Caught IOException while closing ObjectInputStream of" + name + " connection:\n\t" + e);
+ }
+ }
+ }
+ super.closeSocketStreams();
+ }
+
+ /**
+ * Close sockets and associated streams.
+ */
+ protected void closeConnection() {
+ if (connectionClosed)
+ return;
+ connected = false;
+ shouldStop = true;
+ super.closeConnection();
+ }
+
+ /**
+ * Make up object streams for socket.
+ */
+ protected void makeSocketStreams() {
+ try {
+ logger.trace(TRACE_LEVEL_IO, "Making input/output object streams for " + name + " connection");
+ synchronized(outLock) {
+ out = new ObjectOutputStream(socket.getOutputStream());
+ out.flush();
+ }
+ logger.trace(TRACE_LEVEL_IO, "Output stream created: " + out);
+ synchronized(inLock) {
+ in = new ObjectInputStream(socket.getInputStream());
+ }
+ logger.trace(TRACE_LEVEL_IO, "Input stream created: " + in);
+ } catch (IOException e) {
+ e.printStackTrace(logger.getOutStream());
+ throw new Failure("Caught exception while making streams for " + name + " connection:\n\t" + e);
+ }
+ }
+
+} // SocketConnection
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketIOPipe.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jpda;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import nsk.share.*;
+
+/*
+ * This class represents communication channel based on TCP/IP sockets.
+ * Usage of this class implies creation of objects of 2 types: server SocketIOPipe object
+ * (this object creates server socket and waits for incoming connection) and client
+ * SocketIOPipe (this object attaches to server).
+ *
+ * Server and client objects should be created using special static methods provided by this class,
+ * for example 'createServerIOPipe(Log log, int port, long timeout)' for server SocketIOPipe
+ * and 'createClientIOPipe(Log log, String host, int port, long timeout)' for client SocketIOPipe.
+ *
+ * When SocketIOPipe is created it can be used to send and receive strings using methods 'readln()' and 'println(String s)'.
+ * TCP/IP connection is established at the first attempt to read or write data.
+ *
+ * For example, if client process should send string 'OK' to the server process which is run
+ * at the host 'SERVER_HOST' following code can be written:
+ *
+ * Server side:
+ *
+ * // SocketIOPipe creates ServerSocket listening given port
+ * SocketIOPipe pipe = SocketIOPipe.createServerIOPipe(log, port, timeoutValue);
+ *
+ * // SocketIOPipe waits connection from client and reads data sent by the client
+ * String command = pipe.readln();
+ *
+ * Client side:
+ *
+ * // initialize SocketIOPipe with given values of server host name and port
+ * SocketIOPipe pipe = SocketIOPipe.createClientIOPipe(log, 'SERVER_HOST', port, timeoutValue);
+ *
+ * String command = "OK";
+ * // SocketIOPipe tries to create socket and send command to the server
+ * pipe.println(command);
+ *
+ */
+public class SocketIOPipe extends Log.Logger implements Finalizable {
+
+ public static final int DEFAULT_TIMEOUT_VALUE = 1 * 60 * 1000;
+
+ public static final String DEFAULT_PIPE_LOG_PREFIX = "SocketIOPipe> ";
+
+ protected boolean listening;
+
+ protected String host;
+
+ protected int port;
+
+ protected long timeout;
+
+ protected SocketConnection connection;
+
+ protected volatile boolean shouldStop;
+
+ protected Process connectingProcess;
+
+ protected ServerSocket serverSocket;
+
+ protected String name;
+
+ /**
+ * Make general <code>IOPipe</code> object with specified parameters.
+ */
+ protected SocketIOPipe(String name, Log log, String logPrefix, String host, int port, long timeout, boolean listening) {
+ super(log, logPrefix);
+ this.host = host;
+ this.port = port;
+ this.timeout = timeout;
+ this.listening = listening;
+ this.name = name;
+ }
+
+ /**
+ * Make general <code>IOPipe</code> object with specified parameters.
+ */
+ protected SocketIOPipe(Log log, String logPrefix, String host, int port, long timeout, boolean listening) {
+ super(log, logPrefix);
+ this.host = host;
+ this.port = port;
+ this.timeout = timeout;
+ this.listening = listening;
+ }
+
+ /**
+ * Create listening SocketIOPipe using given port
+ */
+ public static SocketIOPipe createServerIOPipe(Log log, int port, long timeout) {
+ SocketIOPipe pipe = new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, null, 0, timeout, true);
+
+ try {
+ ServerSocket ss = new ServerSocket();
+ if (port == 0) {
+ // Only need SO_REUSEADDR if we're using a fixed port. If we
+ // start seeing EADDRINUSE due to collisions in free ports
+ // then we should retry the bind() a few times.
+ ss.setReuseAddress(false);
+ }
+ ss.bind(new InetSocketAddress(port));
+ pipe.setServerSocket(ss);
+ } catch (IOException e) {
+ e.printStackTrace(log.getOutStream());
+ throw new Failure("Caught IOException while binding for IOPipe connection: \n\t" + e);
+ }
+
+ return pipe;
+ }
+
+ /**
+ * Create listening SocketIOPipe using any free port
+ */
+ public static SocketIOPipe createServerIOPipe(Log log, long timeout) {
+ return createServerIOPipe(log, 0, timeout);
+ }
+
+ /**
+ * Create attaching SocketIOPipe using given port and timeout
+ */
+ public static SocketIOPipe createClientIOPipe(Log log, String host, int port, long timeout) {
+ return new SocketIOPipe(log, DEFAULT_PIPE_LOG_PREFIX, host, port, timeout, false);
+ }
+
+ /**
+ * Return true if <code>IOPipe</code> connection established.
+ */
+ public boolean isConnected() {
+ return (connection != null && connection.isConnected());
+ }
+
+ /**
+ * Returns port number used by SocketIOPipe
+ */
+ public int getPort() {
+ return port;
+ }
+
+ protected void setConnectingProcess(Process connectingProcess) {
+ this.connectingProcess = connectingProcess;
+ }
+
+ protected void setServerSocket(ServerSocket serverSocket) {
+ this.serverSocket = serverSocket;
+ if (serverSocket != null)
+ port = serverSocket.getLocalPort();
+ }
+
+ /**
+ * Write (and flush) given <code>line</code> to this
+ * <code>IOPipe</code> cnannel.
+ *
+ * @throws Failure if error occured while sending data
+ */
+ public void println(String line) {
+ if (connection == null) {
+ connect();
+ }
+ connection.writeObject(line);
+ }
+
+ /**
+ * Read a text line from this <code>IOPipe</code> channel,
+ * or return <i>null</i> if EOF reached.
+ *
+ * @throws Failure if error occured while reading data
+ */
+ public String readln() {
+ if (connection == null) {
+ connect();
+ }
+ String line = (String) connection.readObject();
+ return line;
+ }
+
+ /**
+ * Close this <code>IOPipe</code> connection.
+ */
+ public void close() {
+ shouldStop = true;
+ if (connection != null) {
+ connection.close();
+ }
+ }
+
+ /**
+ * Establish <code>IOPipe</code> connection by attaching or accepting
+ * connection appropriately.
+ */
+ protected void connect() {
+ if (connection != null) {
+ throw new TestBug("IOPipe connection is already established");
+ }
+
+ if (shouldStop)
+ return;
+
+ connection = new SocketConnection(this, getName());
+
+ if (listening) {
+ connection.setConnectingProcess(connectingProcess);
+ if (serverSocket == null) {
+ connection.bind(port, timeout);
+ } else {
+ connection.setServerSocket(serverSocket);
+ }
+
+ if (shouldStop)
+ return;
+
+ // wait for connection from remote host
+ connection.accept(timeout);
+
+ } else {
+ // attach from the debuggee's side
+ connection.continueAttach(host, port, timeout);
+ }
+ }
+
+ /**
+ * Set ping timeout in milliseconds (0 means don't use ping at all).
+ */
+ public void setPingTimeout(long timeout) {
+ if (connection == null) {
+ throw new TestBug("Attempt to set ping timeout for not established connection");
+ }
+ connection.setPingTimeout(timeout);
+ }
+
+ /**
+ * Returns value of current ping timeout in milliseconds (0 means ping is not used).
+ */
+ public long getPingTimeout() {
+ if (connection == null) {
+ throw new TestBug("Attempt to get ping timeout for not established connection");
+ }
+ return connection.getPingTimeout();
+ }
+
+ /**
+ * Perform finalization of the object by invoking close().
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ /**
+ * Perform finalization of the object at exit by invoking finalize().
+ */
+ public void finalizeAtExit() throws Throwable {
+ finalize();
+ }
+
+ /**
+ * Field 'pipeCounter' and method 'getNextPipeNumber' are used to construct unique names for SocketIOPipes
+ */
+ private static int pipeCounter;
+
+ private synchronized int getNextPipeNumber() {
+ return pipeCounter++;
+ }
+
+ /**
+ * Construct name for SocketIOPipe if it wasn't specified
+ */
+ private String getName() {
+ if (name == null) {
+ name = "SocketIOPipe-" + getNextPipeNumber();
+ }
+
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/StateTestThread.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.jpda;
+
+import nsk.share.TestBug;
+import nsk.share.locks.MonitorLockingThread;
+
+/*
+ * StateTestThread sequentially switches its state in following order:
+ * - thread not started
+ * - thread is running
+ * - thread is sleeping
+ * - thread in Object.wait()
+ * - thread wait on java monitor
+ * - thread is finished
+ *
+ * To use this class create new instance of StateTestThread and sequentially call method nextState().
+ */
+public class StateTestThread extends Thread {
+ // thread states available through ThreadReference.state()
+ public static String stateTestThreadStates[] = { "UNKNOWN", "RUNNING", "SLEEPING", "WAIT", "MONITOR", "ZOMBIE" };
+
+ private Object waitOnObject = new Object();
+
+ public StateTestThread(String name) {
+ super(name);
+ }
+
+ private volatile boolean isRunning;
+
+ private volatile boolean waitState;
+
+ public int getCurrentState() {
+ return currentState;
+ }
+
+ private MonitorLockingThread auxiliaryThread = new MonitorLockingThread(this);
+
+ private boolean isExecutedWithErrors;
+
+ private volatile boolean readyToBeBlocked;
+
+ private String errorMessage;
+
+ public void run() {
+ isRunning = true;
+
+ // running state
+ while (isRunning)
+ ;
+
+ try {
+ // sleeping state
+ sleep(Long.MAX_VALUE);
+ } catch (InterruptedException e) {
+ // expected exception
+ }
+
+ synchronized (waitOnObject) {
+ try {
+ // wait state
+ while (waitState)
+ waitOnObject.wait();
+ } catch (InterruptedException e) {
+ isExecutedWithErrors = true;
+ errorMessage = "StateTestThread was unexpected interrupted during waiting";
+ }
+ }
+
+ // start auxiliary thread which should acquire 'this' lock
+ auxiliaryThread.acquireLock();
+
+ readyToBeBlocked = true;
+
+ // try acquire the same lock as auxiliaryThread, switch state to 'wait on monitor'
+ synchronized (this) {
+
+ }
+ }
+
+ private int currentState = 1;
+
+ public void nextState() {
+ // check is thread states change as expected
+ if (isExecutedWithErrors)
+ throw new TestBug(errorMessage);
+
+ switch (currentState++) {
+ case 1:
+ // start thread
+ start();
+
+ while (!isRunning)
+ yield();
+
+ break;
+ case 2:
+ // stop running
+ isRunning = false;
+
+ while (this.getState() != Thread.State.TIMED_WAITING)
+ yield();
+
+ break;
+ case 3:
+ waitState = true;
+
+ // stop sleeping
+ interrupt();
+
+ while (getState() != Thread.State.WAITING)
+ yield();
+
+ break;
+ case 4:
+ waitState = false;
+
+ // stop wait
+ synchronized (waitOnObject) {
+ waitOnObject.notify();
+ }
+
+ while (!readyToBeBlocked || (getState() != Thread.State.BLOCKED))
+ yield();
+
+ break;
+ case 5:
+ // let StateTestThread thread acquire lock
+ auxiliaryThread.releaseLock();
+ try {
+ join();
+ } catch (InterruptedException e) {
+ throw new TestBug("Unexpected exception: " + e);
+ }
+ break;
+
+ default:
+ throw new TestBug("Invalid thread state");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import nsk.share.*;
+
+/*
+ * DeadlockLocker - class used for deadlock creation
+ *
+ * To create deadlock second 'inner' instance of DeadlockLocker is required.
+ *
+ * Deadlock creation scenario:
+ * - object acquires its resource
+ * - notify 'inner' through Wicket step1 that resource is locked and 'inner' can try to acquire this object's resource
+ * - wait notification through Wicket step2 from 'inner' that 'inner' acquired its resource
+ * - call readyWicket.unlock to notify thread waiting deadlock creation
+ * - try acquire locked inner's resource, at the same time inner trying to acquire locked this object's resource - deadlock is created
+ *
+ * Subclasses should implement method doLock() taking in account described scenario.
+ *
+ * Objects of DeadlockLocker should not be created directly, to create deadlocked threads use class DeadlockMaker
+ */
+abstract public class DeadlockLocker {
+ protected DeadlockLocker inner;
+
+ protected Wicket step1;
+
+ protected Wicket step2;
+
+ // 'readyWicket' is used to notify DeadlockMacker that deadlock is almost created
+ protected Wicket readyWicket;
+
+ public DeadlockLocker(Wicket step1, Wicket step2, Wicket readyWicket) {
+ this.step1 = step1;
+ this.step2 = step2;
+ this.readyWicket = readyWicket;
+ }
+
+ public void setInner(DeadlockLocker inner) {
+ this.inner = inner;
+ }
+
+ protected void checkInnerLocker() {
+ if (inner == null) {
+ throw new IllegalStateException(getClass().getName() + " deadlockLocker's inner locker is null");
+ }
+ }
+
+ protected abstract void doLock();
+
+ abstract public Object getLock();
+
+ private int lockCount;
+
+ final public void lock() {
+ // call this method once
+ if (lockCount++ > 1)
+ return;
+
+ // check that inner locker was set
+ checkInnerLocker();
+
+ doLock();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockMaker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import java.util.*;
+import nsk.share.TestBug;
+import nsk.share.Wicket;
+
+/*
+ * Class used to create deadlocked threads. It is possible create 2 or more deadlocked thread, also
+ * is is possible to specify resource of which type should lock each deadlocked thread
+ */
+public class DeadlockMaker {
+ // create deadlock with 2 threads
+ // lockType1 and lockType2 - type of locking resources used for deadlock creation
+ public static DeadlockedThread[] createDeadlockedThreads(LockType lockType1, LockType lockType2) {
+ DeadlockedThread[] resultThreads = new DeadlockedThread[2];
+
+ Wicket step1 = new Wicket();
+ Wicket step2 = new Wicket();
+
+ Wicket readyWicket = new Wicket(2);
+
+ DeadlockLocker locker1 = createLocker(lockType1, step1, step2, readyWicket);
+ DeadlockLocker locker2 = createLocker(lockType2, step2, step1, readyWicket);
+ locker1.setInner(locker2);
+ locker2.setInner(locker1);
+
+ resultThreads[0] = new DeadlockedThread(locker1);
+ resultThreads[1] = new DeadlockedThread(locker2);
+
+ resultThreads[0].start();
+ resultThreads[1].start();
+
+ readyWicket.waitFor();
+
+ // additional check to be sure that all threads really blocked
+ waitForDeadlock(resultThreads);
+
+ return resultThreads;
+ }
+
+ // create deadlock with several threads
+ // locksTypes - type of locking resources used for deadlock creation
+ public static DeadlockedThread[] createDeadlockedThreads(List<LockType> locksTypes) {
+ if (locksTypes.size() < 2) {
+ throw new IllegalArgumentException("Need at least 2 threads for deadlock");
+ }
+
+ int threadsNumber = locksTypes.size();
+
+ DeadlockedThread[] resultThreads = new DeadlockedThread[threadsNumber];
+
+ Wicket readyWicket = new Wicket(threadsNumber);
+
+ DeadlockLocker deadlockLockers[] = new DeadlockLocker[threadsNumber];
+ Wicket stepWickets[] = new Wicket[threadsNumber];
+
+ for (int i = 0; i < threadsNumber; i++)
+ stepWickets[i] = new Wicket();
+
+ int index1 = 0;
+ int index2 = 1;
+ for (int i = 0; i < threadsNumber; i++) {
+ Wicket step1 = stepWickets[index1];
+ Wicket step2 = stepWickets[index2];
+
+ deadlockLockers[i] = createLocker(locksTypes.get(i), step1, step2, readyWicket);
+
+ if (i > 0)
+ deadlockLockers[i - 1].setInner(deadlockLockers[i]);
+
+ index1 = (index1 + 1) % threadsNumber;
+ index2 = (index2 + 1) % threadsNumber;
+ }
+ deadlockLockers[threadsNumber - 1].setInner(deadlockLockers[0]);
+
+ for (int i = 0; i < threadsNumber; i++) {
+ resultThreads[i] = new DeadlockedThread(deadlockLockers[i]);
+ resultThreads[i].start();
+ }
+
+ readyWicket.waitFor();
+
+ // additional check to be sure that all threads really blocked
+ waitForDeadlock(resultThreads);
+
+ return resultThreads;
+ }
+
+ /*
+ * Wait when thread state will change to be sure that deadlock is really created
+ */
+ static private void waitForDeadlock(DeadlockedThread[] threads) {
+ Set<Thread.State> targetStates = new HashSet<Thread.State>();
+
+ // thread is waiting for a monitor lock to enter a synchronized block/method
+ targetStates.add(Thread.State.BLOCKED);
+
+ // thread calls LockSupport.park
+ targetStates.add(Thread.State.WAITING);
+
+ // thread calls LockSupport.parkNanos or LockSupport.parkUntil
+ targetStates.add(Thread.State.TIMED_WAITING);
+
+ for (Thread thread : threads) {
+ while (!targetStates.contains(thread.getState())) {
+ sleep(100);
+ }
+ }
+ }
+
+ static private void sleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ System.out.println("Unexpected exception: " + e);
+ e.printStackTrace(System.out);
+
+ TestBug testBugException = new TestBug("Unexpected exception was throw: " + e);
+ testBugException.initCause(e);
+ throw testBugException;
+ }
+ }
+
+ // create locker with given type
+ public static DeadlockLocker createLocker(LockType type, Wicket step1, Wicket step2, Wicket readyWicket) {
+ switch (type) {
+ case SYNCHRONIZED_METHOD:
+ return new SynchronizedMethodLocker(step1, step2, readyWicket);
+ case SYNCHRONIZED_BLOCK:
+ return new SynchronizedBlockLocker(step1, step2, readyWicket);
+ case REENTRANT_LOCK:
+ return new ReentrantLockLocker(step1, step2, readyWicket);
+ case JNI_LOCK:
+ return new JNIMonitorLocker(step1, step2, readyWicket);
+ }
+
+ throw new IllegalArgumentException("Unsupported lock type: " + type);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/DeadlockedThread.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import nsk.share.Wicket;
+
+/*
+ * Thread class used for deadlock creation, requires instance of DeadlockLocker to created deadlock.
+ * Objects of DeadlockedThread should not be created directly, to create deadlocked threads
+ * use class DeadlockMaker
+ */
+public class DeadlockedThread extends Thread {
+ private DeadlockLocker locker;
+
+ private Wicket dedlockResolutionWicket = new Wicket();
+
+ // should call readyWicket.unlock() when deadlock is ready
+ public DeadlockedThread(DeadlockLocker locker) {
+ this.locker = locker;
+ }
+
+ public void run() {
+ locker.lock();
+
+ // reach here if deadlock was resolved
+ dedlockResolutionWicket.unlockAll();
+
+ // sleep if deadlock was resolved
+ try {
+ sleep(Long.MAX_VALUE);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ // If it is expected that deadlock with using of this DeadlockedThread should be resolved
+ // this method can be used for waiting this event
+ public void waitDeadlockResolution() {
+ // if deadlock was resolved DeadlockedThread calls dedlockResolutionWicket.unlockAll()
+ dedlockResolutionWicket.waitFor();
+ }
+
+ public DeadlockLocker getLocker() {
+ return locker;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include "jni.h"
+#include "nsk_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_PTR
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG_2(x, y) y
+#define JNI_ENV_ARG_3(x, y, z) y, z
+#define JNI_ENV_ARG_4(x, y, z. a) y, z, a
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG_2(x,y) x, y
+#define JNI_ENV_ARG_3(x, y, z) x, y, z
+#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+JNIEXPORT void JNICALL
+Java_nsk_share_locks_JNIMonitorLocker_doLock(JNIEnv *env, jobject thisObject)
+{
+/*
+This method executes JNI analog for following Java code:
+
+ JNI_MonitorEnter(this);
+
+ step1.unlockAll();
+ step2.waitFor();
+ readyWicket.unlock();
+ inner.lock();
+
+ JNI_MonitorExit(this);
+*/
+ jint success;
+ jfieldID field;
+ jclass thisObjectClass;
+
+ // fields 'step1' and 'step2'
+ jobject wicketObject;
+
+ // class for fields 'step1', 'step2', 'readyWicket'
+ jclass wicketClass;
+
+ // field 'inner'
+ jobject innerObject;
+
+ // class for field 'inner'
+ jclass deadlockLockerClass;
+
+ success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero"));
+ }
+
+ thisObjectClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, thisObject));
+
+ // step1.unlockAll()
+ field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "step1", "Lnsk/share/Wicket;"));
+
+ wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field));
+ wicketClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, wicketObject));
+
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "unlockAll", "()V"))));
+
+ // step2.waitFor()
+ field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "step2", "Lnsk/share/Wicket;"));
+ wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field));
+
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "waitFor", "()V"))));
+
+ // readyWicket.unlock()
+ field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "readyWicket", "Lnsk/share/Wicket;"));
+ wicketObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field));
+
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, wicketObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, wicketClass, "unlock", "()V"))));
+
+ // inner.lock()
+ field = JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG_4(env, thisObjectClass, "inner", "Lnsk/share/locks/DeadlockLocker;"));
+ innerObject = JNI_ENV_PTR(env)->GetObjectField(JNI_ENV_ARG_3(env, thisObject, field));
+ deadlockLockerClass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, innerObject));
+
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, innerObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, deadlockLockerClass, "lock", "()V"))));
+
+ success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, thisObject));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero"));
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/JNIMonitorLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import nsk.share.Consts;
+import nsk.share.Wicket;
+
+/*
+ * Class used for deadlock creation, acquires lock using JNI MonitorEnter
+ */
+public class JNIMonitorLocker extends DeadlockLocker {
+ static {
+ try {
+ System.loadLibrary("JNIMonitorLocker");
+ } catch (UnsatisfiedLinkError e) {
+ System.out.println("Unexpected UnsatisfiedLinkError on loading library 'JNIMonitorLocker'");
+ e.printStackTrace(System.out);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+
+ public JNIMonitorLocker(Wicket step1, Wicket step2, Wicket readyWicket) {
+ super(step1, step2, readyWicket);
+ }
+
+ public Object getLock() {
+ return this;
+ }
+
+ protected native void doLock();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockType.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+/*
+ * Types of resources used for deadlock creation
+ */
+public enum LockType
+{
+ SYNCHRONIZED_METHOD,
+ SYNCHRONIZED_BLOCK,
+ REENTRANT_LOCK,
+ JNI_LOCK
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include "jni.h"
+#include "nsk_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_PTR
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG_2(x, y) y
+#define JNI_ENV_ARG_3(x, y, z) y, z
+#define JNI_ENV_ARG_4(x, y, z, a) y, z, a
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG_2(x,y) x, y
+#define JNI_ENV_ARG_3(x, y, z) x, y, z
+#define JNI_ENV_ARG_4(x, y, z, a) x, y, z, a
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+JNIEXPORT void JNICALL
+Java_nsk_share_locks_LockingThread_nativeJNIMonitorEnter(JNIEnv *env, jobject thisObject, jobject object)
+{
+ jint success;
+ jclass klass;
+
+ success = JNI_ENV_PTR(env)->MonitorEnter(JNI_ENV_ARG_2(env, object));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorEnter return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorEnter return non-zero"));
+ }
+
+ klass = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG_2(env, thisObject));
+
+ JNI_ENV_PTR(env)->CallVoidMethod(JNI_ENV_ARG_3(env, thisObject, JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG_4(env, klass, "createStackFrame", "()V"))));
+
+ success = JNI_ENV_PTR(env)->MonitorExit(JNI_ENV_ARG_2(env, object));
+
+ if(success != 0)
+ {
+ NSK_COMPLAIN1("MonitorExit return non-zero: %d\n", success);
+
+ JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG_3(env, JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG_2(env, "nsk/share/TestJNIError")), "MonitorExit return non-zero"));
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/LockingThread.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
+
+import nsk.share.Consts;
+import nsk.share.Log;
+import nsk.share.TestBug;
+import nsk.share.TestJNIError;
+import nsk.share.Wicket;
+
+/*
+ Thread with possibility acquiring monitors in different ways:
+ - entering synchronized method
+ - entering synchronized method for thread object itself
+ - entering synchronized static method
+ - entering synchronized method for thread class itself
+ - entering synchronized block on non-static object
+ - entering synchronized block on non-static on thread object itself
+ - entering synchronized block on static object
+ - entering synchronized block on static thread object itself
+ - JNI MonitorEnter.
+
+ Description of required thread stack should be passed to LockingThread in constructor.
+ When started locking thread create required stack and sleep until not interrupted.
+
+ LockingThread can relinquish acquired monitors in follows ways:
+ - relinquish single monitor through Object.wait - relinquishMonitor(int monitorIndex),
+ - relinquish single monitor through exiting from synchronized blocks/methods or through JNI MonitorExit - exitSingleFrame(),
+ - relinquish all monitors(exit from all synchronized blocks/methods) - stopLockingThread()
+
+ Debug information about each acquired/relinquished monitor is stored and can be obtained through getMonitorsInfo().
+
+ To be sure that LockingThread have reached required state call method LockingThread.waitState().
+
+ Usage example:
+
+ List<String> stackFramesDescription = new ArrayList<String>();
+ stackFramesDescription.add(LockingThread.SYNCHRONIZED_METHOD);
+ stackFramesDescription.add(LockingThread.SYNCHRONIZED_OBJECT_BLOCK);
+
+ LockingThread lockingThread = new LockingThread(log, stackFramesDescription);
+
+ lockingThread.start();
+
+ // after calling waitState() LockingThread should complete stack creation
+ lockingThread.waitState();
+
+ lockingThread.exitSingleFrame();
+
+ // after calling waitState() LockingThread should complete exit from stack frame
+ lockingThread.waitState();
+ */
+public class LockingThread extends Thread {
+ // native part uses TestJNIError class
+ private static final Class<?> jniErrorKlass = TestJNIError.class;
+ static {
+ try {
+ System.loadLibrary("LockingThread");
+ } catch (UnsatisfiedLinkError e) {
+ System.out.println("Unexpected UnsatisfiedLinkError on loading library 'LockingThread'");
+ e.printStackTrace(System.out);
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
+ }
+ }
+
+ /*
+ * Information about acquired monitor
+ */
+ public static class DebugMonitorInfo {
+ public DebugMonitorInfo(Object monitor, int stackDepth, Thread thread, boolean isNative) {
+ this.monitor = monitor;
+ this.stackDepth = stackDepth;
+ this.thread = thread;
+ this.isNative = isNative;
+ }
+
+ public Object monitor;
+
+ public int stackDepth;
+
+ public Thread thread;
+
+ boolean isNative;
+ }
+
+ // acquire JNI monitor through JNIMonitorEnter()
+ public static final String JNI_MONITOR_ENTER = "JNI_MONITOR_ENTER";
+
+ // entering synchronized static method
+ public static final String SYNCHRONIZED_STATIC_METHOD = "SYNCHRONIZED_STATIC_METHOD";
+
+ // entering synchronized static method for thread class itself
+ public static final String SYNCHRONIZED_STATIC_THREAD_METHOD = "SYNCHRONIZED_STATIC_THREAD_METHOD";
+
+ // entering synchronized method
+ public static final String SYNCHRONIZED_METHOD = "SYNCHRONIZED_METHOD";
+
+ // entering synchronized method for thread object itself
+ public static final String SYNCHRONIZED_THREAD_METHOD = "SYNCHRONIZED_THREAD_METHOD";
+
+ // entering synchronized block for thread object itself
+ public static final String SYNCHRONIZED_THIS_BLOCK = "SYNCHRONIZED_THIS_BLOCK";
+
+ // entering synchronized block
+ public static final String SYNCHRONIZED_OBJECT_BLOCK = "SYNCHRONIZED_OBJECT_BLOCK";
+
+ // entering synchronized block on static object
+ public static final String SYNCHRONIZED_BLOCK_STATIC_OBJECT = "SYNCHRONIZED_BLOCK_STATIC_OBJECT";
+
+ // entering synchronized block on static thread object itself
+ public static final String SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT = "SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT";
+
+ // entering frame without monitor acquiring
+ public static final String FRAME_WITHOUT_LOCK = "FRAME_WITHOUT_LOCK";
+
+ // all acquired monitors
+ private List<DebugMonitorInfo> monitorsInfo = new ArrayList<DebugMonitorInfo>();
+
+ // This parameter should be passed in constructor
+ // It describe how many locks and in which way LockingThread should acquire
+ private List<String> stackFramesDescription;
+
+ private Log log;
+
+ // is during LockingThread's operations any errors occurred
+ private boolean executedWithErrors;
+
+ public boolean isExecutedWithErrors() {
+ return executedWithErrors;
+ }
+
+ public LockingThread(Log log, List<String> stackFramesDescription) {
+ this.log = log;
+ this.stackFramesDescription = stackFramesDescription;
+ }
+
+ // return array containing all acquired monitors
+ public DebugMonitorInfo[] getMonitorsInfo(boolean returnJNIMonitors) {
+ Map<Object, DebugMonitorInfo> result = new HashMap<Object, DebugMonitorInfo>();
+
+ for (int i = monitorsInfo.size() - 1; i >= 0; i--) {
+ DebugMonitorInfo monitorInfo = monitorsInfo.get(i);
+
+ if ((returnJNIMonitors || !monitorInfo.isNative) &&
+
+ // don't return relinquished monitors
+ (monitorInfo.monitor != relinquishedMonitor) &&
+
+ // return only last monitor occurrence
+ !result.containsKey(monitorInfo.monitor)) {
+ result.put(monitorInfo.monitor, monitorInfo);
+ }
+ }
+
+ return result.values().toArray(new DebugMonitorInfo[] {});
+ }
+
+ void log(String message) {
+ log.display(Thread.currentThread().getName() + ": " + message);
+ }
+
+ // add debug information about acquired monitor
+ void addMonitorInfo(DebugMonitorInfo monitorInfo) {
+ monitorsInfo.add(monitorInfo);
+ }
+
+ // remove debug information about acquired monitor (also should update information about stack depth)
+ void removeMonitorInfo(DebugMonitorInfo removedMonitor) {
+ for (DebugMonitorInfo monitor : monitorsInfo) {
+ if (monitor.stackDepth > removedMonitor.stackDepth)
+ monitor.stackDepth -= 2;
+ }
+
+ monitorsInfo.remove(removedMonitor);
+ }
+
+ // used for stack frames creation
+ private int currentIndex;
+
+ // Recursive function used for stack frames creation
+
+ // For example if LockingThread should acquire 1 monitor through synchronized block
+ // and 1 monitor through synchronized method pass list with values SYNCHRONIZED_METHOD and SYNCHRONIZED_OBJECT_BLOCK
+ // to the constructor and after running LockingThread will have following stack frames:
+
+ // run()
+ // createStackFrame()
+ // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here
+ // createStackFrame()
+ // synchronizedObjectBlock() // monitor for instance of Object is acquired here
+ // createStackFrame()
+ // doWait()
+ // sleep()
+
+ // When LockingThread have created required stack frame it calls method doWait() and sleep(Long.MAX_VALUE)
+
+ // If LockingThread should relinquish one of the acquired monitors it should be interrupted and after
+ // interrupting should call 'wait()' for specified monitor, and for this example LockingThread will have
+ // following stack frames:
+
+ // run()
+ // createStackFrame()
+ // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here
+ // createStackFrame()
+ // synchronizedObjectBlock() // monitor for instance of Object is acquired here
+ // createStackFrame()
+ // doWait()
+ // relinquishedMonitor.wait()
+
+ // LockingThread still holds all other locks because of it didn't exit from corresponding synchronized methods and blocks.
+ // To let LockingThread acquire relinquished monitor 'relinquishedMonitor.notifyAll()' should be called, after this
+ // LockingThread will acquire this monitor again because of it still in corresponding synchronized method or block and
+ // it will have again such stack frames:
+
+ // run()
+ // createStackFrame()
+ // ClassWithSynchronizedMethods().synchronizedMethod() // monitor for instance of ClassWithSynchronizedMethods is acquired here
+ // createStackFrame()
+ // synchronizedObjectBlock() // monitor for instance of Object is acquired here
+ // createStackFrame()
+ // doWait()
+ // sleep()
+ void createStackFrame() {
+ if (currentIndex < stackFramesDescription.size()) {
+ String frameDescription = stackFramesDescription.get(currentIndex);
+
+ currentIndex++;
+
+ if (frameDescription.equals(JNI_MONITOR_ENTER)) {
+ // for JNI monitors -1 is returned as stack depth
+ int currentStackDepth = -1;
+ Object object = new Object();
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(object, currentStackDepth, this, true);
+ addMonitorInfo(monitorInfo);
+ log("Enter JNI monitor");
+ nativeJNIMonitorEnter(object);
+ log("Exit JNI monitor");
+ removeMonitorInfo(monitorInfo);
+ } else if (frameDescription.equals(SYNCHRONIZED_BLOCK_STATIC_OBJECT)) {
+ synchronizedBlockStaticObject();
+ } else if (frameDescription.equals(SYNCHRONIZED_BLOCK_STATIC_THREAD_OBJECT)) {
+ synchronizedBlockStaticThreadObject();
+ } else if (frameDescription.equals(SYNCHRONIZED_METHOD)) {
+ new ClassWithSynchronizedMethods().synchronizedMethod(this);
+ } else if (frameDescription.equals(SYNCHRONIZED_THREAD_METHOD)) {
+ synchronizedMethod();
+ } else if (frameDescription.equals(SYNCHRONIZED_STATIC_METHOD)) {
+ ClassWithSynchronizedMethods.synchronizedStaticMethod(this);
+ } else if (frameDescription.equals(SYNCHRONIZED_STATIC_THREAD_METHOD)) {
+ synchronizedStaticMethod(this);
+ } else if (frameDescription.equals(SYNCHRONIZED_THIS_BLOCK)) {
+ synchronizedThisBlock();
+ } else if (frameDescription.equals(SYNCHRONIZED_OBJECT_BLOCK)) {
+ synchronizedObjectBlock();
+ } else if (frameDescription.equals(FRAME_WITHOUT_LOCK)) {
+ frameWithoutLock();
+ } else
+ throw new TestBug("Invalid stack frame description: " + frameDescription);
+ } else {
+ // required stack is created
+ ready();
+ doWait();
+ }
+
+ if (exitSingleFrame) {
+ if (currentIndex-- < stackFramesDescription.size()) {
+ // exit from single synchronized block/method
+ ready();
+ doWait();
+ }
+ }
+ }
+
+ public Object getRelinquishedMonitor() {
+ return relinquishedMonitor;
+ }
+
+ private Object relinquishedMonitor;
+
+ private Wicket waitStateWicket = new Wicket();
+
+ private Thread.State requiredState;
+
+ public void waitState() {
+ // try wait with timeout to avoid possible hanging (if LockingThread have finished execution because of uncaught exception)
+ int result = waitStateWicket.waitFor(60000);
+
+ if (result != 0) {
+ throw new TestBug("Locking thread can't reach required state (waitStateWicket wasn't unlocked)");
+ }
+
+ if (requiredState == null)
+ throw new TestBug("Required state not specified");
+
+ long startTime = System.currentTimeMillis();
+
+ // additional check to be sure that LockingThread acquired state
+ while (this.getState() != requiredState) {
+
+ // try wait with timeout to avoid possible hanging if something will go wrong
+ if ((System.currentTimeMillis() - startTime) > 60000) {
+ throw new TestBug("Locking thread can't reach required state (state: " + requiredState + " wasn't reached) in 1 minute");
+ }
+
+ yield();
+ }
+
+ requiredState = null;
+
+ Object relinquishedMonitor = getRelinquishedMonitor();
+ /*
+ * Changing thread state and release of lock is not single/atomic operation.
+ * As result there is a potential race when thread state (LockingThread) has
+ * been changed but the lock has not been released yet. To avoid this current
+ * thread is trying to acquire the same monitor, so current thread proceeds
+ * execution only when monitor has been really relinquished by LockingThread.
+ */
+ if (relinquishedMonitor != null) {
+ synchronized (relinquishedMonitor) {
+ }
+ }
+ }
+
+ // LockingThread acquired required state
+ private void ready() {
+ waitStateWicket.unlockAll();
+ }
+
+ // is LockingThread should relinquish single monitor
+ private volatile boolean relinquishMonitor;
+
+ private int relinquishedMonitorIndex;
+
+ // relinquish single monitor with given index through Object.wait()
+ public void relinquishMonitor(int index) {
+ if (index >= monitorsInfo.size()) {
+ throw new TestBug("Invalid monitor index: " + index);
+ }
+
+ requiredState = Thread.State.WAITING;
+ waitStateWicket = new Wicket();
+ relinquishMonitor = true;
+ relinquishedMonitorIndex = index;
+
+ interrupt();
+
+ DebugMonitorInfo monitorInfo = monitorsInfo.get(relinquishedMonitorIndex);
+
+ if (monitorInfo == null)
+ throw new TestBug("Invalid monitor index: " + relinquishedMonitorIndex);
+ }
+
+ public void acquireRelinquishedMonitor() {
+ if (relinquishedMonitor == null) {
+ throw new TestBug("There is no relinquished monitor");
+ }
+
+ // Set requiredState to 'Thread.State.TIMED_WAITING' because of LockingThread call
+ // Thread.sleep(Long.MAX_VALUE) after monitor acquiring
+ requiredState = Thread.State.TIMED_WAITING;
+
+ waitStateWicket = new Wicket();
+ relinquishMonitor = false;
+
+ synchronized (relinquishedMonitor) {
+ relinquishedMonitor.notifyAll();
+ }
+ }
+
+ public void stopLockingThread() {
+ requiredState = Thread.State.TIMED_WAITING;
+
+ waitStateWicket = new Wicket();
+ exitSingleFrame = false;
+
+ interrupt();
+ }
+
+ // is thread should exit from single synchronized block/method
+ private boolean exitSingleFrame;
+
+ public void exitSingleFrame() {
+ requiredState = Thread.State.TIMED_WAITING;
+
+ waitStateWicket = new Wicket();
+ exitSingleFrame = true;
+
+ interrupt();
+ }
+
+ // LockingThread call this method when required state is reached
+ private void doWait() {
+ while (true) {
+ try {
+ Thread.sleep(Long.MAX_VALUE);
+ } catch (InterruptedException e) {
+ // expected exception, LockingThread should be interrupted to change state
+ }
+
+ // if single monitor should be relinquished through Object.wait()
+ if (relinquishMonitor) {
+ try {
+ DebugMonitorInfo monitorInfo = monitorsInfo.get(relinquishedMonitorIndex);
+
+ if (monitorInfo == null)
+ throw new TestBug("Invalid monitor index: " + relinquishedMonitorIndex);
+
+ relinquishedMonitor = monitorInfo.monitor;
+
+ log("Relinquish monitor: " + relinquishedMonitor);
+
+ // monitor is relinquished
+ ready();
+
+ // Really monitor is relinquished only when LockingThread calls relinquishedMonitor.wait(0) below,
+ // but to be sure that LockingThread have reached required state method waitState() should be called
+ // and this method waits when LockingThred change state to 'Thread.State.WAITING'
+
+ while (relinquishMonitor)
+ relinquishedMonitor.wait(0);
+
+ log("Acquire relinquished monitor: " + relinquishedMonitor);
+ } catch (Exception e) {
+ executedWithErrors = true;
+ log("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
+ }
+
+ relinquishedMonitor = null;
+
+ // monitor is acquired again
+ //(becuase we still are located in the frame where lock was acquired before we relinquished it)
+ ready();
+ } else
+ // exit from frame
+ break;
+ }
+ }
+
+ public void run() {
+ // LockingThread call Thread.sleep() when required stack frame was created
+ requiredState = Thread.State.TIMED_WAITING;
+
+ createStackFrame();
+
+ // thread relinquished all monitors
+ ready();
+ doWait();
+ }
+
+ static synchronized void synchronizedStaticMethod(LockingThread lockingThread) {
+ int currentStackDepth = lockingThread.expectedDepth();
+
+ lockingThread.log("Enter synchronized static thread method");
+
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(LockingThread.class, currentStackDepth, lockingThread, false);
+ lockingThread.addMonitorInfo(monitorInfo);
+ lockingThread.createStackFrame();
+ lockingThread.removeMonitorInfo(monitorInfo);
+
+ lockingThread.log("Exit synchronized static thread method");
+ }
+
+ // calculate stack depth at which monitor was acquired
+ int expectedDepth() {
+ // for each monitor call 2 methods: createStackFrame() and method which acquire monitor
+ // + when stack creation is finished call 3 methods: createStackFrame()->doWait()->sleep()
+ return (stackFramesDescription.size() - currentIndex) * 2 + 3;
+ }
+
+ private native void nativeJNIMonitorEnter(Object object);
+
+ synchronized void synchronizedMethod() {
+ int currentStackDepth = expectedDepth();
+
+ log("Enter synchronized thread method");
+
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(this, currentStackDepth, this, false);
+ addMonitorInfo(monitorInfo);
+ createStackFrame();
+ removeMonitorInfo(monitorInfo);
+
+ log("Exit synchronized thread method");
+ }
+
+ void synchronizedThisBlock() {
+ int currentStackDepth = expectedDepth();
+
+ log("Enter synchronized(this) block");
+
+ synchronized (this) {
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(this, currentStackDepth, this, false);
+ addMonitorInfo(monitorInfo);
+ createStackFrame();
+ removeMonitorInfo(monitorInfo);
+ }
+
+ log("Exit synchronized(this) block");
+ }
+
+ private static Object staticObject;
+
+ // 'staticObjectInitializingLock' is used in synchronizedBlockStaticObject() and synchronizedBlockStaticThreadObject().
+ // In this methods LockingThread initializes static object and enters in synchronized block
+ // for this static object, this actions are not thread safe(because of static fields are used) and 'staticObjectInitializingLock'
+ // is used to prevent races
+ private static ReentrantLock staticObjectInitializingLock = new ReentrantLock();
+
+ void synchronizedBlockStaticObject() {
+ int currentStackDepth = expectedDepth();
+
+ // initializing of 'staticObject' and entering to the synchronized(staticObject) block should be thread safe
+ staticObjectInitializingLock.lock();
+
+ staticObject = new Object();
+
+ log("Enter synchronized(static object) block");
+
+ synchronized (staticObject) {
+ // thread unsafe actions was done
+ staticObjectInitializingLock.unlock();
+
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(staticObject, currentStackDepth, this, false);
+ addMonitorInfo(monitorInfo);
+ createStackFrame();
+ removeMonitorInfo(monitorInfo);
+ }
+
+ log("Exit synchronized(static object) block");
+ }
+
+ private static LockingThread staticLockingThread;
+
+ void synchronizedBlockStaticThreadObject() {
+ int currentStackDepth = expectedDepth();
+
+ // initializing of 'staticLockingThread' and entering to the synchronized(staticLockingThread) block should be thread safe
+ staticObjectInitializingLock.lock();
+
+ staticLockingThread = this;
+
+ log("Enter synchronized(static thread object) block");
+
+ synchronized (staticLockingThread) {
+ // thread unsafe actions was done
+ staticObjectInitializingLock.unlock();
+
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(staticLockingThread, currentStackDepth, this, false);
+ addMonitorInfo(monitorInfo);
+ createStackFrame();
+ removeMonitorInfo(monitorInfo);
+ }
+
+ log("Exit synchronized(static thread object) block");
+ }
+
+ void synchronizedObjectBlock() {
+ int currentStackDepth = expectedDepth();
+
+ Object object = new Object();
+
+ log("Enter synchronized(object) block");
+
+ synchronized (object) {
+ DebugMonitorInfo monitorInfo = new DebugMonitorInfo(object, currentStackDepth, this, false);
+ addMonitorInfo(monitorInfo);
+ createStackFrame();
+ removeMonitorInfo(monitorInfo);
+ }
+
+ log("Exit synchronized(object) block");
+ }
+
+ private void frameWithoutLock() {
+ log("Enter frameWithoutLock");
+
+ createStackFrame();
+
+ for (DebugMonitorInfo monitor : monitorsInfo)
+ monitor.stackDepth -= 2;
+
+ log("Exit frameWithoutLock");
+ }
+}
+
+//class containing synchronized method and synchronized static method, used by LockingThread
+class ClassWithSynchronizedMethods {
+ public synchronized void synchronizedMethod(LockingThread lockingThread) {
+ int currentStackDepth = lockingThread.expectedDepth();
+
+ lockingThread.log("Enter synchronized method");
+
+ LockingThread.DebugMonitorInfo monitorInfo = new LockingThread.DebugMonitorInfo(this, currentStackDepth, lockingThread, false);
+ lockingThread.addMonitorInfo(monitorInfo);
+ lockingThread.createStackFrame();
+ lockingThread.removeMonitorInfo(monitorInfo);
+
+ lockingThread.log("Exit synchronized method");
+ }
+
+ public static synchronized void synchronizedStaticMethod(LockingThread lockingThread) {
+ int currentStackDepth = lockingThread.expectedDepth();
+
+ lockingThread.log("Enter synchronized static method");
+
+ LockingThread.DebugMonitorInfo monitorInfo = new LockingThread.DebugMonitorInfo(ClassWithSynchronizedMethods.class, currentStackDepth,
+ lockingThread, false);
+ lockingThread.addMonitorInfo(monitorInfo);
+ lockingThread.createStackFrame();
+ lockingThread.removeMonitorInfo(monitorInfo);
+
+ lockingThread.log("Exit synchronized static method");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/MonitorLockingThread.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+/*
+ * Thread intended to hold given lock until method releaseLock() not called
+ *
+ * Example of usage:
+ *
+ * Object lockToHold = new Object();
+ * MonitorLockingThread lockingThread = new MonitorLockingThread(lockToHold);
+ *
+ * // after calling this method lock 'lockToHold' is acquired by lockingThread
+ * lockingThread.acquireLock();
+ *
+ * // after calling this method lockingThread releases 'lockToHold' and finishes execution
+ * lockingThread.releaseLock();
+ */
+public class MonitorLockingThread extends Thread {
+ /*
+ * Class MonitorLockingThread is written for usage in tests provoking monitor contention.
+ * Typically in these tests exists thread holding lock (MonitorLockingThread) and another
+ * thread trying to acquire the same lock. But this scenario also requires one more thread
+ * which will force MonitorLockingThread to release lock when contention occurred, for this purpose
+ * auxiliary thread class LockFreeThread is written.
+ *
+ * Example of usage of MonitorLockingThread and LockFreeThread:
+ *
+ * Object lock = new Object();
+ * MonitorLockingThread monitorLockingThread = new MonitorLockingThread(lock);
+ *
+ * MonitorLockingThread.LockFreeThread lockFreeThread =
+ * new MonitorLockingThread.LockFreeThread(Thread.currentThread(), monitorLockingThread);
+ *
+ * monitorLockingThread.acquireLock();
+ *
+ * lockFreeThread.start();
+ *
+ * // try to acquire lock which is already held by MonitorLockingThread (here monitor contention should occur),
+ * // when LockFreeThread finds that contention occurred it forces MonitorLockingThread to release lock
+ * // and current thread is able to continue execution
+ * synchronized (lock) {
+ * }
+ */
+ public static class LockFreeThread extends Thread {
+ private Thread blockedThread;
+
+ private MonitorLockingThread lockingThread;
+
+ public LockFreeThread(Thread blockedThread, MonitorLockingThread lockingThread) {
+ this.blockedThread = blockedThread;
+ this.lockingThread = lockingThread;
+ }
+
+ public void run() {
+ /*
+ * Wait when blockedThread's state will switch to 'BLOCKED' (at that moment monitor contention
+ * should already occur) and then force MonitorLockingThread to release lock
+ */
+ while (blockedThread.getState() != Thread.State.BLOCKED)
+ yield();
+
+ lockingThread.releaseLock();
+ }
+ }
+
+ private volatile boolean isRunning = true;
+
+ private volatile boolean holdsLock;
+
+ private Object lockToHold;
+
+ public MonitorLockingThread(Object lockToHold) {
+ this.lockToHold = lockToHold;
+ }
+
+ public void run() {
+ synchronized (lockToHold) {
+ holdsLock = true;
+ while (isRunning)
+ yield();
+ }
+ holdsLock = false;
+ }
+
+ public void releaseLock() {
+ isRunning = false;
+ while (holdsLock)
+ yield();
+ }
+
+ public void acquireLock() {
+ start();
+ while (!holdsLock)
+ yield();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/ReentrantLockLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import java.util.concurrent.locks.ReentrantLock;
+import nsk.share.Wicket;
+
+/*
+ * Class used for deadlock creation, acquires java.util.concurrent.locks.ReentrantLock
+ */
+public class ReentrantLockLocker extends DeadlockLocker {
+ private ReentrantLock lock = new ReentrantLock();
+
+ public ReentrantLockLocker(Wicket step1, Wicket step2, Wicket readyWicket) {
+ super(step1, step2, readyWicket);
+ }
+
+ public ReentrantLock getLock() {
+ return lock;
+ }
+
+ protected void doLock() {
+ lock.lock();
+
+ try {
+ step1.unlockAll();
+ step2.waitFor();
+ readyWicket.unlock();
+ inner.lock();
+ } finally {
+ lock.unlock();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedBlockLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import nsk.share.Wicket;
+
+/*
+ * Class used for deadlock creation, acquires java lock
+ * using synchronized block
+ */
+public class SynchronizedBlockLocker extends DeadlockLocker {
+ private Object object = new Object();
+
+ public SynchronizedBlockLocker(Wicket step1, Wicket step2, Wicket readyWicket) {
+ super(step1, step2, readyWicket);
+ }
+
+ public Object getLock() {
+ return object;
+ }
+
+ protected void doLock() {
+ synchronized (object) {
+ step1.unlockAll();
+ step2.waitFor();
+ readyWicket.unlock();
+ inner.lock();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/locks/SynchronizedMethodLocker.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.locks;
+
+import nsk.share.Wicket;
+
+/*
+ * Class used for deadlock creation, acquires java lock
+ * using synchronized method
+ */
+public class SynchronizedMethodLocker extends DeadlockLocker {
+ public SynchronizedMethodLocker(Wicket step1, Wicket step2, Wicket readyWicket) {
+ super(step1, step2, readyWicket);
+ }
+
+ public Object getLock() {
+ return this;
+ }
+
+ protected synchronized void doLock() {
+ step1.unlock();
+ step2.waitFor();
+ readyWicket.unlock();
+ inner.lock();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/Log.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.log;
+
+/**
+ * Log interface.
+ */
+public interface Log {
+ /**
+ * Log at INFO level.
+ *
+ * @param o object to log
+ */
+ public void info(Object o);
+
+ /**
+ * Log at DEBUG level.
+ *
+ * @param o object to log
+ */
+ public void debug(Object o);
+
+ /**
+ * Log at WARN level.
+ *
+ * @param o object to log
+ */
+ public void warn(Object o);
+
+ /**
+ * Log at ERROR level
+ *
+ * @param o object to log
+ */
+ public void error(Object o);
+
+ /**
+ * Determine if logging at DEBUG level.
+ *
+ * @return true if debug logging is enabled, false otherwise
+ */
+ public boolean isDebugEnabled();
+
+ /**
+ * Determine if logging at INFO level.
+ *
+ * @return true if info logging is enabled, false otherwise
+ */
+ public boolean isInfoEnabled();
+
+ /**
+ * Determine if logging at WARN level.
+ *
+ * @return true if warn logging is enabled, false otherwise
+ */
+ public boolean isWarnEnabled();
+
+ /**
+ * Determine if logging at ERROR level.
+ *
+ * @return true if error logging is enabled, false otherwise
+ */
+ public boolean isErrorEnabled();
+
+ /**
+ * Enable/disable info output.
+ *
+ * @param infoEnabled
+ */
+ public void setInfoEnabled(boolean infoEnabled);
+
+ /**
+ * Enable/disable debug output.
+ *
+ * @param debugEnabled
+ */
+ public void setDebugEnabled(boolean debugEnabled);
+
+ /**
+ * Enable/disable warn output.
+ * @param warnEnabled
+ */
+ public void setWarnEnabled(boolean warnEnabled);
+
+ /**
+ * Enable/disable error output.
+ * @param errorEnabled
+ */
+ public void setErrorEnabled(boolean errorEnabled);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.log;
+
+/**
+ * Marker interface to inject Log.
+ * @see nsk.share.log.Log
+ */
+public interface LogAware {
+ /**
+ * Set log to use.
+ *
+ * @param log log
+ */
+ public void setLog(Log log);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/log/LogSupport.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.log;
+
+import java.io.PrintStream;
+
+/**
+ * Basic Log that outputs to PrintStream.
+ *
+ * This log also tries to catch OutOfMemoryErrors and retry.
+ *
+ * @see nsk.share.log.Log
+ */
+public class LogSupport implements Log {
+ private final int attempts = 2;
+ private PrintStream out;
+ private boolean infoEnabled = true;
+ private boolean debugEnabled = true;
+ private boolean warnEnabled = true;
+ private boolean errorEnabled = true;
+
+ public LogSupport() {
+ this(System.out);
+ }
+
+ public LogSupport(PrintStream out) {
+ this.out = out;
+ }
+
+ protected void logObject(Object o) {
+ if (o instanceof Throwable) {
+ logThrowable((Throwable) o);
+ return;
+ }
+ for (int i = 0; i < attempts; ++i) {
+ try {
+ out.println(o.toString());
+ out.flush();
+ break;
+ } catch (OutOfMemoryError e) {
+ System.gc();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ out.flush();
+ }
+
+ protected void logThrowable(Throwable o) {
+ for (int i = 0; i < attempts; ++i) {
+ try {
+ o.printStackTrace(out);
+ out.flush();
+ break;
+ } catch (OutOfMemoryError e) {
+ System.gc();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ out.flush();
+ }
+
+ public void info(Object o) {
+ if (infoEnabled)
+ logObject(o);
+ }
+
+ public void debug(Object o) {
+ if (debugEnabled)
+ logObject(o);
+ }
+
+ public void warn(Object o) {
+ if (warnEnabled)
+ logObject(o);
+ }
+
+ public void error(Object o) {
+ if (errorEnabled)
+ logObject(o);
+ }
+
+ public boolean isInfoEnabled() {
+ return infoEnabled;
+ }
+
+ public void setInfoEnabled(boolean infoEnabled) {
+ this.infoEnabled = infoEnabled;
+ }
+
+ public boolean isDebugEnabled() {
+ return debugEnabled;
+ }
+
+ public void setDebugEnabled(boolean debugEnabled) {
+ this.debugEnabled = debugEnabled;
+ }
+
+ public boolean isWarnEnabled() {
+ return warnEnabled;
+ }
+
+ public void setWarnEnabled(boolean warnEnabled) {
+ this.warnEnabled = warnEnabled;
+ }
+
+ public boolean isErrorEnabled() {
+ return errorEnabled;
+ }
+
+ public void setErrorEnabled(boolean errorEnabled) {
+ this.errorEnabled = errorEnabled;
+ }
+
+ public void setOut(PrintStream out) {
+ this.out = out;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/README Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,186 @@
+Copyright (c) 2003, 2018, 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.
+
+---------------------------------------------------------------------------------
+
+This directory contains source files of testbase_nsk native
+framework, which provides support for native tests.
+
+ Source files:
+ nsk_tools.h
+ nsk_tools.c
+
+ Naming conventions:
+ macroses: NSK_*
+ functions: nsk_*
+
+Also this directory provides support for running native threads
+in a platform independent manner.
+
+ Source files:
+ native_thread.h
+ native_thread.c
+
+ Naming conventions:
+ functions: THREAD_*
+
+The following source files declares a set of functions which
+provides support for lists of various objects
+
+ Source files:
+ nsk_list.h
+ nsk_list.c
+
+ Naming conventions:
+ functions: nsk_list_*
+
+---------------------------------------------------------------------------------
+
+nsk_tools.h
+
+Provides functions and macroses for the most usefull actions:
+
+ - access native JVM environment in a compiler independent manner
+
+ NSK_CPP_STUBn(function, env, arg1, ..., argn)
+
+ - print error message with arguments
+
+ NSK_COMPLAINn(format, arg1, ..., argn)
+
+ - print verbose message with arguments
+
+ NSK_DISPLAYn(format, arg1, ..., argn)
+
+ - trace action execution
+
+ NSK_TRACE(action)
+
+ - trace action, check result for true/false and print error if required
+
+ NSK_VERIFY(action)
+ NSK_VERIFY_NEGATIVE(action)
+
+ - set verbose and trace mode of test output
+
+ void nsk_setVerboseMode(int verbose);
+ int nsk_getVerboseMode();
+
+ void nsk_setTraceMode(int mode);
+ int nsk_getTraceMode();
+
+ - miscelaneous functions for printing messages
+ (hidden by above mentioned macroses)
+
+Typical example of using macroses NSK_CPP_STUB and NSK_VERIFY
+for accesing JVM native environment:
+
+ // jvm->GetEnv(jvm, &env, version)
+ if (!NSK_VERIFY(
+ NSK_CPP_STUB3(GetEnv, jvm, &env, JNI_VERSION_1_2) == JNI_OK)) {
+ return JNI_ERR;
+ }
+
+For more specific checks in invocations of JNI and JVMTI functions
+use special macroses defined in share/jni and share/jvmti frameworks.
+
+---------------------------------------------------------------------------------
+
+native_thread.h
+
+Provides platform-independent support for running native threads:
+
+ - manage native threads
+
+ void* THREAD_new(PROCEDURE procedure, void* context);
+ void* THREAD_start(void* thread);
+ void THREAD_waitFor(void* thread);
+ void THREAD_sleep(int seconds);
+
+ - get status of native threads
+
+ int THREAD_isStarted(void* thread);
+ int THREAD_hasFinished(void* thread);
+ int THREAD_status(void* thread);
+
+---------------------------------------------------------------------------------
+
+nsk_list.h
+
+Provides support for lists of various objects:
+
+ - managing list
+ const void* nsk_list_Create();
+ int nsk_list_Destroy(const void *plist);
+
+ - managing elements
+ const void* nsk_list_Add(const void *plist, const void *p);
+ int nsk_list_Delete(const void *plist, int ind);
+
+ - getting element info
+ int nsk_list_getCount(const void *plist);
+ const void* nsk_list_Get(const void *plist, int ind);
+
+Typical example:
+
+int TOTAL_COUNT = 10;
+typedef struct recordStruct {
+ int field1;
+ int field2;
+} record;
+
+main() {
+ int i;
+ record *rec;
+ const void *plist;
+
+ /* creating list */
+ plist = nsk_list_create();
+
+ /* adding new elements */
+ for (i = 0; i < TOTAL_COUNT; i ++) {
+ rec = (record *)malloc(sizeof(record));
+ rec->field1 = i;
+ rec->field2 = i * 10;
+ if (!nsk_list_add(plist, rec)) {
+ free((void *)rec);
+ }
+ }
+
+ /* getting elements */
+ for (i = 0; i < TOTAL_COUNT; i ++) {
+ rec = (record *)nsk_list_get(plist, i);
+ printf("%3d %3d\n", rec->field1, rec->field2);
+ }
+
+ /* deleteing elements */
+ for (i = 0; i < TOTAL_COUNT; i ++) {
+ rec = (record *)nsk_list_get(plist, i);
+ free(rec);
+ nsk_list_remove(plist, 0);
+ }
+
+ /* destroying list */
+ nsk_list_destroy(plist);
+
+}
+
+---------------------------------------------------------------------------------
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,211 @@
+/*
+* Copyright (c) 2003, 2018, 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* testbase_nsk threads: */
+#include <native_thread.h>
+
+/***************************************************************/
+
+#ifdef _WIN32
+
+#define windows
+#include <windows.h>
+#include <process.h> /* for thread routines */
+typedef unsigned int THREAD_ID;
+
+#else // !_WIN32
+
+#include <unistd.h>
+
+#ifdef sun
+#include <thread.h>
+typedef thread_t THREAD_ID;
+#else // !sun
+#include <pthread.h>
+typedef pthread_t THREAD_ID;
+#endif // !sun
+
+#endif // !_WIN32
+
+/***************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A mirror to control a thread.
+ */
+typedef
+ struct STRUCT_THREAD {
+ PROCEDURE procedure;
+ void* context;
+ /**/
+ int started;
+ int finished;
+ int status;
+ /**/
+ THREAD_ID id;
+ }
+ THREAD;
+
+/***************************************************************/
+
+/**
+ * Return a new thread mirror, or NULL if failed.
+ */
+void* THREAD_new(PROCEDURE procedure, void* context) {
+ THREAD* thread = (THREAD*)malloc(sizeof(THREAD));
+ if (thread == NULL)
+ return NULL;
+ thread->procedure = procedure;
+ thread->context = context;
+ thread->started = 0; /* No */
+ thread->finished = 0;
+ thread->status = -1; /* undefined */
+ return thread;
+}
+
+/***************************************************************/
+
+#ifdef windows
+unsigned __stdcall procedure(void* t) {
+#else // !windows
+void* procedure(void* t) {
+#endif
+ THREAD* thread = (THREAD*)t;
+ thread->started = 1;
+ thread->status = thread->procedure(thread->context);
+ thread->finished = 1;
+ return 0;
+}
+
+/**
+ * Return the thread if started OK, or NULL if failed.
+ */
+void* THREAD_start(void* t) {
+ THREAD* thread = (THREAD*)t;
+ if (thread == NULL)
+ return NULL;
+ if (thread->started != 0)
+ return NULL;
+/* thread->started = 0; -- not yet */
+ thread->finished = 0;
+ thread->status = 0;
+ {
+
+#ifdef windows
+ uintptr_t result = _beginthreadex(NULL,0,procedure,thread,0,&(thread->id));
+ if (result == 0) {
+ perror("failed to create a native thread");
+ return NULL;
+ }
+#elif sun
+ int result = thr_create(NULL,0,procedure,thread,0,&(thread->id));
+ if (result != 0) {
+ perror("failed to create a native thread");
+ return NULL;
+ }
+#else // !windows & !sun
+ int result = pthread_create(&(thread->id),NULL,procedure,thread);
+ if (result != 0) {
+ perror("failed to create a native thread");
+ return NULL;
+ }
+#endif // !windows & !sun
+ };
+ return thread;
+}
+
+/***************************************************************/
+
+/**
+ * Return 1 if the thread has been started, or 0 if not,
+ * or -1 if thread==NULL.
+ */
+int THREAD_isStarted(void* t) {
+ THREAD* thread = (THREAD*)t;
+ if (thread == NULL)
+ return -1;
+ return (thread->started == 1);
+}
+
+/**
+ * Return 1 if the thread has been started and already has finished,
+ * or 0 if the thread hasn't finish (or even hasn't been started),
+ * or -1 if thread==NULL.
+ */
+int THREAD_hasFinished(void* t) {
+ THREAD* thread = (THREAD*)t;
+ if (thread == NULL)
+ return -1;
+ return (thread->finished == 1);
+}
+
+/**
+ * Return thread->status if thread has finished,
+ * or return 0 if thread hasn't finished,
+ * or retuen -1 if thread==NULL.
+ */
+int THREAD_status(void* t) {
+ THREAD* thread = (THREAD*)t;
+ if (thread == NULL)
+ return -1;
+ return thread->status;
+}
+
+/***************************************************************/
+
+/**
+ * Cycle with 1 second sleeps until the thread has finished;
+ * or return immediately, if thread==NULL.
+ */
+void THREAD_waitFor(void* t) {
+ THREAD* thread = (THREAD*)t;
+ if (thread == NULL)
+ return;
+ while (thread->finished == 0)
+ THREAD_sleep(1); /* yield for a second */
+}
+
+/***************************************************************/
+
+/**
+ * Current thread sleeps.
+ */
+void THREAD_sleep(int seconds) {
+#ifdef windows
+ Sleep(1000L * seconds);
+#else
+ sleep(seconds);
+#endif
+}
+
+/***************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_thread.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+#ifndef NSK_SHARE_NATIVE_NATIVE_THREAD_H
+#define NSK_SHARE_NATIVE_NATIVE_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A thread procedure with a void* argument and returning
+ * a status.
+ */
+typedef int(*PROCEDURE)(void*);
+
+/**
+ * Return a thread mirror, or NULL if failed.
+ */
+void* THREAD_new(PROCEDURE procedure, void* context);
+
+/**
+ * Return the thread if started OK, or NULL if failed.
+ */
+void* THREAD_start(void* thread);
+
+/**
+ * Return 1 if the thread has been started, or 0 if not,
+ * or -1 if thread==NULL.
+ */
+int THREAD_isStarted(void* thread);
+
+/**
+ * Return 1 if the thread has been started and already has finished,
+ * or 0 if the thread hasn't finish (or even hasn't been started),
+ * or -1 if thread==NULL.
+ */
+int THREAD_hasFinished(void* thread);
+
+/**
+ * Return thread->status if thread has finished,
+ * or return 0 if thread hasn't finished,
+ * or retuen -1 if thread==NULL.
+ */
+int THREAD_status(void* thread);
+
+/**
+ * Cycle with 1 second sleeps until the thread has finished;
+ * or return immediately, if thread==NULL.
+ */
+void THREAD_waitFor(void* thread);
+
+/**
+ * Current thread sleeps.
+ */
+void THREAD_sleep(int seconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2006, 2018, 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.
+ */
+#include <stdio.h>
+
+#if (defined(WIN32) || defined (_WIN32) )
+#include <process.h>
+#define getpid _getpid
+#define pidType int
+#else
+#include <unistd.h>
+#define pidType pid_t
+#endif
+
+#include <sys/types.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong
+JNICALL Java_nsk_share_NativeUtils_getCurrentPID(JNIEnv * jni, jobject jobj) {
+ return (jlong) getpid();
+}
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2004, 2018, 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nsk_list.h"
+#include "nsk_tools.h"
+
+#define NSK_LIST_INIT_COUNT 20
+
+typedef struct nsk_list_infoStruct {
+ const void **arr;
+ int elements_count;
+ int allocated_count;
+} nsk_list_info;
+
+
+static int nsk_list_size_void = sizeof(void *);
+
+/* ============================================================================= */
+
+const void* nsk_list_create() {
+
+ nsk_list_info *list_info;
+
+ /* create nsk_list_info */
+ list_info = (nsk_list_info *)malloc(sizeof(nsk_list_info));
+ if (list_info == NULL) {
+ return NULL;
+ }
+
+ list_info->allocated_count = NSK_LIST_INIT_COUNT;
+ list_info->elements_count = 0;
+ list_info->arr = (const void **)malloc(list_info->allocated_count * nsk_list_size_void);
+ if (list_info->arr == NULL) {
+ free(list_info);
+ return NULL;
+ }
+
+ return list_info;
+}
+
+/* ============================================================================= */
+
+int nsk_list_destroy(const void *plist) {
+
+ const nsk_list_info *list_info = (const nsk_list_info *)plist;
+
+ free((void *)list_info->arr);
+ free((void *)plist);
+
+ return NSK_TRUE;
+}
+
+/* ============================================================================= */
+
+int nsk_list_add(const void *plist, const void *p) {
+
+ nsk_list_info *list_info = (nsk_list_info *)plist;
+
+ if (list_info->elements_count >= list_info->allocated_count) {
+ list_info->allocated_count += NSK_LIST_INIT_COUNT;
+ list_info->arr = (const void **)realloc((void *)list_info->arr, list_info->allocated_count * nsk_list_size_void);
+ if (list_info->arr == NULL) {
+ return NSK_FALSE;
+ }
+ }
+ list_info->arr[list_info->elements_count++] = p;
+
+ return NSK_TRUE;
+}
+
+/* ============================================================================= */
+
+int nsk_list_remove(const void *plist, int ind) {
+
+ nsk_list_info *list_info = (nsk_list_info *)plist;
+
+ if ((list_info->elements_count <= 0)
+ || ((ind < 0) || (ind >= list_info->elements_count)))
+ return NSK_FALSE;
+
+ {
+ int i;
+ for (i = ind+1; i < list_info->elements_count; i++) {
+ list_info->arr[i - 1] = list_info->arr[i];
+ }
+ }
+ list_info->arr[--list_info->elements_count] = 0;
+
+ return NSK_TRUE;
+}
+
+/* ============================================================================= */
+
+int nsk_list_getCount(const void *plist) {
+
+ return ((const nsk_list_info *)plist)->elements_count;
+}
+
+/* ============================================================================= */
+
+const void* nsk_list_get(const void *plist, int i) {
+
+ const nsk_list_info *list_info = (const nsk_list_info *)plist;
+
+ if ((i >= 0) && (i < list_info->elements_count)) {
+ return list_info->arr[i];
+ }
+
+ return NULL;
+}
+
+/* ============================================================================= */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_list.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004, 2018, 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.
+ */
+
+#ifndef NSK_LIST
+#define NSK_LIST
+
+/**
+ * Prepares array of pointers which has fixed INITIAL_SIZE.
+ * Memory for this array will be reallocated at the nsk_list_add()
+ * invocation if it is required.
+ *
+ * To release memory call nsk_list_destroy()
+ *
+ */
+const void* nsk_list_create();
+
+/**
+ * Releases memory allocated for array of pointer
+ * Returns NSK_TRUE if array was successfully released
+ */
+int nsk_list_destroy(const void *plist);
+
+/**
+ * Returns number of elements
+ */
+int nsk_list_getCount(const void *plist);
+
+/**
+ * Returns pointer to i-th element.
+ * User must care for type cast of this pointer
+ */
+const void* nsk_list_get(const void *plist, int i);
+
+/**
+ * Adds new element into array.
+ * If array is full then memory is reallocated so as
+ * array could contain additional INITIAL_SIZE elements
+ * Returns NSK_TRUE if pointer was successfully added
+ */
+int nsk_list_add(const void *plist, const void *p);
+
+/**
+ * Removes i-th pointer from array
+ */
+int nsk_list_remove(const void *plist, int i);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010, 2018, 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.
+ */
+
+#include <stdlib.h>
+#include "nsk_mutex.h"
+
+#ifndef _WIN32
+
+#include <pthread.h>
+
+MUTEX* MUTEX_create()
+{
+ MUTEX* mutex = (MUTEX*)malloc(sizeof(pthread_mutex_t));
+ if (mutex)
+ {
+ pthread_mutex_init((pthread_mutex_t*)mutex, NULL);
+ }
+ return mutex;
+}
+
+void MUTEX_acquire(MUTEX* mutex)
+{
+ pthread_mutex_lock((pthread_mutex_t*)mutex);
+}
+
+void MUTEX_release(MUTEX* mutex)
+{
+ pthread_mutex_unlock((pthread_mutex_t*)mutex);
+}
+
+void MUTEX_destroy(MUTEX* mutex)
+{
+ pthread_mutex_destroy((pthread_mutex_t*)mutex);
+
+ free(mutex);
+}
+
+#else // _WIN32
+
+#include <windows.h>
+
+MUTEX* MUTEX_create()
+{
+ MUTEX* mutex = (MUTEX*)malloc(sizeof(CRITICAL_SECTION));
+ if (mutex)
+ {
+ InitializeCriticalSection((PCRITICAL_SECTION)mutex);
+ }
+ return mutex;
+}
+
+void MUTEX_acquire(MUTEX* mutex)
+{
+ EnterCriticalSection((PCRITICAL_SECTION)mutex);
+}
+
+void MUTEX_release(MUTEX* mutex)
+{
+ LeaveCriticalSection((PCRITICAL_SECTION)mutex);
+}
+
+void MUTEX_destroy(MUTEX* mutex)
+{
+ DeleteCriticalSection((PCRITICAL_SECTION)mutex);
+
+ free(mutex);
+}
+
+#endif // _WIN32
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_mutex.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010, 2018, 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.
+ */
+
+#ifndef NSK_MUTEX_H
+#define NSK_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Structure to hold mutex data (the content is platform-specific)
+ */
+typedef struct _MUTEX MUTEX;
+
+/**
+ * Create a mutex
+ */
+MUTEX* MUTEX_create();
+
+/**
+ * Acquire a mutex
+ */
+void MUTEX_acquire(MUTEX* mutex);
+
+/**
+ * Release a mutex
+ */
+void MUTEX_release(MUTEX* mutex);
+
+/**
+ * Destroy a mutex
+ */
+void MUTEX_destroy(MUTEX* mutex);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+
+/*************************************************************/
+
+#include "nsk_tools.h"
+
+/*************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+static struct {
+ int verbose;
+ int tracing;
+ int nComplains;
+} nsk_context = {NSK_FALSE, NSK_TRACE_NONE, 0};
+
+void nsk_setVerboseMode(int verbose) {
+ nsk_context.verbose = verbose;
+}
+
+int nsk_getVerboseMode() {
+ return nsk_context.verbose;
+}
+
+void nsk_setTraceMode(int mode) {
+ nsk_context.tracing = mode;
+}
+
+int nsk_getTraceMode() {
+ return nsk_context.tracing;
+}
+
+/*************************************************************/
+
+static const char* file_basename(const char* fullname) {
+ const char* p;
+ const char* base = fullname;;
+
+ if (fullname == NULL)
+ return NULL;
+
+ for (p = fullname; *p != '\0'; p++) {
+ if (*p == '/' || *p == '\\')
+ base = p + 1;
+ }
+ return base;
+}
+
+/*************************************************************/
+
+void nsk_display(const char format[], ...) {
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvdisplay(NULL,0,format,ap);
+ va_end(ap);
+}
+
+void nsk_ldisplay(const char file[], int line, const char format[], ...) {
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvdisplay(file,line,format,ap);
+ va_end(ap);
+}
+
+void nsk_vdisplay(const char format[], va_list ap) {
+ nsk_lvdisplay(NULL,0,format,ap);
+}
+
+void nsk_lvdisplay(const char file[], int line, const char format[], va_list ap)
+{
+ if (!nsk_context.verbose)
+ return;
+ if (file != NULL)
+ (void) nsk_printf("- %s, %d: ",file_basename(file),line);
+ (void) nsk_vprintf(format,ap);
+}
+
+/*************************************************************/
+
+void nsk_complain(const char format[], ...) {
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvcomplain(NULL,0,format,ap);
+ va_end(ap);
+}
+
+void nsk_lcomplain(const char file[], int line, const char format[], ...)
+{
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvcomplain(file,line,format,ap);
+ va_end(ap);
+}
+
+void nsk_vcomplain(const char format[], va_list ap) {
+ nsk_lvcomplain(NULL,0,format,ap);
+}
+
+void nsk_lvcomplain(const char file[], int line,
+ const char format[], va_list ap)
+{
+ char msg_buf[1024];
+ nsk_context.nComplains++;
+ if (!nsk_context.verbose) {
+ if ( nsk_context.nComplains > NSK_MAX_COMPLAINS_NON_VERBOSE ) {
+ return;
+ }
+
+ if ( nsk_context.nComplains == NSK_MAX_COMPLAINS_NON_VERBOSE ) {
+ nsk_printf("# ...\n"
+ "# ERROR: too many complains, giving up to save disk space (CR 6341460)\n"
+ "# Please rerun the test with -verbose option to listen to the entire song\n");
+ return;
+ }
+ }
+
+ // Generate the message into a temp buffer since we can't call vfprintf on it twice,
+ // and also may need to modify a copy of the message slightly.
+ (void) vsnprintf(msg_buf, sizeof(msg_buf), format, ap);
+
+ // Print a fake exception with the error for failure analysis.
+ // Do this only for the first complaint.
+ if (nsk_context.nComplains == 1) {
+ char msg_buf2[sizeof(msg_buf)];
+ char* nl_ptr;
+ strncpy(msg_buf2, msg_buf, sizeof(msg_buf2));
+ // Only include up to the 1st newline in the exception's error message.
+ nl_ptr = strchr(msg_buf2, '\n');
+ if (nl_ptr != NULL) {
+ nl_ptr++; // Skip past the newline char.
+ *nl_ptr = '\0'; // Terminate the string after the newline char.
+ } else if (strlen(msg_buf2) != 0) {
+ msg_buf2[strlen(msg_buf2)-1] = '\n'; // Make sure we have a newline char at the end.
+ }
+ (void) nsk_printf("The following fake exception stacktrace is for failuire analysis. \n");
+ (void) nsk_printf("nsk.share.Fake_Exception_for_RULE_Creation: ");
+ if (file != NULL) {
+ (void) nsk_printf("(%s:%d) ", file_basename(file), line);
+ }
+ (void) nsk_printf(msg_buf2);
+ (void) nsk_printf("\tat nsk_lvcomplain(%s:%d)\n", file_basename(__FILE__), __LINE__);
+ }
+
+ if (file != NULL) {
+ (void) nsk_printf("# ERROR: %s, %d: ", file_basename(file), line);
+ } else {
+ (void) nsk_printf("# ERROR: ");
+ }
+ (void) nsk_printf(msg_buf);
+}
+
+/*************************************************************/
+
+void nsk_ltrace(int mode, const char file[], int line, const char format[], ...) {
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvtrace(mode,file,line,format,ap);
+ va_end(ap);
+}
+
+void nsk_lvtrace(int mode, const char file[], int line, const char format[], va_list ap)
+{
+ if ((nsk_context.tracing & mode) == 0) {
+ return;
+ }
+
+ {
+ const char* prefix;
+ switch (mode) {
+ case NSK_TRACE_BEFORE:
+ prefix = ">>";
+ break;
+ case NSK_TRACE_AFTER:
+ prefix = "<<";
+ break;
+ default:
+ prefix = "..";
+ break;
+ }
+
+ (void) nsk_printf("- %s, %d: %s ",file_basename(file),line,prefix);
+ (void) nsk_vprintf(format,ap);
+ }
+}
+
+/*************************************************************/
+
+int nsk_lverify(int value, const char file[], int line, const char format[], ...)
+{
+ int fail=0;
+ va_list ap;
+ va_start(ap,format);
+ nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap);
+ if (!value) {
+ nsk_lvcomplain(file,line,format,ap);
+ nsk_printf("# verified assertion is FALSE\n");
+ fail=1;
+ };
+ va_end(ap);
+ return !fail;
+}
+
+/*************************************************************/
+
+int nsk_vprintf(const char format[], va_list ap) {
+ int x = vfprintf(stdout,format,ap);
+ int err = fflush(stdout);
+ if (err != 0) {
+ printf("stdout: fflush failed - err=%d errno=%d x=%d\n", err, errno, x);
+ fprintf(stderr, "stderr: fflush failed - err=%d errno=%d x=%d\n", err, errno, x);
+ }
+ assert(err == 0);
+ return x;
+}
+
+int nsk_printf(const char format[], ...) {
+ int x;
+ va_list ap;
+ va_start(ap,format);
+ x = nsk_vprintf(format,ap);
+ va_end(ap);
+ return x;
+}
+
+/*************************************************************/
+
+#define MAX_HEX_COLUMNS 255
+
+void nsk_printHexBytes(const char indent[], int columns,
+ size_t size, const unsigned char bytes[]) {
+ char hex[MAX_HEX_COLUMNS * 3 + 1];
+ char ascii[MAX_HEX_COLUMNS + 1];
+ char buf[16];
+
+ size_t i;
+
+ if (size <= 0 || bytes == NULL)
+ return;
+
+ for (i = 0; i < size; i += columns) {
+ int j;
+
+ hex[0] = '\0';
+ ascii[0] = '\0';
+
+ for (j = 0; j < columns && (i + j) < size; j++) {
+ unsigned int b = (unsigned int)bytes[i + j] & 0xFF;
+ char ch = (char)bytes[i + j];
+
+ if (!(isascii(ch) && isprint(ch))) ch = '.';
+ sprintf(buf, " %02X", b);
+ strcat(hex, buf);
+ ascii[j] = ch;
+ }
+
+ ascii[j] = '\0';
+ if (j < columns) {
+ for (; j < columns; j++) {
+ strcat(hex, " ");
+ }
+ }
+
+ nsk_printf("%s0x%08X: %s %s\n", indent, (int)i, hex, ascii);
+ }
+}
+
+/*************************************************************/
+
+const char* nsk_null_string(const char* str) {
+ return (str == NULL)? "<NULL>" : str;
+}
+
+/*************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/native/nsk_tools.h Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ */
+
+#ifndef NSK_TOOLS_DEFINED
+#define NSK_TOOLS_DEFINED
+
+/*************************************************************/
+
+#include <stdarg.h>
+
+/*************************************************************/
+
+/**
+ * Use examples:
+ *
+ * jfieldID id = NSK_CPP_STUB3(jni,GetFieldID,clazz,name,sig);
+ *
+ * jvmtiError code = NSK_CPP_STUB0(jvmti,DisposeEnvironment);
+ *
+ */
+
+#define NSK_CPP_STUB1(Func,env) (*env)->Func(env)
+#define NSK_CPP_STUB2(Func,env,a) (*env)->Func(env,a)
+#define NSK_CPP_STUB3(Func,env,a,b) (*env)->Func(env,a,b)
+#define NSK_CPP_STUB4(Func,env,a,b,c) (*env)->Func(env,a,b,c)
+#define NSK_CPP_STUB5(Func,env,a,b,c,d) (*env)->Func(env,a,b,c,d)
+#define NSK_CPP_STUB6(Func,env,a,b,c,d,e) (*env)->Func(env,a,b,c,d,e)
+#define NSK_CPP_STUB7(Func,env,a,b,c,d,e,f) (*env)->Func(env,a,b,c,d,e,f)
+#define NSK_CPP_STUB8(Func,env,a,b,c,d,e,f,g) (*env)->Func(env,a,b,c,d,e,f,g)
+#define NSK_CPP_STUB9(Func,env,a,b,c,d,e,f,g,h) (*env)->Func(env,a,b,c,d,e,f,g,h)
+
+#ifdef __cplusplus
+#ifndef NSK_CPP_STUBS_ENFORCE_C
+#undef NSK_CPP_STUB1
+#undef NSK_CPP_STUB2
+#undef NSK_CPP_STUB3
+#undef NSK_CPP_STUB4
+#undef NSK_CPP_STUB5
+#undef NSK_CPP_STUB6
+#undef NSK_CPP_STUB7
+#undef NSK_CPP_STUB8
+#undef NSK_CPP_STUB9
+#define NSK_CPP_STUB1(Func,env) env->Func()
+#define NSK_CPP_STUB2(Func,env,a) env->Func(a)
+#define NSK_CPP_STUB3(Func,env,a,b) env->Func(a,b)
+#define NSK_CPP_STUB4(Func,env,a,b,c) env->Func(a,b,c)
+#define NSK_CPP_STUB5(Func,env,a,b,c,d) env->Func(a,b,c,d)
+#define NSK_CPP_STUB6(Func,env,a,b,c,d,e) env->Func(a,b,c,d,e)
+#define NSK_CPP_STUB7(Func,env,a,b,c,d,e,f) env->Func(a,b,c,d,e,f)
+#define NSK_CPP_STUB8(Func,env,a,b,c,d,e,f,g) env->Func(a,b,c,d,e,f,g)
+#define NSK_CPP_STUB9(Func,env,a,b,c,d,e,f,g,h) env->Func(a,b,c,d,e,f,g,h)
+#endif
+#endif
+
+/*************************************************************/
+
+/**
+ * Use examples:
+ *
+ * NSK_DISPLAY("Test started.\n");
+ * NSK_COMPLAIN("Test FAILED: %s\n",reason);
+ *
+ *
+ */
+
+#define NSK_DISPLAY0(format) nsk_ldisplay(__FILE__,__LINE__,format)
+#define NSK_DISPLAY1(format,a) nsk_ldisplay(__FILE__,__LINE__,format,a)
+#define NSK_DISPLAY2(format,a,b) nsk_ldisplay(__FILE__,__LINE__,format,a,b)
+#define NSK_DISPLAY3(format,a,b,c) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c)
+#define NSK_DISPLAY4(format,a,b,c,d) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d)
+#define NSK_DISPLAY5(format,a,b,c,d,e) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e)
+#define NSK_DISPLAY6(format,a,b,c,d,e,f) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f)
+#define NSK_DISPLAY7(format,a,b,c,d,e,f,g) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g)
+#define NSK_DISPLAY8(format,a,b,c,d,e,f,g,h) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h)
+#define NSK_DISPLAY9(format,a,b,c,d,e,f,g,h,i) nsk_ldisplay(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h,i)
+
+#define NSK_COMPLAIN0(format) nsk_lcomplain(__FILE__,__LINE__,format)
+#define NSK_COMPLAIN1(format,a) nsk_lcomplain(__FILE__,__LINE__,format,a)
+#define NSK_COMPLAIN2(format,a,b) nsk_lcomplain(__FILE__,__LINE__,format,a,b)
+#define NSK_COMPLAIN3(format,a,b,c) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c)
+#define NSK_COMPLAIN4(format,a,b,c,d) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d)
+#define NSK_COMPLAIN5(format,a,b,c,d,e) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e)
+#define NSK_COMPLAIN6(format,a,b,c,d,e,f) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f)
+#define NSK_COMPLAIN7(format,a,b,c,d,e,f,g) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g)
+#define NSK_COMPLAIN8(format,a,b,c,d,e,f,g,h) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h)
+#define NSK_COMPLAIN9(format,a,b,c,d,e,f,g,h,i) nsk_lcomplain(__FILE__,__LINE__,format,a,b,c,d,e,f,g,h,i)
+
+#define NSK_VERIFY(action) (nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action), \
+ nsk_lverify(!!(action),__FILE__,__LINE__,"%s\n",#action))
+#define NSK_TRACE(action) {nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action); \
+ (void)(action); \
+ nsk_ltrace(NSK_TRACE_AFTER,__FILE__,__LINE__,"%s\n",#action);}
+#define NSK_BEFORE_TRACE(action) nsk_ltrace(NSK_TRACE_BEFORE,__FILE__,__LINE__,"%s\n",#action); \
+ (void)(action)
+
+/*************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NSK_TRUE 1
+#define NSK_FALSE 0
+
+#define NSK_TRACE_NONE 0
+#define NSK_TRACE_BEFORE 1
+#define NSK_TRACE_AFTER 2
+#define NSK_TRACE_ALL (NSK_TRACE_BEFORE | NSK_TRACE_AFTER)
+
+#define NSK_MAX_COMPLAINS_NON_VERBOSE 665
+
+/**
+ * Mode is verbose iff "verbose" isn't NSK_FALSE.
+ */
+void nsk_setVerboseMode(int verbose);
+int nsk_getVerboseMode();
+
+/**
+ * Trace mode can be any combination of NSK_TRACE_* flags.
+ */
+void nsk_setTraceMode(int mode);
+int nsk_getTraceMode();
+
+/**
+ * Display the message if current mode is verbose.
+ */
+void nsk_display(const char format[], ...);
+void nsk_vdisplay(const char format[], va_list args);
+/**
+ * Add a prompt to point the file[] and line location.
+ */
+void nsk_ldisplay(const char file[], int line, const char format[], ...);
+void nsk_lvdisplay(const char file[], int line, const char format[], va_list args);
+
+/**
+ * Complain the error message; add an "ERROR" prompt.
+ * No matter, is current mode verbose or not.
+ */
+void nsk_complain(const char format[], ...);
+void nsk_vcomplain(const char format[], va_list args);
+/**
+ * Add a prompt to point the file[] and line location.
+ */
+void nsk_lcomplain(const char file[], int line, const char format[], ...);
+void nsk_lvcomplain(const char file[], int line, const char format[], va_list args);
+
+/**
+ * Trace executable actions,
+ */
+void nsk_ltrace(int mode, const char file[], int line, const char format[], ...);
+void nsk_lvtrace(int mode, const char file[], int line, const char format[], va_list args);
+
+/**
+ * Complain the message as an error if value==0; return !!value.
+ * Add a prompt to point the file[] and line location.
+ * Display anyway if verbose.
+ */
+int nsk_lverify(int value, const char file[], int line, const char format[], ...);
+
+/**
+ * Same as printf() or vprintf(); but we may redefine this later.
+ */
+int nsk_vprintf(const char format[], va_list args);
+int nsk_printf(const char format[], ...);
+
+/**
+ * Print given bytes array as hex numbers in multiple strings, each
+ * started with 'indent' prefix and offset info, followed by 'columns' bytes
+ * as hex numbers, then followed by the same bytes as ASCII chars where
+ * non-printable chars are replaced by '.', and terminated with new line char.
+ * Typically columns number is 16 and should not be greater than 255.
+ */
+void nsk_printHexBytes(const char indent[], int columns,
+ size_t size, const unsigned char bytes[]);
+
+/*************************************************************/
+
+/**
+ * Returns str or "<NULL>" if str is NULL; useful for printing strings.
+ */
+const char* nsk_null_string(const char* str);
+
+/*************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/FinRunner.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package nsk.share.runner;
+
+/**
+ * Helper that calls System.runFinalization().
+ */
+public class FinRunner implements Runnable {
+ public void run() {
+ System.runFinalization();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/GCRunner.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+/**
+ * Helper that calls GC.
+ */
+public class GCRunner implements Runnable {
+ public void run() {
+ System.gc();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MemDiag.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+/**
+ * Helper that prints memory information.
+ */
+public class MemDiag implements Runnable {
+ private long sleepTime;
+
+ public MemDiag() {
+ this(RunParams.getInstance().getSleepTime());
+ }
+
+ public MemDiag(long sleepTime) {
+ this.sleepTime = sleepTime;
+ }
+
+ public void run() {
+ System.out.println(Runtime.getRuntime().freeMemory());
+ // Ensure that interrupt status is not lost
+ if (Thread.currentThread().isInterrupted())
+ return;
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunner.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+import nsk.share.test.ExecutionController;
+
+/**
+ * Interface that defines a way to run several tasks.
+ *
+ * Several implementations are provided.
+ *
+ * @see nsk.share.runner.ThreadsRunner
+ */
+public interface MultiRunner extends Runnable {
+ /**
+ * Add a task.
+ *
+ * @param runnable task
+ */
+ public void add(Runnable runnable);
+
+ /**
+ * Remove a task.
+ *
+ * @param runnable task
+ */
+ public void remove(Runnable runnable);
+
+ /**
+ * Remove all tasks.
+ */
+ public void removeAll();
+
+ /**
+ * Run tasks.
+ */
+ public void run();
+
+ /**
+ * Get status of run.
+ *
+ * @return true if everything is alright, false if there are any errors
+ */
+ public boolean isSuccessful();
+
+ /**
+ * Get execution controller for current thread.
+ *
+ * @returns execution controller for current thread
+ */
+ public ExecutionController getExecutionController();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/MultiRunnerAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+/**
+ * Marker interface for getting MultiRunner.
+ */
+public interface MultiRunnerAware {
+ public void setRunner(MultiRunner runner);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParams.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+import nsk.share.log.Log;
+import nsk.share.test.StressOptions;
+import java.io.PrintStream;
+
+public class RunParams {
+ private StressOptions stressOptions;
+ private long sleepTime = 500;
+ private long iterations = 0;
+ private int numberOfThreads;
+ private long seed = System.currentTimeMillis();
+ private boolean runGCThread = false;
+ private boolean runFinThread = false;
+ private boolean runMemDiagThread = false;
+ private boolean runFinDiagThread = false;
+ private boolean runAllDiagThread = false;
+ private boolean runForever = false;
+ private long threadBlockSize = 64 * 1024 * 1024;
+ private boolean interruptThreads = false;
+
+ public RunParams() {
+ this(new StressOptions());
+ }
+
+ public RunParams(StressOptions stressOptions) {
+ this.stressOptions = stressOptions;
+ numberOfThreads = getMediumLoadThreadsCount();
+ }
+
+ public RunParams(String[] args) {
+ this();
+ parseCommandLine(args);
+ }
+
+ /**
+ * Get an approximate memory which test should fill.
+ *
+ * This can be used to adjust the parameters of allocated objects
+ * to test run environment. Currently it is 3/5 of
+ * Runtime.getRuntime().maxMemory().
+ */
+ public long getTestMemory() {
+ return 3 * Runtime.getRuntime().maxMemory() / 5;
+ }
+
+ /**
+ * Return memory to use for allocation of threads.
+ *
+ * This is currently 3/4 of getTestMemory();
+ */
+ public long getThreadsMemory() {
+ return 3 * getTestMemory() / 4;
+ }
+
+ public final long getSleepTime() {
+ return sleepTime;
+ }
+
+ public final void setSleepTime(long sleepTime) {
+ this.sleepTime = sleepTime;
+ }
+
+ public final long getIterations() {
+ return iterations;
+ }
+
+ public final void setIterations(long iterations) {
+ if (this.iterations != iterations) {
+ this.iterations = iterations;
+ System.out.println("Iterations: " + iterations);
+ }
+ }
+
+ public int getBasicLoadThreadsCount() {
+ int cnt = (int) Math.min(
+ Integer.MAX_VALUE,
+ Math.min(
+ Runtime.getRuntime().availableProcessors(),
+ Math.round((double) Runtime.getRuntime().maxMemory() / threadBlockSize)
+ )
+ );
+
+ // cnt could be equal to 0 in case maxMemory is less than threadBlockSize then
+ // so, need to check this
+ return (cnt > 0 ? cnt : 1);
+ }
+
+ public int getMediumLoadThreadsCount() {
+ return 2 * getBasicLoadThreadsCount();
+ }
+
+ public int getHighLoadThreadsCount() {
+ return 100 * getBasicLoadThreadsCount();
+ }
+
+ public final int getNumberOfThreads() {
+ return numberOfThreads * stressOptions.getThreadsFactor();
+ }
+
+ public final void setNumberOfThreads(int numberOfThreads) {
+ this.numberOfThreads = numberOfThreads;
+ }
+
+ public final long getSeed() {
+ return seed;
+ }
+
+ public final void setSeed(long seed) {
+ this.seed = seed;
+ }
+
+ public final boolean isRunGCThread() {
+ return runGCThread;
+ }
+
+ public final void setRunGCThread(boolean runGCThread) {
+ this.runGCThread = runGCThread;
+ }
+
+ public final boolean isRunFinThread() {
+ return runFinThread;
+ }
+
+ public final void setRunFinThread(boolean runFinThread) {
+ this.runFinThread = runFinThread;
+ }
+
+ public final boolean isRunMemDiagThread() {
+ return runMemDiagThread;
+ }
+
+ public final void setRunMemDiagThread(boolean runMemDiagThread) {
+ this.runMemDiagThread = runMemDiagThread;
+ }
+
+ public final boolean isRunFinDiagThread() {
+ return runFinDiagThread;
+ }
+
+ public final void setRunFinDiagThread(boolean runFinDiagThread) {
+ this.runFinDiagThread = runFinDiagThread;
+ }
+
+ public final boolean isRunAllDiagThread() {
+ return runAllDiagThread;
+ }
+
+ public final void setRunAllDiagThread(boolean runAllDiagThread) {
+ this.runAllDiagThread = runAllDiagThread;
+ }
+
+ public final boolean isRunForever() {
+ return runForever;
+ }
+
+ public final void setRunForever(boolean runForever) {
+ this.runForever = runForever;
+ }
+
+ public final boolean isInterruptThreads() {
+ return interruptThreads;
+ }
+
+ public final void setInterruptThreads(boolean interruptThreads) {
+ this.interruptThreads = interruptThreads;
+ }
+
+ public final StressOptions getStressOptions() {
+ return stressOptions;
+ }
+
+ public void parseCommandLine(String[] args) {
+ if (args == null)
+ return;
+ stressOptions.parseCommandLine(args);
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].equals("-f"))
+ runForever = true;
+ else if (args[i].equals("-tg"))
+ runGCThread = true;
+ else if (args[i].equals("-tf"))
+ runFinThread = true;
+ else if (args[i].equals("-Dm"))
+ runMemDiagThread = true;
+ else if (args[i].equals("-Dm-"))
+ runMemDiagThread = false;
+ else if (args[i].equals("-Df1"))
+ runFinDiagThread = true;
+ else if (args[i].equals("-Df"))
+ runFinDiagThread = true;
+ else if (args[i].equals("-s"))
+ seed = Long.parseLong(args[++i]);
+ else if (args[i].equals("-t"))
+ numberOfThreads = Integer.parseInt(args[++i]);
+ else if (args[i].equals("-it"))
+ interruptThreads = true;
+ else if (args[i].equals("-iterations"))
+ iterations = Integer.parseInt(args[++i]);
+ }
+ printConfig(System.out);
+ }
+
+ public void prinUsage() {
+ }
+
+ public void printConfig(PrintStream out) {
+ stressOptions.printInfo(out);
+ out.println("Max memory: " + Runtime.getRuntime().maxMemory());
+ out.println("Sleep time: " + sleepTime);
+ out.println("Iterations: " + iterations);
+ out.println("Number of threads: " + numberOfThreads);
+ out.println("Seed: " + seed);
+ out.println("Run GC thread: " + runGCThread);
+ out.println("Run mem diag thread: " + runMemDiagThread);
+ out.println("Run forever: " + runForever);
+ }
+
+ public void logConfig(Log log) {
+ log.debug("Max memory: " + Runtime.getRuntime().maxMemory());
+ log.debug("Sleep time: " + sleepTime);
+ log.debug("Iterations: " + iterations);
+ log.debug("Number of threads: " + numberOfThreads);
+ log.debug("Seed: " + seed);
+ log.debug("Run GC thread: " + runGCThread);
+ log.debug("Run mem diag thread: " + runMemDiagThread);
+ log.debug("Run forever: " + runForever);
+ }
+
+ private static RunParams instance;
+
+ public static RunParams getInstance() {
+ synchronized (RunParams.class) {
+ if (instance == null)
+ instance = new RunParams();
+ return instance;
+ }
+ }
+
+ public static void setInstance(RunParams runParams) {
+ synchronized (RunParams.class) {
+ instance = runParams;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/RunParamsAware.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.runner;
+
+/**
+ * Marker interface to signify that run params are needed.
+ */
+public interface RunParamsAware {
+ public void setRunParams(RunParams runParams);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.runner;
+
+import nsk.share.Wicket;
+import nsk.share.gc.OOMStress;
+import nsk.share.log.*;
+import nsk.share.test.Stresser;
+import nsk.share.test.ExecutionController;
+import nsk.share.TestBug;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Helper to assist in running threads.
+ *
+ * This class starts a number of threads which run some tasks in cycle.
+ * They exit after some time or after some iterations as
+ * determined by RunParams.
+ */
+public class ThreadsRunner implements MultiRunner, LogAware, RunParamsAware {
+
+ private Log log;
+ private RunParams runParams;
+ private List<Runnable> runnables = new ArrayList<Runnable>();
+ private List<ManagedThread> threads = new ArrayList<ManagedThread>();
+ private Wicket wicket = new Wicket();
+ private Wicket finished;
+ private boolean started = false;
+ private boolean successful = true;
+
+ public ThreadsRunner() {
+ this(RunParams.getInstance());
+ }
+
+ public ThreadsRunner(RunParams runParams) {
+ setRunParams(runParams);
+ }
+
+ public final void setLog(Log log) {
+ this.log = log;
+ }
+
+ private class ManagedThread extends Thread {
+
+ private Stresser stresser;
+ private Throwable exception;
+ private Runnable test;
+ private boolean shouldWait;
+
+ public ManagedThread(Runnable test) {
+ super(test.toString());
+ this.test = test;
+ this.shouldWait = true;
+ this.stresser = new Stresser(this.getName(), runParams.getStressOptions());
+ }
+
+ public void run() {
+ wicket.waitFor();
+ try {
+ stresser.start(runParams.getIterations());
+ while (!this.isInterrupted() && stresser.iteration()) {
+ test.run();
+ yield();
+ }
+ waitForOtherThreads();
+ } catch (OutOfMemoryError oom) {
+ waitForOtherThreads();
+ if (test instanceof OOMStress) {
+ // Test stressing OOM, not a failure.
+ log.info("Caught OutOfMemoryError in OOM stress test, omitting exception.");
+ } else {
+ failWithException(oom);
+ }
+ } catch (Throwable t) {
+ waitForOtherThreads();
+ failWithException(t);
+ } finally {
+ stresser.finish();
+ }
+ }
+
+ private void waitForOtherThreads() {
+ if (shouldWait) {
+ shouldWait = false;
+ finished.unlock();
+ finished.waitFor();
+ } else {
+ throw new TestBug("Waiting a second time is not premitted");
+ }
+ }
+
+ private void failWithException(Throwable t) {
+ log.debug("Exception in ");
+ log.debug(test);
+ log.debug(t);
+ exception = t;
+ }
+
+ public void forceFinish() {
+ stresser.forceFinish();
+ if (runParams.isInterruptThreads()) {
+ log.debug("Interrupting: " + this);
+ this.interrupt();
+ }
+ }
+
+ public final Throwable getException() {
+ return exception;
+ }
+
+ public final ExecutionController getExecutionController() {
+ return stresser;
+ }
+ }
+
+ public void add(Runnable runnable) {
+ runnables.add(runnable);
+ }
+
+ public void remove(Runnable runnable) {
+ runnables.remove(runnable);
+ }
+
+ public void removeAll() {
+ runnables.clear();
+ }
+
+ private Runnable get(int index) {
+ return (Runnable) runnables.get(index);
+ }
+
+ public Thread getThread(int index) {
+ return threads.get(index);
+ }
+
+ private int getCount() {
+ return runnables.size();
+ }
+
+ private void prepare() {
+ }
+
+ private void create() {
+ int threadCount = runnables.size();
+ finished = new Wicket(threadCount);
+ for (int i = 0; i < threadCount; ++i) {
+ threads.add(new ManagedThread(get(i)));
+ }
+ }
+
+ /**
+ * Start threads that run the tasks.
+ */
+ public void start() {
+ if (started) {
+ return;
+ }
+ create();
+ prepare();
+ for (int i = 0; i < threads.size(); ++i) {
+ Thread t = (Thread) threads.get(i);
+ log.debug("Starting " + t);
+ t.start();
+ }
+ wicket.unlock();
+ started = true;
+ }
+
+ /**
+ * Stop threads that run the tasks.
+ */
+ public void forceFinish() {
+ log.info("Forcing threads to finish");
+ for (int i = 0; i < threads.size(); i++) {
+ ManagedThread thread = threads.get(i);
+ thread.forceFinish();
+ }
+ }
+
+ /**
+ * Join threads that run the tasks.
+ */
+ public void join() throws InterruptedException {
+ for (int i = 0; i < threads.size(); ++i) {
+ Thread t = (Thread) threads.get(i);
+ //log.debug("Joining " + t);
+ t.join();
+ }
+ }
+
+ private int dumpFailures() {
+ int n = 0;
+ for (int i = 0; i < threads.size(); i++) {
+ ManagedThread thread = threads.get(i);
+ Throwable exception = thread.getException();
+ if (exception != null) {
+ if (n == 0) {
+ log.error("Failures summary:");
+ }
+ ++n;
+ log.error(exception);
+ }
+ }
+ if (n == 0) {
+ log.info("No unexpected exceptions/errors are thrown");
+ }
+ return n;
+ }
+
+ private ManagedThread findManagedThread(Thread t) {
+ for (int i = 0; i < threads.size(); i++) {
+ ManagedThread mt = threads.get(i);
+ if (mt == t) {
+ return mt;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Run threads as determined by RunParams.
+ *
+ * Start threads, run for some time or for some number of iterations,
+ * then join and report if there were any exceptions.
+ *
+ * This method may additionally run other threads (as determined by RunParams):
+ * - thread that does System.gc() in cycle, @see GCRunner
+ * - thread that prints memory information in cycle, @see MemDiag
+ * - thread that prints information about FinMemoryObject's in cycle, @see FinDiag
+ * - thread that prints information about AllMemoryObject's in cycle, @see AllDiag
+ *
+ * @return true if there were no exceptions, false otherwise
+ */
+ public void run() {
+ if (runParams.isRunGCThread()) {
+ add(new GCRunner());
+ }
+ if (runParams.isRunFinThread()) {
+ add(new FinRunner());
+ }
+ if (runParams.isRunMemDiagThread()) {
+ add(new MemDiag());
+ }
+ try {
+ start();
+ join();
+ successful = dumpFailures() == 0;
+ } catch (Throwable t) {
+ log.info("Unexpected exception during the run.");
+ log.info(t);
+ successful = false;
+ }
+ }
+
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+ public ExecutionController getExecutionController() {
+ Thread ct = Thread.currentThread();
+ ManagedThread t = findManagedThread(ct);
+ if (t != null) {
+ return t.getExecutionController();
+ } else {
+ throw new TestBug("Unable to find managed thread for thread (this method should be called from one of managed threads): " + ct);
+ }
+ }
+
+ public void runForever() {
+ start();
+ }
+
+ public final void setRunParams(RunParams runParams) {
+ this.runParams = runParams;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersBTree.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.sysdict;
+
+import nsk.share.*;
+
+/**
+ * A binary tree of class loaders.
+ *
+ * @see TreeNodesDenotation
+ */
+public class ClassLoadersBTree {
+ /**
+ * Cannot instantiate while a tree root and height
+ * are not specified.
+ *
+ * @see #ClassLoadersBTree(ClassLoader,int)
+ */
+ protected ClassLoadersBTree() {
+ }
+
+ /**
+ * Given the <tt>root</tt> loader, instantiate a binary tree
+ * of loaders up to the given tree <tt>height</tt>.
+ *
+ * @see #getHeight()
+ * @see #getRoot()
+ * @see #getLoader(String)
+ * @see #getLoader(int,int)
+ */
+ public ClassLoadersBTree(ClassLoader root, int height) {
+ if (height < 1)
+ throw new IllegalArgumentException("wrong height: " + height);
+ loaders = new ClassLoader [ height ] [];
+ for (int level=0; level<height; level++)
+ loaders[level] = new ClassLoader [1 << level];
+ loaders[0][0] = root;
+ generateSubtree("");
+ }
+ private void generateSubtree(String name) {
+ int level = name.length();
+ int height = loaders.length;
+ if (level+1 == height)
+ return;
+ String nameL = name + "L";
+ String nameR = name + "R";
+ int[] index = denotation.indexFor(name);
+ int[] indexL = denotation.indexFor(nameL);
+ int[] indexR = denotation.indexFor(nameR);
+ // assertion: index[0] == level
+ // assertion: indexL[0] == indexR[0] == level+1
+ int item = index[1];
+ int itemL = indexL[1];
+ int itemR = indexR[1];
+ ClassLoader parent = loaders[level][item];
+ ClassLoader childL = new DummyClassLoader(parent);
+ ClassLoader childR = new DummyClassLoader(parent); // another item
+ loaders[level+1][itemL] = childL;
+ loaders[level+1][itemR] = childR;
+ generateSubtree(nameL);
+ generateSubtree(nameR);
+ }
+
+ private ClassLoader loaders[][]; // loaders[0][0] is root
+ private Denotation denotation = new TreeNodesDenotation();
+
+ /**
+ * Return the loader found at the given <tt>level</tt> of
+ * this loaders tree, and having the given <tt>item</tt>
+ * number at the enumeration of that <tt>level</tt>.
+ *
+ * <p>The value of <tt>level</tt> must be from <tt>0</tt>
+ * to <tt>getHeight()-1</tt>, and the <tt>item</tt> number
+ * must be from <tt>0</tt> to <tt>2<sup>level</sup>-1</tt>.
+ *
+ * @see #getHeight()
+ * @see #getRoot()
+ * @see #getLoader(String)
+ */
+ public ClassLoader getLoader(int level, int item) {
+ return loaders[level][item];
+ }
+
+ /**
+ * Return the loader having the giving <tt>name</tt> at
+ * the standard denotation of binary tree nodes.
+ *
+ * @see #getHeight()
+ * @see #getRoot()
+ * @see #getLoader(int,int)
+ */
+ public ClassLoader getLoader(String name) {
+ int[] index = denotation.indexFor(name);
+ int level = index[0];
+ int item = index[1];
+ return loaders[level][item];
+ }
+
+ /**
+ * Return the tree's height.
+ *
+ * @see #ClassLoadersBTree(ClassLoader,int)
+ * @see #getLoader(int,int)
+ * @see #getLoader(String)
+ */
+ public int getHeight() {
+ return loaders.length;
+ }
+
+ /**
+ * Return the tree's root loader.
+ *
+ * @see #ClassLoadersBTree(ClassLoader,int)
+ * @see #getLoader(int,int)
+ * @see #getLoader(String)
+ */
+ public ClassLoader getRoot() {
+ return loaders[0][0];
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/sysdict/ClassLoadersChain.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.sysdict;
+
+import nsk.share.*;
+
+/**
+ * A chain of class loaders. Imagine a chain as a tower
+ * growing downstairs: the 0<sup>th</sup> level is the
+ * root, and a level n+1 loader has the n<sup>th</sup>
+ * loader as the parent.
+ */
+public class ClassLoadersChain {
+ /**
+ * Cannot instantiate while a chain root and height
+ * are not specified.
+ *
+ * @see #ClassLoadersChain(ClassLoader,int)
+ */
+ protected ClassLoadersChain() {
+ }
+
+ /**
+ * Given the <tt>root</tt> loader, instantiate a chain
+ * of loaders up to the given <tt>height</tt>.
+ *
+ * @see #getHeight()
+ * @see #getRoot()
+ * @see #getLoader(int)
+ */
+ public ClassLoadersChain(ClassLoader root, int height) {
+ if (height < 1)
+ throw new IllegalArgumentException("wrong height: " + height);
+ loaders = new ClassLoader [ height ];
+ loaders[0] = root;
+ for (int i=1; i<height; i++)
+ loaders[i] = new DummyClassLoader(loaders[i-1]);
+ }
+
+ private ClassLoader loaders[]; // loaders[0] is the root
+
+ /**
+ * Return the loader found at the given <tt>level</tt>.
+ * The value of <tt>level</tt> must be from <tt>0</tt>
+ * to <tt>getHeight()-1</tt>.
+ *
+ * @see #getHeight()
+ * @see #getRoot()
+ */
+ public ClassLoader getLoader(int level) {
+ return loaders[level];
+ }
+
+ /**
+ * Return the chain's height.
+ *
+ * @see #ClassLoadersChain(ClassLoader,int)
+ * @see #getLoader(int)
+ */
+ public int getHeight() {
+ return loaders.length;
+ }
+
+ /**
+ * Return the chain's root loader.
+ *
+ * @see #ClassLoadersChain(ClassLoader,int)
+ * @see #getLoader(int)
+ */
+ public ClassLoader getRoot() {
+ return loaders[0];
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Dumpable.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+import nsk.share.log.Log;
+
+public interface Dumpable {
+ public void dump(Log log);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/ExecutionController.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+public interface ExecutionController {
+ public void start(long stdIterations);
+ public boolean iteration();
+ public boolean continueExecution();
+ public long getIteration();
+ public void finish();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Initializable.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+/**
+ * Marker interface for initialization.
+ */
+public interface Initializable {
+ public void initialize();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyFormatString.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+public class LazyFormatString {
+
+ private String format;
+ private Object[] args;
+
+ public LazyFormatString(String format, Object... args) {
+ this.format = format;
+ this.args = args;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(format, args);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyIntArrayToString.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+import java.util.Arrays;
+
+public class LazyIntArrayToString {
+
+ private int[] array;
+
+ public LazyIntArrayToString(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(array);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LazyObjectArrayToString.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+import java.util.Arrays;
+
+public class LazyObjectArrayToString {
+
+ private Object[] array;
+
+ public LazyObjectArrayToString(Object[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(array);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/LocalRandom.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+import java.util.concurrent.ThreadLocalRandom;
+import nsk.share.TestFailure;
+
+/**
+ * Utility class which encapsulates all useful static methods.
+ */
+public class LocalRandom {
+ private static int minPauseTime = 3000;
+ private static int maxPauseTime = 5000;
+ private static int maxRandomCount = 65536;
+
+ /*
+ * Return next random double number.
+ *
+ * @return random double
+ */
+ public static double random() {
+ return ThreadLocalRandom.current().nextDouble();
+ }
+
+ public static double nextDouble() {
+ return ThreadLocalRandom.current().nextDouble();
+ }
+
+ public static byte nextByte() {
+ return (byte) nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE);
+ }
+
+ public static char nextChar() {
+ return (char) nextInt(Character.MIN_VALUE, Character.MAX_VALUE);
+ }
+
+ public static short nextShort() {
+ return (short) nextInt(Short.MIN_VALUE, Short.MAX_VALUE);
+ }
+
+ public static boolean nextBoolean() {
+ return ThreadLocalRandom.current().nextBoolean();
+ }
+
+ public static void nextBytes(byte[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ byte hash = 0;
+ byte b;
+ for (int i = 0; i < arr.length - k; i += k) {
+ b = nextByte();
+ arr[i] = b;
+ hash ^= b;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(byte[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ byte hash = 0;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != 0) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextShorts(short[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ short hash = 0;
+ short s;
+ for (int i = 0; i < arr.length - k; i += k) {
+ s = nextShort();
+ arr[i] = s;
+ hash ^= s;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(short[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ short hash = 0;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != 0) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextChars(char[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ char hash = 0;
+ char c;
+ for (int i = 0; i < arr.length - k; i += k) {
+ c = nextChar();
+ arr[i] = c;
+ hash ^= c;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(char[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ char hash = 0;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != 0) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextInts(int[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ int hash = 0;
+ int in;
+ for (int i = 0; i < arr.length - k; i += k) {
+ in = nextInt();
+ hash ^= in;
+ arr[i] = in;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(int[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ int hash = 0;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != 0) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextBooleans(boolean[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ boolean hash = false;
+ boolean b;
+ for (int i = 0; i < arr.length - k; i += k) {
+ b = nextBoolean();
+ hash ^= b;
+ arr[i] = b;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(boolean[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ boolean hash = false;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != false) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextLongs(long[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ long hash = 0;
+ long l;
+ for (int i = 0; i < arr.length - k; i += k) {
+ l = nextLong();
+ hash ^= l;
+ arr[i] = l;
+ }
+ arr[arr.length - k] = hash;
+ }
+
+ public static void validate(long[] arr) {
+ int k = Math.max(1, arr.length / maxRandomCount);
+ long hash = 0;
+ for (int i = 0; i < arr.length; i += k) {
+ hash ^= arr[i];
+ }
+ if (hash != 0) {
+ throw new TestFailure(
+ "Validation failure: " + arr.getClass() + " hash: " + hash);
+ }
+ }
+
+ public static void nextFloats(float[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ for (int i = 0; i < arr.length - k; i += k) {
+ arr[i] = nextFloat();
+ }
+ }
+
+ public static void validate(float[] arr) {
+ }
+
+ public static void nextDoubles(double[] arr) {
+ if (arr.length == 0) {
+ return;
+ }
+ int k = Math.max(1, arr.length / maxRandomCount);
+ for (int i = 0; i < arr.length - k; i += k) {
+ arr[i] = nextDouble();
+ }
+ }
+
+ public static void validate(double[] arr) {
+ }
+
+ public static int nextInt() {
+ return ThreadLocalRandom.current().nextInt();
+ }
+
+ /**
+ * Return next integer value from 0..n range.
+ *
+ * @param n maximum value
+ * @return random integer
+ */
+ public static int nextInt(int n) {
+ return ThreadLocalRandom.current().nextInt(n);
+ }
+
+ public static long nextLong() {
+ return ThreadLocalRandom.current().nextLong();
+ }
+
+ /**
+ * Return next random integer from min..max range.
+ *
+ * @param min minimum value
+ * @param max maximum value
+ * @return random integer
+ */
+ public static int nextInt(int min, int max) {
+ return min + nextInt(max - min);
+ }
+
+ /**
+ * Return next random float number.
+ *
+ * @return random double
+ */
+ public static float nextFloat() {
+ return ThreadLocalRandom.current().nextFloat();
+ }
+
+ /**
+ * Return random pause time.
+ */
+ public static long randomPauseTime() {
+ return nextInt(minPauseTime, maxPauseTime);
+ }
+
+ /**
+ * Set minimum pause time.
+ *
+ * @param minPauseTime minimum pause time
+ */
+ public static void setMinPauseTime(int minPauseTime) {
+ LocalRandom.minPauseTime = minPauseTime;
+ }
+
+ /**
+ * Set maximum pause time.
+ *
+ * @param maxPauseTime maximum pause time
+ */
+ public static void setMaxPauseTime(int maxPauseTime) {
+ LocalRandom.maxPauseTime = maxPauseTime;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/StressOptions.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+import java.io.PrintStream;
+import vm.share.options.Option;
+
+/**
+ * Options for stress tests.
+ *
+ * The following options may be configured:
+ *
+ * -stressTime [time] execution time in seconds
+ * -stressIterationsFactor [factor] iterations factor.
+ * The actual number of iterations is obtained by multiplying standard
+ * number of iterations (which is defined by the test itself) and this factor.
+ * -stressThreadsFactor [factor] number of threads factor
+ * The actual number of threads is determined by multiplying standard
+ * number of threads (which is determined by test itself and may also depend
+ * on machine configuration) and this factor.
+ */
+public class StressOptions {
+ /**
+ * This enum contains names of stress options
+ */
+ public static enum StressOptionsParam {
+ stressTime,
+ stressIterationsFactor,
+ stressThreadsFactor,
+ stressRunsFactor,
+ stressDebug,
+ stressDebugDetailed,
+ }
+
+ /* Execution time in seconds */
+ @Option(name = "stressTime", default_value = "60", description = "Stress execution time in seconds")
+ private long time;
+
+ /* Iterations factor */
+ @Option(name = "stressIterationsFactor", default_value = "1", description = "Stress iterations factor")
+ private int iterationsFactor;
+
+ /* Number of threads factor */
+ @Option(name = "stressThreadsFactor", default_value = "1", description = "Stress threads factor")
+ private int threadsFactor;
+
+ @Option(name = "stressRunsFactor", default_value = "1", description = "Times to re-run the test (if supported by the test)")
+ private int runsFactor;
+
+ /* Debug stress execution */
+ @Option(name = "stressDebugEnabled", default_value = "false", description = "Stress debug execution enabled")
+ private boolean debugEnabled = false;
+
+ /* Detailed stressExecution */
+ @Option(name = "stressDebugDetailed", default_value = "false", description = "Stress debug detailed enabled")
+ private boolean debugDetailed = false;
+
+ /**
+ * Create StressOptions with default settings.
+ */
+ public StressOptions() {
+ time = 60;
+ iterationsFactor = 1;
+ threadsFactor = 1;
+ runsFactor = 1;
+ }
+
+ /**
+ * Create StressOptions configured from command line arguments.
+ *
+ * @param arg arguments
+ */
+ public StressOptions(String[] args) {
+ this();
+ parseCommandLine(args);
+ }
+
+ /**
+ * Create stresser with same parameters as another.
+ *
+ * @param other another instance of StressOptions
+ */
+ public StressOptions(StressOptions other) {
+ this.time = other.time;
+ this.iterationsFactor = other.iterationsFactor;
+ this.threadsFactor = other.threadsFactor;
+ this.runsFactor = other.runsFactor;
+ }
+
+ public static boolean isValidStressOption(String option) {
+ for (int i = 0; i < StressOptions.StressOptionsParam.values().length; i++) {
+ if (option.equals(StressOptions.StressOptionsParam.values()[i].name()))
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse command line options related to stress.
+ *
+ * Other options are ignored.
+ *
+ * @param args arguments
+ */
+ public void parseCommandLine(String[] args) {
+ int i = 0;
+ while (i < args.length) {
+ String arg = args[i];
+ String value = null;
+
+ int eqPos = arg.indexOf('=');
+ if (eqPos != -1) {
+ value = arg.substring(eqPos + 1);
+ arg = arg.substring(0, eqPos);
+ }
+
+ if (arg.equals("-stressTime")) {
+ try {
+ if (value == null) {
+ if (++i >= args.length)
+ error("Missing value of -stressTime parameter");
+ value = args[i];
+ }
+ time = Long.parseLong(value);
+ if (time < 0) {
+ error("Invalid value of -stressTime parameter: " + time);
+ }
+ } catch (NumberFormatException e) {
+ error("Invalid value of -stressTime parameter: " + value);
+ }
+ } else if (arg.equals("-stressIterationsFactor")) {
+ try {
+ if ( value == null ) {
+ if (++i >= args.length) {
+ error("Missing value of -stressIterationsFactor parameter");
+ }
+ value = args[i];
+ }
+ iterationsFactor = Integer.parseInt(value);
+ if (iterationsFactor <= 0) {
+ error("Invalid value of -stressIterationsFactor parameter: " + threadsFactor);
+ }
+ } catch (NumberFormatException e) {
+ error("Invalid value of -stressIterationsFactor parameter: " + value);
+ }
+ } else if (arg.equals("-stressThreadsFactor")) {
+ try {
+ if ( value == null ) {
+ if (++i >= args.length) {
+ error("Missing value of -stressThreadsFactor parameter");
+ }
+ value = args[i];
+ }
+ threadsFactor = Integer.parseInt(value);
+ if (threadsFactor <= 0) {
+ error("Invalid value of -stressThreadsFactor parameter: " + threadsFactor);
+ }
+ } catch (NumberFormatException e) {
+ error("Invalid value of -stressThreadsFactor parameter: " + value);
+ }
+ } else if (arg.equals("-stressRunsFactor")) {
+ try {
+ if (value == null) {
+ if (++i >= args.length) {
+ error("Missing value of -stressRunsFactor parameter");
+ }
+ value = args[i];
+ }
+ runsFactor = Integer.parseInt(value);
+ if (runsFactor <= 0) {
+ error("Invalid value of -stressRunsFactor parameter: " + threadsFactor);
+ }
+ } catch (NumberFormatException e) {
+ error("Invalid value of -stressRunsFactor parameter: " + value);
+ }
+ } else if (arg.equals("-stressDebug")) {
+ debugEnabled = true;
+ } else if (arg.equals("-stressDebugDetailed")) {
+ debugDetailed = true;
+ }
+
+ ++i;
+ }
+ }
+
+ /**
+ * Display information about stress options.
+ *
+ * @param out output stream
+ */
+ public void printInfo(PrintStream out) {
+ out.println("Stress time: " + time + " seconds");
+ out.println("Stress iterations factor: " + iterationsFactor);
+ out.println("Stress threads factor: " + threadsFactor);
+ out.println("Stress runs factor: " + runsFactor);
+ }
+
+ private void error(String msg) {
+ throw new IllegalArgumentException(msg);
+ }
+
+ /**
+ * Obtain execution time in seconds.
+ *
+ * @return time
+ */
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * Obtain iterations factor.
+ *
+ * @return iterations factor
+ */
+ public int getIterationsFactor() {
+ return iterationsFactor;
+ }
+
+ /**
+ * Obtain threads factor.
+ *
+ * @return threads factor
+ */
+ public int getThreadsFactor() {
+ return threadsFactor;
+ }
+
+ /**
+ * Obtain runs factor.
+ *
+ * @return runs factor
+ */
+ public int getRunsFactor() {
+ return runsFactor;
+ }
+
+ /**
+ * Determine if debugging of stress execution is set.
+ *
+ * @return true if debugging stress execution
+ */
+ public boolean isDebugEnabled() {
+ return debugEnabled;
+ }
+
+ /**
+ * Determine if detailed debugging of stress execution is set.
+ *
+ * @return true if detailed debugging is enabled
+ */
+ public boolean isDebugDetailed() {
+ return debugDetailed;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Stresser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+import java.io.PrintStream;
+import nsk.share.TestBug;
+
+/**
+ * Support class for implementing configurable stress execution.
+ *
+ * This class is intended to be used in one thread
+ *
+ * <code>
+ * Stresser stresser = new Stresser(stressOptions);
+ *
+ * try {
+ * stresser.start(100);
+ * while (stresser.iteration()) {
+ * ...
+ * }
+ * } finally {
+ * stresser.finish();
+ * }
+ * </code>
+ *
+ * Standard number of iterations (integer parameter to start() method) is
+ * defined by particular test itself. It may be different for different tests
+ * because average execution time of one iteration may be different.
+ * This is value which is enough to do what test intends to do and it should
+ * also give average execution time on most configurations less than
+ * standard value of stressTime parameter (60 seconds).
+ *
+ * @see nsk.share.test.StressOptions for explanation of stress options.
+ */
+public class Stresser implements ExecutionController {
+
+ private StressOptions options;
+ private String name;
+ private long maxIterations;
+ private long iterations;
+ private long startTime;
+ private long finishTime;
+ private long currentTime;
+ private PrintStream defaultOutput = System.out;
+
+ /*
+ * Flag which indicates that execution is finished.
+ * Volatile, because another thread might read this variable.
+ */
+ private volatile boolean finished;
+
+ /*
+ * Flag which indicates that execution should be forced to finish.
+ * Volatile, because another thread might set this variable.
+ */
+ private volatile boolean forceFinish;
+
+ /**
+ * Creates stresser with default settings.
+ */
+ public Stresser() {
+ this(new StressOptions());
+ }
+
+ /**
+ * Creates stresser with given options.
+ *
+ * @param options stress options
+ */
+ public Stresser(StressOptions options) {
+ setOptions(options);
+ }
+
+ /**
+ * Create stresser configured from command line arguments.
+ *
+ * @param arg arguments
+ */
+ public Stresser(String[] args) {
+ this(new StressOptions(args));
+ }
+
+ /**
+ * Creates stresser configured from command line arguments and
+ * sets its output stream to a given one
+ *
+ * @param arg arguments
+ * @param out default output stream
+ */
+ public Stresser(String[] args, PrintStream out) {
+ this(new StressOptions(args));
+ setDefaultOutput(out);
+ }
+
+ /**
+ * Creates stresser with default options and given name.
+ *
+ * @param name stresser name
+ */
+ public Stresser(String name) {
+ this();
+ setName(name);
+ }
+
+ /**
+ * Creates stresser with given name and options.
+ *
+ * @param name stresser name
+ * @param options stress options
+ */
+ public Stresser(String name, StressOptions options) {
+ this(options);
+ setName(name);
+ }
+
+ /**
+ * Creates stresser with given name from command line arguments.
+ *
+ * @param name stresser name
+ * @param args arguments
+ */
+ public Stresser(String name, String[] args) {
+ this(args);
+ setName(name);
+ }
+
+ /**
+ * Sets default output stream for printing debug messages.
+ * Initially it is set to System.out.
+ *
+ * @param out The stream to print to
+ */
+ public void setDefaultOutput(PrintStream out) {
+ defaultOutput = out;
+ }
+
+ /**
+ * Displays information about stress options.
+ */
+ public void printStressOptions(PrintStream out) {
+ options.printInfo(out);
+ }
+
+ /**
+ * Displays information about this stresser.
+ *
+ * @param out output stream
+ */
+ public void printStressInfo(PrintStream out) {
+ println(out, "Stress time: " + options.getTime() + " seconds");
+ println(out, "Iterations: " + maxIterations);
+ }
+
+ /**
+ * Displays information about this particular execution
+ * of this stresser.
+ *
+ * @param out output stream
+ */
+ public void printExecutionInfo(PrintStream out) {
+ println(out, "Completed iterations: " + iterations);
+ println(out, "Execution time: " + (currentTime - startTime) + " seconds");
+ if (!finished) {
+ println(out, "Execution is not finished yet");
+ } else if (forceFinish) {
+ println(out, "Execution was forced to finish");
+ } else if (maxIterations != 0 && iterations >= maxIterations) {
+ println(out, "Execution finished because number of iterations was exceeded: " + iterations + " >= " + maxIterations);
+ } else if (finishTime != 0 && currentTime >= finishTime) {
+ println(out, "Execution finished because time was exceeded: " + (currentTime - startTime) + " >= " + (finishTime - startTime));
+ }
+ }
+
+ private void println(PrintStream out, String s) {
+ if (name != null) {
+ out.print(name);
+ out.print(": ");
+ }
+ out.println(s);
+ out.flush();
+ }
+
+ /**
+ * Starts stress execution.
+ *
+ * @param stdIterations standard number of iterations.
+ */
+ public void start(long stdIterations) {
+ maxIterations = stdIterations * options.getIterationsFactor();
+ iterations = 0;
+ long stressTime = options.getTime();
+ startTime = System.currentTimeMillis();
+ if (stressTime == 0) {
+ finishTime = 0;
+ } else {
+ finishTime = startTime + stressTime * 1000;
+ }
+ finished = false;
+ forceFinish = false;
+ if (options.isDebugEnabled()) {
+ println(defaultOutput, "Starting stress execution: " + stdIterations);
+ printStressInfo(defaultOutput);
+ }
+ }
+
+ /**
+ * Finishes stress execution.
+ *
+ * This method should be called from the thread where
+ * execution is performed after the loop. It is also
+ * recommended that this method is called from
+ * finally {} block.
+ */
+ public void finish() {
+ currentTime = System.currentTimeMillis();
+ finished = true;
+ if (options.isDebugEnabled()) {
+ printExecutionInfo(defaultOutput);
+ }
+ }
+
+ /**
+ * Forces execution to finish.
+ *
+ * This method may be called from other thread.
+ */
+ public void forceFinish() {
+ forceFinish = true;
+ }
+
+ /**
+ * Marks the beginning of new iteration.
+ *
+ * @return true if execution needs to continue
+ */
+ public boolean iteration() {
+ ++iterations;
+ if (options.isDebugDetailed()) {
+ printExecutionInfo(defaultOutput);
+ }
+ return continueExecution();
+ }
+
+ /**
+ * Checks if execution needs to continue. This does not mark new iteration.
+ *
+ * @return true if execution needs to continue
+ */
+ public boolean continueExecution() {
+ currentTime = System.currentTimeMillis();
+ if (startTime == 0) {
+ throw new TestBug("Stresser is not started.");
+ }
+ return !forceFinish
+ && !finished
+ && (maxIterations == 0 || iterations < maxIterations)
+ && (finishTime == 0 || currentTime < finishTime);
+ }
+
+ /**
+ * Obtains current iteration number.
+ *
+ * @return current iteration
+ */
+ public long getIteration() {
+ return iterations;
+ }
+
+ /**
+ * Obtains maximum number of iterations.
+ *
+ * @return max number of iterations
+ */
+ public long getMaxIterations() {
+ return maxIterations;
+ }
+
+ public long getIterationsLeft() {
+ if (iterations >= maxIterations) {
+ return 0;
+ } else {
+ return maxIterations - iterations;
+ }
+ }
+
+ /**
+ * Obtains time passed from start of stress execution in milliseconds.
+ *
+ * @return time
+ */
+ public long getExecutionTime() {
+ return System.currentTimeMillis() - startTime;
+ }
+
+ /**
+ * Obtains time left till end of execution in milliseconds.
+ *
+ * @return time
+ */
+ public long getTimeLeft() {
+ long current = System.currentTimeMillis();
+ if (current >= finishTime) {
+ return 0;
+ } else {
+ return finishTime - current;
+ }
+ }
+
+ /**
+ * Sets stress options for this stresser.
+ *
+ * @param options stress options
+ */
+ public void setOptions(StressOptions options) {
+ this.options = options;
+ }
+
+ /**
+ * Sets name of this stresser.
+ *
+ * @param name name of stresser
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Obtains name of this stresser.
+ */
+ public String getName() {
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Test.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+/**
+ * Test marker interface.
+ */
+public interface Test extends Runnable {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestBase.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+import nsk.share.log.Log;
+import nsk.share.log.LogAware;
+import nsk.share.Consts;
+import vm.share.options.OptionSupport;
+import vm.share.options.Option;
+import vm.share.options.Options;
+
+public abstract class TestBase implements Test, LogAware, TestExitCode {
+ @Option
+ protected Log log;
+ protected volatile int exitCode = 0;
+
+ public final void setLog(Log log) {
+ this.log = log;
+ }
+
+ public final int getExitCode() {
+ return exitCode;
+ }
+
+ public final void setExitCode(int exitCode) {
+ this.exitCode = exitCode;
+ }
+
+ public final void setFailed(boolean failed) {
+ setExitCode(Consts.JCK_STATUS_BASE + (failed ? Consts.TEST_FAILED : Consts.TEST_PASSED));
+ }
+
+ public final boolean isFailed() {
+ return exitCode != 0 && exitCode != 95;
+ }
+
+ public static void runTest(TestBase test, String[] args) {
+ OptionSupport.setup(test, args);
+ test.run();
+ int exitCode = test.getExitCode();
+ if (exitCode != 0)
+ System.exit(exitCode);
+ else
+ System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestExitCode.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+/**
+ * Marker interface to signify that test needs to return exit code.
+ */
+public interface TestExitCode {
+ public int getExitCode();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/TestUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+
+import nsk.share.Failure;
+import nsk.share.TestFailure;
+
+import static java.lang.String.format;
+
+public class TestUtils {
+ /**
+ * @throws nsk.share.Failure with given error message
+ *
+ */
+ public static void testFailed(Object errorMessage) {
+ throw new Failure(errorMessage.toString());
+ }
+
+ /**
+ * Checks that expr is true
+ *
+ * @throws nsk.share.Failure
+ * when expr is false
+ */
+ public static void assertTrue(boolean expr, Object errorMessage) {
+ if (!expr)
+ testFailed(errorMessage);
+ }
+
+ /**
+ * Checks that obj is not null
+ *
+ * @throws nsk.share.Failure
+ * when obj is null
+ */
+ public static void assertNotNull(Object obj, Object errorMessage) {
+ assertTrue(obj != null, errorMessage);
+ }
+
+ /**
+ * Checks that obj1 equal obj2
+ *
+ * @throws nsk.share.Failure
+ * when obj1 is not equal obj2
+ */
+ public static void assertEquals(Object obj1, Object obj2, Object errorMessage) {
+ assertTrue(obj1.equals(obj2), new LazyFormatString("%s: [%s] != [%s]", errorMessage, obj1, obj2));
+ }
+
+ public static <T> void assertNotInCollection(Collection<T> list, T value) {
+ assertTrue(! list.contains(value), new LazyFormatString("Internal error: %s is in collection %s", value, list));
+ }
+
+ public static <T> void assertInCollection(Collection<T> list, T value) {
+ assertTrue(list.contains(value), new LazyFormatString("Internal error: %s is not in collection %s", value, list));
+ }
+
+ public static void assertEquals(int i1, int i2) {
+ if (i1 != i2) {
+ throw new TestFailure(
+ format("Check failed: %d != %d", i1, i2));
+ }
+ }
+
+ public static void fail(String msg) {
+ throw new TestFailure(msg);
+ }
+
+ public static void assertEquals(String s1, String s2) {
+ if (s1 == null && s2 == null) {
+ return;
+ }
+
+ if (s1 != null && s1.equals(s2)) {
+ return;
+ }
+
+ throw new TestFailure(format("Failed: %s != %s", s1, s2));
+ }
+
+ /**
+ * Check that obj is an instance of a class c.
+ *
+ * @param obj
+ * @param c
+ */
+ public static void assertExactClass(Object obj, Class c) {
+ if (obj.getClass() != c) {
+ throw new TestFailure(format("Exact class doesn't match: expected: %s; actual: %s",
+ c.getName(), obj.getClass().getName()));
+ }
+ }
+ /**
+ * @throws nsk.share.Failure (given exception is set as Failure cause)
+ *
+ */
+ public static void unexpctedException(Throwable exception) {
+ throw new Failure("Unexpected exception: " + exception, exception);
+ }
+
+ public static <T> T[] concatArrays(T[] a1, T[] a2) {
+ T[] result = Arrays.copyOf(a1, a1.length + a2.length);
+ System.arraycopy(a2, 0, result, a1.length, a2.length);
+ return result;
+ }
+
+ public static <T> T[] concatArrays(T[] a1, T[] a2, T[] a3) {
+ T[] result = Arrays.copyOf(a1, a1.length + a2.length + a3.length);
+ System.arraycopy(a2, 0, result, a1.length, a2.length);
+ System.arraycopy(a3, 0, result, a1.length + a2.length, a3.length);
+ return result;
+ }
+
+ public static <T> T[] concatArrays(T a1, T[] a2) {
+ @SuppressWarnings("unchecked")
+ T[] result = (T[]) Array.newInstance(a1.getClass(), 1 + a2.length);
+ result[0] = a1;
+ System.arraycopy(a2, 0, result, 1, a2.length);
+ return result;
+ }
+
+ public static <T> T[] cdr(T[] args) {
+ return Arrays.copyOfRange(args, 1, args.length);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/Tests.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package nsk.share.test;
+
+import nsk.share.log.*;
+import nsk.share.runner.*;
+import nsk.share.TestFailure;
+
+public class Tests {
+ protected static class TestRunner {
+ protected String[] args;
+ private Log log;
+ private MultiRunner runner;
+ private RunParams runParams;
+ private Test test;
+
+ public TestRunner(Test test, String[] args) {
+ this.args = args;
+ this.test = test;
+ }
+
+ public synchronized Log getLog() {
+ if (log == null) {
+ log = new LogSupport(System.out);
+ }
+ return log;
+ }
+
+ private synchronized RunParams getRunParams() {
+ if (runParams == null) {
+ runParams = RunParams.getInstance();
+ runParams.parseCommandLine(args);
+ }
+ return runParams;
+ }
+
+ public void configure(Object o) {
+ if (o instanceof LogAware)
+ ((LogAware) o).setLog(getLog());
+ if (o instanceof MultiRunnerAware)
+ ((MultiRunnerAware) o).setRunner(getRunner());
+ if (o instanceof RunParamsAware)
+ ((RunParamsAware) o).setRunParams(getRunParams());
+ }
+
+ private synchronized MultiRunner getRunner() {
+ if (runner == null) {
+ runner = new ThreadsRunner();
+ configure(runner);
+ }
+ return runner;
+ }
+
+
+ public void execute(Object o) {
+ if (o instanceof Initializable)
+ ((Initializable) o).initialize();
+ int exitCode = 0;
+ try {
+ if (o instanceof Runnable)
+ ((Runnable) o).run();
+ if (o instanceof TestExitCode)
+ exitCode = ((TestExitCode) o).getExitCode();
+ } catch (RuntimeException t) {
+ getLog().error(t);
+ exitCode = 97;
+ }
+ if (exitCode != 95 && exitCode != 0)
+ throw new TestFailure("Test exit code: " + exitCode);
+ //System.exit(exitCode);
+ }
+
+ public void run() {
+ configure(test);
+ execute(test);
+ }
+ }
+
+
+ public static void runTest(Test test, String[] args) {
+ new TestRunner(test, args).run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test.timeoutwatchdog;
+
+/**
+ * TimeoutHandler - interface to define reaction on timeout.
+ * @see TimeoutWatchdoc
+ */
+public interface TimeoutHandler {
+
+ /**
+ * Invoked when watchdog detects timeout. Subclasses must implement this method to define how timeout should be handled.
+ */
+ void handleTimeout();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package nsk.share.test.timeoutwatchdog;
+
+import nsk.share.test.ExecutionController;
+
+/**
+ * This class watches for ExecutionControler and notifies TimeoutHander in case of timeout.
+ */
+public class TimeoutWatchdog implements Runnable {
+
+ private ExecutionController executionController;
+
+ private TimeoutHandler handler;
+
+ private static long CHECK_PERIOD = 1000; // In milliseconds
+
+ private TimeoutWatchdog(ExecutionController executionController, TimeoutHandler handler) {
+ this.executionController = executionController;
+ this.handler = handler;
+ }
+
+ /**
+ * Start watching for timeout.
+ * This method runs a new daemon thread that checks periodically if the observable test is still running.
+ * If timeout is detected <code>handler.handleTimeout()</code> will be called. If the test finishes normally the daemon
+ * thread will silently die.
+ * @param executionController - executionController used to monitor time left
+ * @param handler - handler on which handleTimeout() will be called
+ */
+ public static void watch(ExecutionController executionController, TimeoutHandler handler) {
+ Thread thread = new Thread(new TimeoutWatchdog(executionController, handler));
+ thread.setName("TimeoutWatchdog_thread");
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ Thread.sleep(CHECK_PERIOD);
+ if (!executionController.continueExecution()) {
+ System.out.println("Time expired. TimeoutWatchdog is calling TimeoutHandler.handleTimeout.");
+ handler.handleTimeout();
+ }
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Somebody dared to interrupt TimeoutWatchdog thread.");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/CommentedFileReader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.io.*;
+import java.util.LinkedList;
+
+/**
+ * Utility class intended to read file line by line and skip comments.
+ */
+public class CommentedFileReader {
+
+ /**
+ * Type of comments that should be removed from file.
+ */
+ public static enum CommentStyle {
+ /**
+ * Comments started with <i>#</i>.
+ */
+ BASH,
+ /**
+ * Comments started with <i>//</i>.
+ */
+ JAVA
+ }
+
+ /**
+ * Get lines from specified file and filter out comments.
+ * Only comments in BASH style will be filtered out.
+ *
+ * @param path to file that should be readed
+ * @return filtered lines from file
+ */
+ public static String[] readFile(String path) throws IOException {
+ return readFile(new File(path), CommentStyle.BASH);
+ }
+
+ /**
+ * Get lines from specified file and filter out comments.
+ * Only comments in BASH style will be filtered out.
+ *
+ * @param file that should be readed
+ * @return filtered lines from file
+ */
+ public static String[] readFile(File file) throws IOException {
+ return readFile(file, CommentStyle.BASH);
+ }
+
+ /**
+ * Get lines from specified file without comments.
+ *
+ * @param path to file that should be readed
+ * @param commentStyle describes what strings will be treated as comments
+ * @return filtered lines from file
+ */
+ public static String[] readFile(String path, CommentStyle commentStyle) throws IOException {
+ return readFile(new File(path), commentStyle);
+ }
+
+ /**
+ * Get lines from specified file without comments.
+ *
+ * @param file that should be readed
+ * @param commentStyle describes what strings will be treated as comments
+ * @return filtered lines from file
+ */
+ public static String[] readFile(File file, CommentStyle commentStyle) throws IOException {
+ LinkedList<String> entries = new LinkedList<String>();
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String commentBeginning;
+
+ switch (commentStyle) {
+ case BASH:
+ commentBeginning = "#";
+ break;
+ case JAVA:
+ commentBeginning = "//";
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown comment style");
+ }
+
+ while (true) {
+ String entry = reader.readLine();
+ if (entry == null) {
+ break;
+ }
+
+ entry = entry.replaceAll(commentBeginning + ".*", "").trim();
+
+ if (entry.length() > 0) {
+ entries.add(entry);
+ }
+ }
+
+ return entries.toArray(new String[entries.size()]);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/FileUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+
+public class FileUtils {
+
+ private static ClassLoader cl = ClassLoader.getSystemClassLoader();
+
+ public static byte[] readFile(File f) throws IOException {
+ FileInputStream is = new FileInputStream(f);
+ try {
+ return readStream(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public static byte[] readClass(String name) throws IOException {
+ return readResource(name.replace('.', '/') + ".class");
+ }
+
+ public static byte[] readResource(String name) throws IOException {
+ InputStream is = FileUtils.cl.getResourceAsStream(name);
+ if (is == null)
+ throw new IOException("Can't read resource " + name);
+
+ try {
+ return readStream(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public static byte[] readStream(InputStream is) throws IOException {
+ byte buf[] = new byte[0xFFFF];
+ int offset = 0;
+ int r;
+ while ((r = is.read(buf, offset, buf.length - offset)) > 0)
+ offset += r;
+ return Arrays.copyOf(buf, offset);
+ }
+
+ public static void writeBytesToFile(File file, byte[] buf)
+ throws IOException {
+ FileOutputStream fos = new FileOutputStream(file);
+ try {
+ fos.write(buf);
+ } finally {
+ fos.close();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/InMemoryJavaCompiler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+import java.io.ByteArrayOutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+public class InMemoryJavaCompiler {
+
+ public static Map<String, byte[]> compile(Map<String, ? extends CharSequence> inputMap) {
+ Collection<JavaFileObject> sourceFiles = new LinkedList<JavaFileObject>();
+ for (Entry<String, ? extends CharSequence> entry : inputMap.entrySet()) {
+ sourceFiles.add(new SourceFile(entry.getKey(), entry.getValue()));
+ }
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ FileManager fileManager = new FileManager(compiler.getStandardFileManager(null, null, null));
+
+ Writer writer = new StringWriter();
+ Boolean exitCode = compiler.getTask(writer, fileManager, null, null, null, sourceFiles).call();
+ if (!exitCode) {
+ System.out.println("*********** javac output begin ***********");
+ System.out.println(writer.toString());
+ System.out.println("*********** javac output end ***********");
+ if (writer.toString().contains("java.lang.OutOfMemoryError")) {
+ System.out.println("Got OOME while performing in memory compilation. It happens on weak hosts and there is nothing we can do. ");
+ throw new OutOfMemoryError("Got OOME while performing in memory compilation.");
+ }
+ throw new RuntimeException("Test bug: in memory compilation failed.");
+ }
+ return fileManager.getByteCode();
+ }
+
+ // Wraper for class file
+ static class ClassFile extends SimpleJavaFileObject {
+
+ private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ protected ClassFile(String name) {
+ super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
+ }
+
+ @Override
+ public ByteArrayOutputStream openOutputStream() { return this.baos; }
+
+ byte[] toByteArray() { return baos.toByteArray(); }
+ }
+
+ // File manager which spawns ClassFile instances by demand
+ static class FileManager extends ForwardingJavaFileManager<JavaFileManager> {
+
+ private Map<String, ClassFile> classesMap = new HashMap<String, ClassFile>();
+
+ protected FileManager(JavaFileManager fileManager) {
+ super(fileManager);
+ }
+
+ @Override
+ public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) {
+ ClassFile classFile = new ClassFile(name);
+ classesMap.put(name, classFile);
+ return classFile;
+ }
+
+ public Map<String, byte[]> getByteCode() {
+ Map<String, byte[]> result = new HashMap<String, byte[]>();
+ for (Entry<String, ClassFile> entry : classesMap.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().toByteArray());
+ }
+ return result;
+ }
+ }
+
+ // Wrapper for source file
+ static class SourceFile extends SimpleJavaFileObject {
+
+ private CharSequence sourceCode;
+
+ public SourceFile(String name, CharSequence sourceCode) {
+ super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
+ this.sourceCode = sourceCode;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignore) {
+ return this.sourceCode;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include "jni.h"
+#include "native_thread.h"
+#ifdef _WIN32
+#include <windows.h>
+#include <process.h>
+#include <vdmdbg.h>
+#include <dbghelp.h>
+#else /* _WIN32 */
+#include <unistd.h>
+#include <signal.h>
+#endif /* _WIN32 */
+#include "jni_tools.h"
+
+/*
+ * Class: vm_share_ProcessUtils
+ * Method: sendSignal
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendSignal
+(JNIEnv *env, jclass class, jint signalNum) {
+#ifdef _WIN32
+/* TODO TODO TODO
+ int dw;
+ LPVOID lpMsgBuf;
+ if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
+ dw = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ printf("%s\n", (LPTSTR)lpMsgBuf);
+ LocalFree(lpMsgBuf);
+ return JNI_FALSE;
+ }
+ */
+ return JNI_TRUE;
+#else /* _WIN32 */
+ if (kill(getpid(), signalNum) < 0)
+ return JNI_FALSE;
+ return JNI_TRUE;
+#endif /* _WIN32 */
+}
+
+/*
+ * Class: vm_share_ProcessUtils
+ * Method: sendCtrlBreak
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendCtrlBreak
+(JNIEnv *env, jclass class) {
+#ifdef _WIN32
+ int dw;
+ LPVOID lpMsgBuf;
+ if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
+ dw = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ printf("%s\n", (LPTSTR)lpMsgBuf);
+ LocalFree(lpMsgBuf);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+#else /* _WIN32 */
+ if (kill(getpid(), SIGQUIT) < 0)
+ return JNI_FALSE;
+ return JNI_TRUE;
+#endif /* _WIN32 */
+}
+
+#ifdef _WIN32
+static BOOL (WINAPI *_MiniDumpWriteDump) ( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
+ PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);
+void reportLastError(const char *msg) {
+ long errcode = GetLastError();
+ if (errcode != 0) {
+ DWORD len = 0;
+ char *buf;
+ size_t n = (size_t)FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ errcode,
+ 0,
+ (LPSTR) &buf,
+ (DWORD)len,
+ NULL);
+ if (n > 3) {
+ /* Drop final '.', CR, LF */
+ if (buf[n - 1] == '\n') n--;
+ if (buf[n - 1] == '\r') n--;
+ if (buf[n - 1] == '.') n--;
+ buf[n] = '\0';
+ }
+ printf("%s: %s\n", msg, buf);
+ LocalFree(buf);
+ }
+}
+
+#endif /* _WIN32 */
+
+jboolean doDumpCore() {
+#ifdef _WIN32
+ char path[MAX_PATH];
+ DWORD size;
+ DWORD pathLen = (DWORD) sizeof(path);
+ HINSTANCE dbghelp;
+ MINIDUMP_EXCEPTION_INFORMATION* pmei;
+
+ HANDLE hProcess = GetCurrentProcess();
+ DWORD processId = GetCurrentProcessId();
+ HANDLE dumpFile;
+ MINIDUMP_TYPE dumpType;
+ static const char* cwd;
+ static const char* name = "DBGHELP.DLL";
+
+ printf("# TEST: creating Windows minidump...\n");
+ if ((size = GetSystemDirectory(path, pathLen)) > 0) {
+ strcat(path, "\\");
+ strcat(path, name);
+ dbghelp = LoadLibrary(path);
+ if (dbghelp == NULL)
+ reportLastError("Load DBGHELP.DLL from system directory");
+ } else {
+ printf("GetSystemDirectory returned 0\n");
+ }
+
+ // try Windows directory
+ if (dbghelp == NULL && ((size = GetWindowsDirectory(path, pathLen)) > 6)) {
+ strcat(path, "\\");
+ strcat(path, name);
+ dbghelp = LoadLibrary(path);
+ if (dbghelp == NULL) {
+ reportLastError("Load DBGHELP.DLL from Windows directory");
+ }
+ }
+ if (dbghelp == NULL) {
+ printf("Failed to load DBGHELP.DLL\n");
+ return JNI_FALSE;
+ }
+
+ _MiniDumpWriteDump = (
+ BOOL(WINAPI *)( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
+ PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION)) GetProcAddress(dbghelp, "MiniDumpWriteDump");
+
+ if (_MiniDumpWriteDump == NULL) {
+ printf("Failed to find MiniDumpWriteDump() in module dbghelp.dll");
+ return JNI_FALSE;
+ }
+ dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData);
+
+ // Older versions of dbghelp.h doesn't contain all the dumptypes we want, dbghelp.h with
+ // API_VERSION_NUMBER 11 or higher contains the ones we want though
+#if API_VERSION_NUMBER >= 11
+ dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo |
+ MiniDumpWithUnloadedModules);
+#endif
+
+ dumpFile = CreateFile("core.mdmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (dumpFile == INVALID_HANDLE_VALUE) {
+ reportLastError("Failed to create file for dumping");
+ return JNI_FALSE;
+ }
+ pmei = NULL;
+
+
+ // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all
+ // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then.
+ if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == FALSE &&
+ _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == FALSE) {
+ reportLastError("Call to MiniDumpWriteDump() failed");
+ return JNI_FALSE;
+ }
+
+ CloseHandle(dumpFile);
+ printf("# TEST: minidump created\n");
+ // Emulate Unix behaviour - exit process.
+ ExitProcess(137);
+
+ return JNI_TRUE;
+#else /* _WIN32 */
+ if (kill(getpid(), SIGSEGV) < 0)
+ return JNI_FALSE;
+ return JNI_TRUE;
+#endif /* _WIN32 */
+
+}
+
+/*
+ * Class: vm_share_ProcessUtils
+ * Method: dumpCore
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_dumpCore
+ (JNIEnv *env, jclass class)
+{
+ return doDumpCore();
+}
+
+/*
+ * Class: vm_share_ProcessUtils
+ * Method: getPid
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getPid
+ (JNIEnv *env, jclass class) {
+#ifdef _WIN32
+ return _getpid();
+#else /* _WIN32 */
+ return getpid();
+#endif /* _WIN32 */
+}
+
+
+/*
+ * Class: vm_share_ProcessUtils
+ * Method: getPid
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getWindowsPid
+ (JNIEnv *env, jclass class, jlong handle) {
+#ifdef _WIN32
+ return GetProcessId((HANDLE) handle);
+#else /* _WIN32 */
+ return -1;
+#endif /* _WIN32 */
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/ProcessUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Field;
+
+import nsk.share.TestBug;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+
+public final class ProcessUtils {
+ static {
+ System.loadLibrary("ProcessUtils");
+ }
+
+ private ProcessUtils() {}
+
+ /**
+ * Send Ctrl-\ to java process and Ctrl-Break on Windows.
+ * This will usually trigger stack dump for all threads and
+ * may trigger heap dump.
+ *
+ * @return true if it was successful
+ */
+ public static native boolean sendCtrlBreak();
+
+ /**
+ * Send any signal to java process on Unix. It currently does nothing on Windows.
+ *
+ * @return true if it was successful
+ */
+ public static native boolean sendSignal(int signalNum);
+
+ /**
+ * Force java process to dump core.
+ *
+ * This is done by sending SIGSEGV on unix systems.
+ *
+ * @return true if it was successful, false if not (for example on Windows)
+ */
+ public static native boolean dumpCore();
+
+ /**
+ * Get PID of java process.
+ *
+ * @return PID
+ */
+ public static native int getPid();
+
+ public static int getPid(Process process) {
+ Throwable exception;
+ try {
+ Field pidField = process.getClass().getDeclaredField("pid");
+ pidField.setAccessible(true);
+ return ((Integer) pidField.get(process)).intValue();
+ } catch (NoSuchFieldException e) {
+ exception = e;
+ } catch (IllegalAccessException e) {
+ exception = e;
+ }
+ // Try to get Windows handle
+ try {
+ Field handleField = process.getClass().getDeclaredField("handle");
+ handleField.setAccessible(true);
+ long handle = ((Long) handleField.get(process)).longValue();
+ return getWindowsPid(handle);
+ } catch (NoSuchFieldException e) {
+ exception = e;
+ } catch (IllegalAccessException e) {
+ exception = e;
+ }
+ throw new TestBug("Unable to determine pid from process class " + process.getClass(), exception);
+ }
+
+ private static native int getWindowsPid(long handle);
+
+ @SuppressWarnings("restriction")
+ public static void dumpHeapWithHotspotDiagnosticMXBean(String fileName) throws IOException {
+ System.err.println("Dumping heap to " + fileName);
+
+ File f = new File(fileName);
+ if (f.exists())
+ f.delete();
+
+ HotSpotDiagnosticMXBean b = ManagementFactory.getPlatformMXBeans(
+ com.sun.management.HotSpotDiagnosticMXBean.class).get(0);
+ b.dumpHeap(fileName, false);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/RandomEx.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class RandomEx extends Random {
+ private final Map<Class<?>, Supplier<?>> map = new HashMap<>();
+
+ {
+ map.put(Boolean.class, this::nextBoolean);
+ map.put(boolean.class, this::nextBoolean);
+ map.put(Byte.class, this::nextByte);
+ map.put(byte.class, this::nextByte);
+ map.put(Short.class, this::nextShort);
+ map.put(short.class, this::nextShort);
+ map.put(Character.class, this::nextChar);
+ map.put(char.class, this::nextChar);
+ map.put(Integer.class, this::nextInt);
+ map.put(int.class, this::nextInt);
+ map.put(Long.class, this::nextLong);
+ map.put(long.class, this::nextLong);
+ map.put(Float.class, this::nextFloat);
+ map.put(float.class, this::nextFloat);
+ map.put(Double.class, this::nextDouble);
+ map.put(double.class, this::nextDouble);
+ }
+
+ public RandomEx() {
+ }
+
+ public RandomEx(long seed) {
+ super(seed);
+ }
+
+ public byte nextByte() {
+ return (byte) next(Byte.SIZE);
+ }
+
+ public short nextShort() {
+ return (short) next(Short.SIZE);
+ }
+
+ public char nextChar() {
+ return (char) next(Character.SIZE);
+ }
+
+ public <T> T next(Predicate<T> p, T dummy) {
+ T result;
+ do {
+ result = next(dummy);
+ } while (!p.test(result));
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T next(T dummy) {
+ Supplier<?> supplier = map.get(dummy.getClass());
+ if (supplier == null) {
+ throw new IllegalArgumentException("supplier for <" +
+ dummy.getClass() + ">is not found");
+ }
+ return (T) supplier.get();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/StringUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Random;
+import java.util.function.Predicate;
+
+public class StringUtils {
+
+ public static byte[] binaryReplace(final byte[] src, String search,
+ String replacement) {
+ if (search.length() == 0)
+ return src;
+
+ int nReplaced = 0;
+
+ try {
+ final byte[] bSrch = search.getBytes("ASCII");
+ final byte[] bRepl = replacement.getBytes("ASCII");
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ searching: for (int i = 0; i < src.length; i++) {
+ if (src[i] == bSrch[0]) {
+ replacing: do {
+ for (int ii = 1; ii < Math.min(bSrch.length,
+ src.length - i); ii++)
+ if (src[i + ii] != bSrch[ii])
+ break replacing;
+
+ out.write(bRepl);
+ i += bSrch.length - 1;
+ nReplaced++;
+ continue searching;
+ } while (false);
+ }
+
+ out.write(src[i]);
+ }
+
+ return out.toByteArray();
+
+ } finally {
+ out.close();
+ }
+ } catch (Exception e) {
+ RuntimeException t = new RuntimeException("Test internal error");
+ t.initCause(e);
+ throw t;
+ }
+ }
+
+ public static String generateString(Random rng, int length,
+ Predicate<Character> predicate) {
+ if (length <= 0) {
+ throw new IllegalArgumentException("length <= 0");
+ }
+ StringBuilder builder = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ char tmp;
+ do {
+ tmp = (char) rng.nextInt(Character.MAX_VALUE);
+ } while (!predicate.test(tmp));
+ builder.append(tmp);
+ }
+ return builder.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/UnsafeAccess.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import java.lang.reflect.Field;
+
+import jdk.internal.misc.Unsafe;
+
+@SuppressWarnings("restriction")
+public class UnsafeAccess {
+ public static Unsafe unsafe;
+
+ static {
+ try {
+ unsafe = Unsafe.getUnsafe();
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ }
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/VMRuntimeEnvUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+
+import java.lang.management.ManagementFactory;
+import java.util.Objects;
+
+public class VMRuntimeEnvUtils {
+ private static HotSpotDiagnosticMXBean DIAGNOSTIC_BEAN
+ = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+
+ private VMRuntimeEnvUtils() {
+ }
+
+ public static boolean isJITEnabled() {
+ boolean isJITEnabled = ManagementFactory.getCompilationMXBean() != null;
+
+ return isJITEnabled;
+ }
+
+ /**
+ * Returns value of VM option.
+ *
+ * @param name option's name
+ * @return value of option or {@code null}, if option doesn't exist
+ * @throws NullPointerException if name is null
+ * @see HotSpotDiagnosticMXBean#getVMOption(String)
+ */
+ public static String getVMOption(String name) {
+ Objects.requireNonNull(name);
+ VMOption tmp;
+ try {
+ tmp = DIAGNOSTIC_BEAN.getVMOption(name);
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ return (tmp == null ? null : tmp.getValue());
+ }
+
+ /**
+ * Returns value of VM option or default value.
+ *
+ * @param name option's name
+ * @param defaultValue default value
+ * @return value of option or {@code defaultValue}, if option doesn't exist
+ * @throws NullPointerException if name is null
+ * @see #getVMOption(String)
+ */
+ public static String getVMOption(String name, String defaultValue) {
+ String result = getVMOption(name);
+ return result == null ? defaultValue : result;
+ }
+
+ /**
+ * Returns if a boolean VM option is enabled or not.
+ *
+ * @param name option's name
+ * @return true iff enabled
+ * @throws IllegalArgumentException if naming non-boolean or non-existing option
+ */
+ public static boolean isVMOptionEnabled(String name) {
+ String isSet = getVMOption(name, "error");
+ if (isSet.equals("true")) {
+ return true;
+ } else if (isSet.equals("false")) {
+ return false;
+ }
+ throw new IllegalArgumentException(name + " is not a boolean option.");
+ }
+
+ /**
+ * Sets a specified value for VM option of given name.
+ *
+ * @param name option's name
+ * @param value new value
+ * @throws NullPointerException if name is null
+ * @throws IllegalArgumentException if new value is invalid or if vm option
+ * is not writable.
+ * @see HotSpotDiagnosticMXBean#setVMOption(String, String)
+ */
+ public static void setVMOption(String name, String value) {
+ Objects.requireNonNull(name);
+ DIAGNOSTIC_BEAN.setVMOption(name, value);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.gc;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import nsk.share.TestFailure;
+import nsk.share.test.ExecutionController;
+
+public class TriggerUnloadingByFillingHeap implements TriggerUnloadingHelper {
+
+ public void triggerUnloading(ExecutionController stresser) {
+ List<String> jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
+ if (jvmArgs.contains("-XX:+ExplicitGCInvokesConcurrent")) {
+ throw new TestFailure("Test bug! Found -XX:+ExplicitGCInvokesConcurrent in jvm args. TriggerUnloadingByFillingHeap.triggerUnloading will not work!.");
+ }
+
+ System.out.println("collections invoked: " + provokeGC(stresser));
+ System.out.println("collections invoked: " + provokeGC(stresser));
+ System.out.println("collections invoked: " + provokeGC(stresser));
+ }
+
+ private static long getGCCounter() {
+ return ManagementFactory.getGarbageCollectorMXBeans().get(1).getCollectionCount();
+ }
+
+ private static Random random = new Random();
+
+ public static byte[] garbage; //make it reference public to avoid compiler optimizations
+
+ private static long provokeGC(ExecutionController stresser) {
+ long initCounter = getGCCounter();
+ ArrayList<byte[]> list = new ArrayList<byte[]>();
+ while (getGCCounter() == initCounter && stresser.continueExecution()) {
+ list.add(new byte[1024]);
+
+ garbage = new byte[1024];
+ if (random.nextInt(10) % 10 < 3 && !list.isEmpty()) {
+ list.remove(0);
+ }
+ System.gc();
+ }
+ return getGCCounter() - initCounter;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.gc;
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import metaspace.stressHierarchy.common.exceptions.GotWrongOOMEException;
+import nsk.share.gc.gp.classload.GeneratedClassProducer;
+import nsk.share.test.ExecutionController;
+
+public class TriggerUnloadingByFillingMetaspace implements
+ TriggerUnloadingHelper {
+
+ private static final int NUMBER_OF_THREADS = 30;
+
+ private static class FillMetaspace {
+ private volatile boolean gotOOME = false;
+ private ExecutionController stresser;
+ private GeneratedClassProducer generatedClassProducer = new GeneratedClassProducer("metaspace.stressHierarchy.common.HumongousClass");
+
+ public FillMetaspace(ExecutionController stresser) { this.stresser = stresser; }
+
+ private class FillMetaspaceTask implements Callable<Object> {
+ @Override
+ public Object call() throws Exception {
+ while (stresser.continueExecution() && ! gotOOME) {
+ try {
+ generatedClassProducer.create(-100500); //argument is not used.
+ } catch (OutOfMemoryError oome) {
+ if (!isInMetaspace(oome)) {
+ throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid.");
+ }
+ gotOOME = true;
+ }
+ }
+ return null;
+ }
+ }
+ }
+
+ private static boolean isInMetaspace(OutOfMemoryError error) {
+ return error.getMessage().trim().toLowerCase().contains("metadata");
+ }
+
+ @Override
+ public void triggerUnloading(ExecutionController stresser) {
+ try {
+ FillMetaspace fillMetaspace = new FillMetaspace(stresser);
+ ArrayList<Callable<Object>> tasks = new ArrayList<Callable<Object>>(NUMBER_OF_THREADS);
+ for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+ tasks.add(fillMetaspace.new FillMetaspaceTask());
+ }
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ try {
+ executorService.invokeAll(tasks);
+ } catch (InterruptedException e) {
+ System.out.println("Process of gaining OOME in metaspace was interrupted.");
+ e.printStackTrace();
+ }
+ } catch (OutOfMemoryError e) {
+ if (!isInMetaspace(e)) {
+ throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid.");
+ }
+ return;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingHelper.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.gc;
+
+import nsk.share.test.ExecutionController;
+
+public interface TriggerUnloadingHelper {
+
+ public void triggerUnloading(ExecutionController stresser);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingWithWhiteBox.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.gc;
+
+
+import sun.hotspot.WhiteBox;
+import nsk.share.test.ExecutionController;
+
+public class TriggerUnloadingWithWhiteBox implements TriggerUnloadingHelper {
+
+ private final static WhiteBox wb = WhiteBox.getWhiteBox();
+
+ @Override
+ public void triggerUnloading(ExecutionController stresser) {
+ wb.fullGC();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/libProcessUtils.c Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ */
+
+#include "jni_tools.c"
+#include "nsk_tools.c"
+#include "ProcessUtils.c"
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/MemoryPoolFinder.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.monitoring;
+
+import java.lang.management.*;
+
+public enum MemoryPoolFinder {
+ CODE_CACHE,
+ EDEN_SPACE,
+ SURVIVOR_SPACE,
+ OLD_GEN,
+ PERM_GEN,
+ METASPACE,
+ CLASS_METASPACE;
+
+ public static MemoryPoolMXBean findPool(MemoryPoolFinder pool) {
+ for(MemoryPoolMXBean candidate : ManagementFactory.getMemoryPoolMXBeans()) {
+ boolean found = false;
+ switch(pool) {
+ case CODE_CACHE:
+ found = candidate.getName().contains("Code Cache");
+ break;
+ case EDEN_SPACE:
+ found = candidate.getName().contains("Eden");
+ break;
+ case SURVIVOR_SPACE:
+ found = candidate.getName().contains("Survivor");
+ break;
+ case OLD_GEN:
+ found = candidate.getName().contains("Old") || candidate.getName().contains("Tenured");
+ break;
+ case PERM_GEN:
+ found = candidate.getName().contains("Perm");
+ break;
+ case METASPACE:
+ found = candidate.getName().contains("Metaspace") && !candidate.getName().contains("Class Metaspace");
+ break;
+ case CLASS_METASPACE:
+ found = candidate.getName().contains("Class Metaspace");
+ break;
+ }
+ if (found) return candidate;
+ }
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryManagerData.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.monitoring.data;
+
+import java.lang.management.*;
+import javax.management.*;
+import java.io.Serializable;
+
+public class MemoryManagerData implements MemoryManagerMXBean, Serializable {
+ private String[] memoryPoolNames;
+ private String name;
+ private boolean valid;
+
+ public MemoryManagerData(String[] memoryPoolNames, String name, boolean valid) {
+ this.memoryPoolNames = memoryPoolNames;
+ this.name = name;
+ this.valid = valid;
+ }
+
+ public MemoryManagerData(MemoryManagerMXBean memoryManager) {
+ this.memoryPoolNames = memoryManager.getMemoryPoolNames();
+ this.name = memoryManager.getName();
+ this.valid = memoryManager.isValid();
+ }
+
+ public String[] getMemoryPoolNames() {
+ return memoryPoolNames;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public ObjectName getObjectName() {
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryPoolData.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.monitoring.data;
+
+import java.lang.management.MemoryPoolMXBean;
+import java.io.Serializable;
+
+public class MemoryPoolData implements Serializable {
+ private String name;
+ private boolean valid;
+ private MemoryUsageData usage;
+
+ public MemoryPoolData(String name, boolean valid, MemoryUsageData usage) {
+ this.name = name;
+ this.valid = valid;
+ }
+
+ public MemoryPoolData(MemoryPoolMXBean memoryManager) {
+ this.name = memoryManager.getName();
+ this.valid = memoryManager.isValid();
+ this.usage = new MemoryUsageData(memoryManager.getUsage());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean hasName(String name) {
+ return this.name.equals(name);
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public MemoryUsageData getUsage() {
+ return usage;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/monitoring/data/MemoryUsageData.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.monitoring.data;
+
+import java.io.Serializable;
+import java.lang.management.MemoryUsage;
+import nsk.share.log.Log;
+
+public class MemoryUsageData implements Serializable {
+ private long init;
+ private long used;
+ private long committed;
+ private long max;
+
+ public MemoryUsageData(long init, long used, long committed, long max) {
+ this.init = init;
+ this.used = used;
+ this.committed = committed;
+ this.max = max;
+ }
+
+ public MemoryUsageData(MemoryUsage usage) {
+ this.init = usage.getInit();
+ this.used = usage.getUsed();
+ this.committed = usage.getCommitted();
+ this.max = usage.getMax();
+ }
+
+ public MemoryUsageData(MemoryUsageData usage, MemoryUsageData usage1) {
+ this.init = usage.getInit() + usage1.getInit();
+ this.used = usage.getUsed() + usage1.getUsed();
+ this.committed = usage.getCommitted() + usage1.getCommitted();
+ this.max = usage.getMax() + usage1.getMax();
+ }
+
+ public long getInit() {
+ return init;
+ }
+
+ public long getUsed() {
+ return used;
+ }
+
+ public long getMax() {
+ return max;
+ }
+
+ public long getFree() {
+ return committed - used;
+ }
+
+ public long getCommitted() {
+ return committed;
+ }
+
+ public void log(Log log) {
+ log.info(" Init: " + init);
+ log.info(" Used: " + used);
+ log.info(" Committed: " + committed);
+ log.info(" Max: " + max);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicObjectFactory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options;
+
+import java.util.HashMap;
+import java.util.Map;
+import nsk.share.TestBug;
+
+/**
+ * This class allows user to create an {@link ObjectFactory} implementation
+ * via @{@link vm.share.options.Factory} annotation. See the source code of
+ * {@link vm.share.options.test.BasicObjectFactoryUsageExample} and
+ * {@link vm.share.options.test.ExampleWithNonprimitiveOptions}.
+ * @see Factory
+ * @see FClass
+ * @see ObjectFactory
+ */
+public class BasicObjectFactory<T> implements ObjectFactory<T>
+{
+ public String getPlaceholder()
+ {
+ return getAnnotaion().placeholder_text();
+ }
+
+ public String[] getPossibleValues()
+ {
+ return getTypesMap().keySet().toArray(new String[0]);
+ }
+
+ public String getDescription()
+ {
+ return getAnnotaion().description().equals(Factory.defDescription)? null : getAnnotaion().description();
+ }
+
+ public String getDefaultValue()
+ {
+ return getAnnotaion().default_value().equals(Factory.defDefaultValue)? null :
+ getAnnotaion().default_value();
+ }
+
+ public String getParameterDescription(String key)
+ {
+ return getTypesMap().get(key).description();
+ }
+
+
+ // shouldn't value be named key?
+
+ public T getObject(String value)
+ {
+ try
+ {
+ @SuppressWarnings(value="unchecked")
+ T result = (T) getTypesMap().get(value).type().newInstance();
+ return result;
+ } catch (InstantiationException ex)
+ {
+ throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex);
+ } catch (IllegalAccessException ex)
+ {
+ throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex);
+ }
+ }
+
+ protected Factory getAnnotaion()
+ {
+ if(!this.getClass().isAnnotationPresent(Factory.class))
+ throw new TestBug(" Found an unnotated BasicObjectFactory subclass.");
+ Factory factoryAnn = this.getClass().getAnnotation(Factory.class);
+ return factoryAnn;
+ }
+
+ protected Map<String, FClass> getTypesMap()
+ { // probably there could be some lazy initialization, but I decided not to deal with that.
+ FClass[] types = getAnnotaion().classlist();
+ Map<String, FClass> typesMap = new HashMap<String, FClass>(types.length);
+ for (FClass type : types)
+ {
+ typesMap.put(type.key(), type);
+ }
+ return typesMap;
+
+ }
+
+ // see ExampleWithNonprimitiveOptions instead.
+// public void test()
+// {
+// if(!this.getClass().isAnnotationPresent(Factory.class))
+// throw new RuntimeException(" Found an unnotated BasicObjectFactory subclass.");
+// Factory factoryAnn = this.getClass().getAnnotation(Factory.class);
+// System.out.println(" placeholder_text " + factoryAnn.placeholder_text());
+// System.out.println(" default_value " +
+// (factoryAnn.default_value().equals(Factory.defDefault_value) ? null : factoryAnn.default_value()) );
+//
+// }
+//
+// @Factory(placeholder_text="number", default_value="test",
+// classlist = {
+// @FClass( key="int", description="integer", type=int.class),
+// @FClass( key="boolean", description="boolean", type=boolean.class)
+// } )
+// public static class testOF extends BasicObjectFactory<BasicObjectFactory> {}
+//
+//// @Factory(placeholder_text="placehldr1")
+//// public static class testOF1 extends BasicObjectFactory<BasicObjectFactory> {}
+//
+//
+// public static void main(String[] args)
+// {
+// BasicObjectFactory bof = new testOF();
+// bof.test();
+//// new testOF1().test();
+//
+// }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/BasicOptionObjectFactory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options;
+
+import java.util.HashMap;
+import java.util.Map;
+import nsk.share.TestBug;
+
+/**
+ * This class allows user to create an {@link ObjectFactory} implementation
+ * via @{@link vm.share.options.Factory} annotation. See the source code of
+ * {@link vm.share.options.test.BasicObjectFactoryUsageExample} and
+ * {@link vm.share.options.test.ExampleWithNonprimitiveOptions}.
+ * @see Factory
+ * @see FClass
+ * @see ObjectFactory
+ */
+public class BasicOptionObjectFactory<T> implements OptionObjectFactory<T>
+{
+ public String getPlaceholder()
+ {
+ return getAnnotaion().placeholder_text();
+ }
+
+ public String[] getPossibleValues()
+ {
+ return getTypesMap().keySet().toArray(new String[0]);
+ }
+
+ public String getDescription()
+ {
+ return getAnnotaion().description().equals(Factory.defDescription)? null : getAnnotaion().description();
+ }
+
+ public String getDefaultValue()
+ {
+ return getAnnotaion().default_value().equals(Factory.defDefaultValue)? null :
+ getAnnotaion().default_value();
+ }
+
+ public String getParameterDescription(String key)
+ {
+ return getTypesMap().get(key).description();
+ }
+
+
+ // shouldn't value be named key?
+
+ public T getObject(String value)
+ {
+ try
+ {
+ @SuppressWarnings(value="unchecked")
+ T result = (T) getTypesMap().get(value).type().newInstance();
+ return result;
+ } catch (InstantiationException ex)
+ {
+ throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex);
+ } catch (IllegalAccessException ex)
+ {
+ throw new TestBug("Error while trying to instantiate via " + this.getClass() + " for key " + value, ex);
+ }
+ }
+
+ protected Factory getAnnotaion()
+ {
+ if(!this.getClass().isAnnotationPresent(Factory.class))
+ throw new TestBug(" Found an unnotated BasicObjectFactory subclass.");
+ Factory factoryAnn = this.getClass().getAnnotation(Factory.class);
+ return factoryAnn;
+ }
+
+ protected Map<String, FClass> getTypesMap()
+ { // probably there could be some lazy initialization, but I decided not to deal with that.
+ FClass[] types = getAnnotaion().classlist();
+ Map<String, FClass> typesMap = new HashMap<String, FClass>(types.length);
+ for (FClass type : types)
+ {
+ typesMap.put(type.key(), type);
+ }
+ return typesMap;
+
+ }
+
+ // see ExampleWithNonprimitiveOptions instead.
+// public void test()
+// {
+// if(!this.getClass().isAnnotationPresent(Factory.class))
+// throw new RuntimeException(" Found an unnotated BasicObjectFactory subclass.");
+// Factory factoryAnn = this.getClass().getAnnotation(Factory.class);
+// System.out.println(" placeholder_text " + factoryAnn.placeholder_text());
+// System.out.println(" default_value " +
+// (factoryAnn.default_value().equals(Factory.def_default_value) ? null : factoryAnn.default_value()) );
+//
+// }
+//
+// @Factory(placeholder_text="number", default_value="test",
+// classlist = {
+// @FClass( key="int", description="integer", type=int.class),
+// @FClass( key="boolean", description="boolean", type=boolean.class)
+// } )
+// public static class testOF extends BasicObjectFactory<BasicObjectFactory> {}
+//
+//// @Factory(placeholder_text="placehldr1")
+//// public static class testOF1 extends BasicObjectFactory<BasicObjectFactory> {}
+//
+//
+// public static void main(String[] args)
+// {
+// BasicObjectFactory bof = new testOF();
+// bof.test();
+//// new testOF1().test();
+//
+// }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/FClass.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+import java.lang.annotation.*;
+/**
+ * This is an auxilary declaration for use with @Factory annotation,
+ * allows to add a particular class to the factory.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface FClass
+{
+// final public static String def_default_value = "[no default]";
+ /**
+ * A key which tells the BasicObjectFactory to instaniate given class,
+ * is mandatory.
+ */
+ String key(); // mandatory ;
+ /**
+ * Description of this kind of instances, is mandatory.
+ */
+ String description();
+
+ /**
+ * The class to instantiate, should have a default public constructor,
+ * so that type().newInstance() will work, is mandatory.
+ */
+ Class<?> type();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Factory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+import java.lang.annotation.*;
+/**
+ * This annotation is coupled with {@link BasicObjectFactory} class,
+ * and allows one to create implementations of ObjectFactory via annotations.
+ * <pre> a simple example:
+@Factory(description="dummy factory", default_value="array_list", placeholder_text="a type",
+classlist={
+@FClass(description="a linked list", key="linked_list", type=LinkedList.class),
+@FClass(description="an array list", key="array_list", type=ArrayList.class)
+})
+public class BasicObjectFactoryUsageExample extends BasicObjectFactory<Collection>
+{
+}
+ * </pre>
+ * @see BasicObjectFactory
+ * @see FClass
+ * @see vm.share.options.test.BasicObjectFactoryUsageExample
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Factory
+{
+ final public static String defDefaultValue = "[no factory default]";
+ final public static String defDescription = "[no factory description]";
+ /**
+ * Used for generating placeholder text in <..> part of help message,
+ * is mandatory.
+ */
+ String placeholder_text(); // mandatory ;
+ /**
+ * Default value, used if the option is not specified AND if no default
+ * value has been specified in the corresponding @Option annotation.
+ */
+ String default_value() default defDefaultValue;
+
+ /**
+ * A help message string for the factory.
+ */
+ String description() default defDescription;
+
+ /**
+ * The list of classes and keys to instantiate.
+ * @see FClass
+ */
+ FClass[] classlist(); // mandatory
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/IgnoreUnknownArgumentsHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+public class IgnoreUnknownArgumentsHandler implements OptionHandler {
+
+ @Override public void option(String name, String value) {}
+ @Override public void argument(String value) {}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/ObjectFactory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options;
+
+/**
+ * This is a factory interface used to setup non-simple type options,
+ * implemented by the user, there is a shortcut, see {@link BasicObjectFactory}.
+ */
+public interface ObjectFactory<T>
+{
+ /**
+ * Returns a string that can be used in <..> section of help message.
+ * @return placeholder text
+ */
+ public String getPlaceholder();
+ /**
+ * Enumerates all possible key values for this factory.
+ * @return an array of keys
+ */
+ public String[] getPossibleValues();
+
+ /**
+ * Returns default description for options which use this factory
+ * @return the description string.
+ */
+ public String getDescription();
+
+
+ /**
+ * For a given parameter value gives its description.
+ * @param key to instantiate parameter
+ * @return description string for the parameter given.
+ */
+ public String getParameterDescription(String key);
+
+ /**
+ * Returns default value for the parameter, which is used if
+ * no default value attribute is defined at the @Option annotation level.
+ * @return default value for the parameter, null if mandatory
+ */
+ public String getDefaultValue();
+
+ /**
+ * Constructs an object given a object type key.
+ * @param key name indicating the type of the object to create.
+ * @return the instance of the requested type
+ */
+ public T getObject(String key);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Option.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+import java.lang.annotation.*;
+/**
+ * This annotation is the most useful one of the whole API.
+ * It is used to mark non-static fields of the object and to declare the
+ * corresponding options. The name of the option defaults to the name of the field.
+ * The help message for the option should also be also declared
+ * here (or it could be declared at the {@link ObjectFactory} level at any case it is mandatory).
+ * For non-simple option types a factory attribute should be provided which
+ * points to a class which implements {@link ObjectFactory} interface. That factory is
+ * then used to instantiate an object given the option value and to populate the
+ * annotated field.
+ *
+ * If a default value is provided it is used if the corresponding option is not declared
+ * at the command line. If it is not provided and there is no option then an error is thrown.
+ * For non-simple field types default values can be provided at ObjectFactory level.
+ * See also the documentation at the package level.).
+ */
+// kept at runtime, applied to fields only.
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Option
+{
+ // these strings help to find out if the corresponding attribute was not defined.
+ final public static String defName = "[no name]";
+ final public static String defDefaultValue = "[no default]";
+ final public static String defDescription = "[no description]";
+
+ /**
+ * The name of the option, defaults to the name of the annotated field.
+ */
+ String name() default defName;
+ /**
+ * The default value for the option, option is mandatory if it is not specified here
+ * and at the ObjectFactory level.
+ */
+ String default_value() default defDefaultValue;
+ /**
+ * A short description of the option used to generate a help message.
+ */
+ String description() default defDescription;
+
+ /**
+ * The factory class to use for instantiating the corresponding option.
+ */
+ Class<? extends OptionObjectFactory> factory() default OptionObjectFactory.class;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionDefinition.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.reflect.Field;
+import nsk.share.TestBug;
+
+/**
+ * This is a "value" class for holding information about the defined options.
+ */
+public final class OptionDefinition {
+ private static final Map<String, OptionObjectFactory> factories = new HashMap<String, OptionObjectFactory>();
+ private String prefix;
+ private String name;
+ private String description;
+ private String defaultValue;
+ private Class<? extends OptionObjectFactory> factory;
+ private Field field;
+ private Object owner;
+
+ public OptionDefinition(String prefix, String name, String description, String defaultValue, Class<? extends OptionObjectFactory> factory, Field field, Object owner) {
+ this.prefix = prefix;
+ this.name = name;
+ this.description = description;
+ this.defaultValue = defaultValue;
+ this.factory = factory;
+ this.field = field;
+ this.owner = owner;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getFullName() {
+ if (prefix != null)
+ return prefix + "." + name;
+ else
+ return name;
+ }
+
+ public Field getField() {
+ return field;
+ }
+
+ public Object getOwner() {
+ return owner;
+ }
+
+ public String getDescription() {
+ if (hasFactory())
+ if (description == null)
+ return getFactory().getDescription();
+ return description;
+ }
+
+ public String getDefaultValue() {
+ if (hasFactory())
+ if (defaultValue == null)
+ return getFactory().getDefaultValue();
+ return defaultValue;
+ }
+
+ public boolean hasFactory() {
+ return factory != null;
+ }
+
+ public String getPlaceHolder() {
+ if (hasFactory())
+ return getFactory().getPlaceholder();
+ else
+ return getField().getType().toString();
+ }
+
+ public synchronized OptionObjectFactory getFactory() {
+ if (factory == null)
+ throw new TestBug("Called getFactory() on OptionDefinition with unset factory");
+ OptionObjectFactory factory = factories.get(this.factory);
+ if (factory == null) {
+ try {
+ factory = this.factory.newInstance();
+ } catch (InstantiationException ex) {
+ throw new TestBug("Failed to instantiate factory " + this.factory, ex);
+ } catch (IllegalAccessException ex) {
+ throw new TestBug("Failed to instantiate factory " + this.factory, ex);
+ }
+ }
+ return factory;
+ }
+
+ public String toString() {
+ return "Option " + name + " field " + field + " object " + owner;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionError.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import nsk.share.TestBug;
+
+public class OptionError extends TestBug {
+ public OptionError(String msg, OptionDefinition optDef) {
+ super(msg + " (option definition: " + optDef + ")");
+ }
+
+ public OptionError(String msg, Throwable e, OptionDefinition optDef) {
+ super(msg + " (option definition: " + optDef + ")", e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options;
+
+/**
+ * Handles options not specified via @Options annotations,
+ * implemented and provided by the user.
+ */
+public interface OptionHandler
+{
+ /**
+ * This method is called for every unknown option
+ * @param name option name (not including '-' or '=', trimmed)
+ * @param value may be null in the case of the last option with no value
+ * specified.
+ */
+ public void option(String name, String value);
+
+ /**
+ * This method is called for every command line argument which
+ * is not recognized as a part of -option_name=value pair.
+ * @param value the value of an unrecognized argument
+ */
+ public void argument(String value);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionObjectFactory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options;
+
+/**
+ * This is a factory interface used to setup non-simple type options,
+ * implemented by the user, there is a shortcut, see {@link BasicObjectFactory}.
+ */
+public interface OptionObjectFactory<T>
+{
+ /**
+ * Returns a string that can be used in <..> section of help message.
+ * @return placeholder text
+ */
+ public String getPlaceholder();
+
+ /**
+ * Enumerates all possible key values for this factory.
+ * @return an array of keys
+ */
+ public String[] getPossibleValues();
+
+ /**
+ * Returns default description for options which use this factory
+ * @return the description string.
+ */
+ public String getDescription();
+
+ /**
+ * For a given parameter value gives its description.
+ * @param key to instantiate parameter
+ * @return description string for the parameter given.
+ */
+ public String getParameterDescription(String key);
+
+ /**
+ * Returns default value for the parameter, which is used if
+ * no default value attribute is defined at the @Option annotation level.
+ * @return default value for the parameter, null if mandatory
+ */
+ public String getDefaultValue();
+
+ /**
+ * Constructs an object given a object type key.
+ * @param key name indicating the type of the object to create.
+ * @return the instance of the requested type
+ */
+ public T getObject(String key);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionSupport.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+/**
+ * This class actually provides the OptionFramework API
+ * via two static {@link OptionSupport#setup} methods.
+ * See also "General description" section of the package level documentation.
+ */
+public class OptionSupport
+{
+ /**
+ * This method parses the commandline arguments, setups the instance fields (annotated by @Option) accordingly
+ * and calls method run().
+ * @param test the instance to setup fields for
+ * @param args command line arguments array
+ */
+ public static void setupAndRun(Runnable test, String[] args) {
+ setupAndRun(test, args, null);
+ }
+
+ /**
+ * This method parses the commandline arguments and setups the instance fields (annotated by @Option) accordingly
+ * @param test the instance to setup fields for
+ * @param args command line arguments array
+ */
+ public static void setup(Object test, String[] args)
+ {
+ setup(test, args, null);
+ }
+
+ /**
+ * This method parses the commandline arguments, setups the instance fields (annotated by @Option) accordingly
+ * and calls method run().
+ * @param test the instance to setup fields for
+ * @param args command line arguments array
+ * @param unknownOptionHandler an option handler for unknown options
+ */
+ public static void setupAndRun(Runnable test, String[] args, OptionHandler unknownOptionHandler) {
+ setup(test, args, unknownOptionHandler);
+ test.run();
+ }
+
+
+ /**
+ * This is an extension API which allows Test author to create and
+ * process some specific options.
+ * @param test the instance to setup fields for
+ * @param args command line arguments array
+ * @param unknownOptionHandler an option handler for unknown options
+ *
+ */
+ public static void setup(Object test, String[] args, OptionHandler unknownOptionHandler) {
+ new OptionsSetup(test, args, unknownOptionHandler).run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/Options.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * This annotation marks fields which should be scanned for @Option annotation,
+ * see the souurce code of {@link vm.share.options.test.SimpleExampleWithOptionsAnnotation}
+ * for detailed example.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Options {
+ // default value for undefined attribute
+ final public static String defPrefix = "[no prefix]";
+ /**
+ * The name of this group of option, added as prefix
+ */
+ String prefix() default defPrefix;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsMap.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * This annotation marks fields of type Map<String, String>,
+ * where the name=>value map of given options is placed by the framework
+ *
+ * should be stored
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface OptionsMap { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.io.PrintStream;
+import nsk.share.TestBug;
+import nsk.share.log.LogSupport;
+
+class OptionsSetup {
+ private LogSupport log = new LogSupport();
+ private boolean verbose = true;
+ private Object test;
+ private String[] args;
+ private OptionHandler unknownOptionHandler;
+
+ private int argIndex = 0;
+ private Map<String, OptionDefinition> optionDefs = new LinkedHashMap<String, OptionDefinition>(); // Use LinkedHashMap to ensure order of options
+ private List<OptionDefinition> unconfiguredOptionsList = new ArrayList<OptionDefinition>();
+ private List<OptionDefinition> unconfiguredOptionList = new ArrayList<OptionDefinition>();
+ private Map<String, Object> optionValues = new LinkedHashMap<String, Object>();
+
+ public OptionsSetup(Object test, String[] args, OptionHandler unknownOptionHandler) {
+ this.test = test;
+ this.args = args;
+ this.unknownOptionHandler = unknownOptionHandler;
+ log.setDebugEnabled(verbose);
+ }
+
+ public void run() {
+ searchAnnotations(test, null);
+ while (argIndex < args.length) {
+ process1Arg();
+ }
+ setDefaultValues();
+ checkMandatoryOptions();
+ if (unconfiguredOptionsList.size() > 0) {
+ for (OptionDefinition optDef : unconfiguredOptionsList)
+ log.info("Unconfigured option: " + optDef);
+ throw new TestBug("Some options are unconfigured");
+ }
+ }
+
+ private void checkMandatoryOptions() {
+ for (Map.Entry<String, OptionDefinition> e : optionDefs.entrySet()) {
+ String name = e.getKey();
+ OptionDefinition optDef = e.getValue();
+ if (optDef.getDefaultValue() == null && !optionValues.containsKey(name))
+ throw new TestBug("Mandatory option is not specified: -" + name);
+ }
+ }
+
+ private void setDefaultValues() {
+ for (Iterator<OptionDefinition> it = unconfiguredOptionList.iterator(); it.hasNext(); ) {
+ OptionDefinition optDef = it.next();
+ String value = optDef.getDefaultValue();
+ if (value == null)
+ continue;
+ setOptionValue(optDef, value);
+ it.remove();
+ if (unconfiguredOptionsList.contains(optDef))
+ unconfiguredOptionsList.remove(optDef);
+ }
+
+ for (Iterator<OptionDefinition> it = unconfiguredOptionsList.iterator(); it.hasNext(); ) {
+ OptionDefinition optDef = it.next();
+ if (optionsAnnotation(optDef.getOwner(), optDef.getField(), null, optDef, true))
+ it.remove();
+ }
+ }
+
+ private void process1Arg() {
+ String arg = args[argIndex++];
+ //log.debug("Processing argument: " + arg);
+ if (!arg.startsWith("-")) {
+ processUnknownArg(arg);
+ return;
+ }
+ String opt = arg.substring(1);
+ String value = null;
+ int i = opt.indexOf('=');
+ if (i != -1) {
+ value = opt.substring(i + 1);
+ opt = opt.substring(0, i);
+ }
+ if (opt.equals("help")) {
+ printHelp();
+ throw new TestBug("-help was specified");
+ }
+ if (!optionDefs.containsKey(opt)) {
+ if (value == null && argIndex < args.length)
+ value = args[argIndex++];
+ // We need to try to resolve default values of all unconfigured fields because one of them may potentially have this option
+ setDefaultValues();
+ if (!optionDefs.containsKey(opt)) {
+ processUnknownOpt(opt, value);
+ return;
+ }
+ }
+ OptionDefinition optDef = optionDefs.get(opt);
+ Field f = optDef.getField();
+ // Handle boolean omitted value
+ if (value == null && (argIndex >= args.length || args[argIndex].startsWith("-"))) {
+ if (f.getType() == boolean.class || f.getType() == Boolean.class) {
+ value = "true";
+ }
+ }
+ if (value == null) {
+ if (argIndex >= args.length)
+ throw new TestBug("Missing value for option -" + opt);
+ value = args[argIndex++];
+ }
+ setOptionValue(optDef, value);
+ if (unconfiguredOptionList.contains(optDef)){
+ unconfiguredOptionList.remove(optDef);
+ }
+ }
+
+ private void setOptionValue(OptionDefinition optDef, String value) {
+ Object ovalue = null;
+ if (optDef.hasFactory()) {
+ ovalue = optDef.getFactory().getObject(value);
+ } else {
+ ovalue = PrimitiveParser.parse(value, optDef.getField().getType());
+ }
+ optionValues.put(optDef.getName(), ovalue);
+ try {
+ Field f = optDef.getField();
+ Object o = optDef.getOwner();
+ f.set(o, ovalue);
+ if (f.isAnnotationPresent(Options.class)) {
+ if (!optionsAnnotation(o, f, optDef.getPrefix(), optDef, false))
+ throw new TestBug("Unexpected (bug in framework?): optionsAnnotation returned null: " + optDef);
+ if (unconfiguredOptionsList.contains(optDef))
+ unconfiguredOptionsList.remove(optDef);
+ }
+ } catch (IllegalArgumentException e) {
+ throw new TestBug("Exception setting field value for option " + optDef.getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new TestBug("Exception setting field value for option " + optDef.getName(), e);
+ }
+ }
+
+ private void processUnknownArg(String arg) {
+ if (unknownOptionHandler != null)
+ unknownOptionHandler.argument(arg);
+ else
+ throw new TestBug("Invalid argument: " + arg);
+ }
+
+ private void processUnknownOpt(String opt, String value) {
+ if (unknownOptionHandler != null)
+ unknownOptionHandler.option(opt, value);
+ else
+ throw new TestBug("Invalid option: '" + opt + "', value: '" + value + "'");
+ }
+
+ private void searchAnnotations(Object o, String prefix) {
+ Class<?> cl0 = o.getClass();
+ //log.debug("Looking for annotations for object " + o + ", class " + cl0);
+ List<Class> classes = new LinkedList<Class>();
+ while (cl0.getSuperclass() != null) {
+ classes.add(0, cl0); // Add to the beginning to ensure the option order is from superclass to subclass
+ cl0 = cl0.getSuperclass();
+ }
+ for (Class<?> cl : classes) {
+ for (Field f : cl.getDeclaredFields()) {
+ OptionDefinition optDef = null;
+ if (f.isAnnotationPresent(Option.class)) {
+ optDef = optionAnnotation(o, f, prefix);
+ if (optDef != null) {
+ unconfiguredOptionList.add(optDef);
+ }
+ }
+ if (f.isAnnotationPresent(Options.class)) {
+ if (!optionsAnnotation(o, f, prefix, optDef, false)) {
+ if (!unconfiguredOptionsList.contains(optDef))
+ unconfiguredOptionsList.add(optDef);
+ }
+ }
+ }
+ }
+ }
+
+ private boolean optionsAnnotation(Object o, Field f, String prefix, OptionDefinition optDef, boolean useDefault) {
+ if (Modifier.isStatic(f.getModifiers()))
+ throw new OptionError("@Options annotation is not allowed at static field", optDef);
+ if (!Object.class.isAssignableFrom(f.getDeclaringClass()))
+ throw new OptionError("@Options annotation is only allowed on object types", optDef);
+ //log.debug("Processing @Options annotation: object " + o + ", field " + f + ", prefix " + prefix);
+ Object v = null;
+ try {
+ f.setAccessible(true);
+ v = f.get(o);
+ } catch (IllegalAccessException e) {
+ throw new OptionError("Exception getting value of field ", e, optDef);
+ }
+ if (v == null) {
+ if (optDef == null)
+ throw new OptionError("Value of field is null and no @Option annotation is present", optDef);
+ if (!optDef.hasFactory())
+ throw new OptionError("Value of field is null and no @Option annotation does not have factory", optDef);
+ if (useDefault) {
+ setOptionValue(optDef, optDef.getDefaultValue());
+ try {
+ v = f.get(o);
+ } catch (IllegalAccessException e) {
+ throw new OptionError("Exception getting value of field ", e, optDef);
+ }
+ }
+ if (v == null) {
+ // We cannot setup it right away, so it is stored until value is set
+ return false;
+ } else
+ return true; // setOption Value already searched annotations
+ }
+ Options opts = f.getAnnotation(Options.class);
+ String vprefix = opts.prefix();
+ if (vprefix.equals(Options.defPrefix))
+ vprefix = null;
+ if (vprefix != null) {
+ if (prefix != null)
+ prefix = prefix + "." + vprefix;
+ else
+ prefix = vprefix;
+ }
+ searchAnnotations(v, prefix);
+ return true;
+ }
+
+ private OptionDefinition optionAnnotation(Object o, Field f, String prefix) {
+ //log.debug("Processing @Option annotation: object " + o + ", field " + f + ", prefix " + prefix);
+ f.setAccessible(true);
+ Option opt = f.getAnnotation(Option.class);
+ String name = opt.name();
+ if (name.equals(Option.defName))
+ name = f.getName(); // option name defaults to field name
+ if (prefix != null)
+ name = prefix + "." + name;
+ if (optionDefs.containsKey(name))
+ throw new TestBug("Option is already defined: " + name);
+ String defaultValue = opt.default_value();
+ if (defaultValue.equals(Option.defDefaultValue))
+ defaultValue = null; // default value defaults to null
+ String description = opt.description();
+ if (description.equals(Option.defDescription))
+ description = null;
+ if (description == null) {
+ if (name.equals("log") || name.endsWith(".log")) {
+ try {
+ f.set(o, log);
+ } catch (IllegalAccessException e) {
+ throw new TestBug("Exception setting log field of " + o, e);
+ }
+ return null;
+ } else
+ throw new TestBug("@Option annotation should always have description set: " + name + ", field: " + f);
+ }
+ Class<? extends OptionObjectFactory> factory = opt.factory();
+ //log.debug("Factory: " + factory);
+ if (factory.equals(OptionObjectFactory.class))
+ factory = null;
+ OptionDefinition optDef = new OptionDefinition(
+ prefix,
+ name,
+ description,
+ defaultValue,
+ factory,
+ f,
+ o
+ );
+ optionDefs.put(name, optDef);
+ //log.debug("Added option definition: " + optDef);
+ return optDef;
+ }
+
+ private void printHelp() {
+ PrintStream out = System.out;
+ out.println(" Supported options:");
+ out.println(" -help");
+ out.println(" Show this help screen");
+ for (Map.Entry<String, OptionDefinition> entry : optionDefs.entrySet()) {
+ String opt = entry.getKey();
+ OptionDefinition optDef = entry.getValue();
+ out.println(" -" + opt + " <" + optDef.getPlaceHolder() + ">");
+ out.print(" " + optDef.getDescription() + " ");
+ if (optDef.getDefaultValue() != null) {
+ out.println("(default: " + optDef.getDefaultValue() + ")");
+ } else {
+ out.println("(mandatory)");
+ }
+ if (optDef.hasFactory()) {
+ OptionObjectFactory factory = optDef.getFactory();
+ for (String key : factory.getPossibleValues()) {
+ out.println(" " + key + ": " + factory.getParameterDescription(key));
+ }
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/ParserException.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.options;
+
+import nsk.share.TestBug;
+
+/**
+ * This class represents a simple Parser exception.
+ */
+public class ParserException extends TestBug {
+ public ParserException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ParserException(String message) {
+ super(message);
+ }
+
+ public ParserException(Throwable cause) {
+ super(cause);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/PrimitiveParser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package vm.share.options;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.Map;
+import nsk.share.TestBug;
+
+/**
+ * A utility class used to parse arguments of various primitive types.
+ */
+public class PrimitiveParser
+{
+ /**
+ * Checks if the parser can handle passed type ("primitive/wrapper" or one-dim array of those).
+ * Note that one-dim arrays of primitives/strings/wrappers are also supported.
+ * @param type the type to parse against
+ * @return true, if can parse.
+ */
+ public static boolean canHandle(Class<?> type)
+ {
+
+ if(type.isArray())
+ {
+ Class<?> compType = type.getComponentType();
+ if(compType.isArray()) return false; // Cannot handle multidimensional arrays
+ return canHandle(compType);
+ }
+ type = convertPrimitiveTypeToWrapper(type);
+ return parsers.containsKey(type);
+ }
+
+ /**
+ * A simple helper method.
+ * @param type the type to check for
+ * @return the parser to use, null if there is none.
+ */
+ private static PParser getParser(Class<?> type)
+ {
+ return parsers.get(convertPrimitiveTypeToWrapper(type));
+ }
+
+ /**
+ * The main API method of this class.
+ * @param param the parameter to parse
+ * @param type parameter type to parse against
+ * @return returns the object of a given type.
+ * @throws vm.share.options.PrimitiveParser.ParserException
+ */
+ public static Object parse(String param, Class<?> type) throws ParserException
+ {
+ if(type.isArray())
+ {
+ Class<?> compType = type.getComponentType();
+ if(compType.isArray())
+ throw new ParserException("Cannot handle multidimensional arrays");
+
+ if(!canHandle(compType))
+ throw new ParserException("Unable to parse unknown array component type " + compType);
+
+ String[] params = param.split(",");
+ Object arr = Array.newInstance(compType, params.length);
+ for (int i = 0; i < params.length; i++)
+ {
+ String par = params[i].trim();
+ Array.set(arr, i, parse(par, compType));
+ }
+ return arr;
+ }
+ else
+ {
+ if(!canHandle(type))
+ throw new ParserException("Unable to parse unknown type " + type);
+ return getParser(type).parse(param);
+ }
+ }
+
+ // I'm not sure, if generics are of any use here...
+ static private abstract class PParser<T>
+ {
+ abstract T parse(String param) throws ParserException;
+
+// Class<T> getClassKey()
+// {
+// return PrimitiveParser.(Class<T>) T.getClass();
+// }
+ }
+
+ /**
+ * Converts primitive types to corresponding wrapper classes.
+ * We could register int.class, boolean.class etc in the hashtable instead.
+ * (Or Integer.TYPE, etc.)
+ * @param type to convert to wrapper
+ * @return wrapper class or type if it is not primitive
+ */
+ public static Class<?> convertPrimitiveTypeToWrapper(Class<?> type)
+ {
+ if(!type.isPrimitive()) return type;
+ Object arr = Array.newInstance(type, 1);
+ Object v = Array.get(arr, 0);
+ return v.getClass();
+ }
+
+
+ //"kind of state" machine stuff
+
+ private static Map<Class<?>, PParser<?>> parsers;
+
+ static
+ {
+ parsers = new HashMap<Class<?>, PrimitiveParser.PParser<?>>(16);
+ parsers.put(Integer.class, new PParser<Integer>()
+ {
+ @Override Integer parse(String param) throws ParserException
+ {
+ if ( param.startsWith("0x") )
+ return Integer.parseInt(param.substring(2));
+ else
+ return Integer.valueOf(param);
+ }
+ });
+ parsers.put(Boolean.class, new PParser<Boolean>()
+ {
+ @Override Boolean parse(String param) throws ParserException
+ {
+ //special behavior for options
+ if(param == null) return true;
+ if(param.trim().length()==0) return true;
+ return Boolean.valueOf(param);
+ }
+ });
+
+ parsers.put(String.class, new PParser<String>()
+ {
+ @Override String parse(String param) throws ParserException
+ {
+ if(param == null) throw new ParserException(" Got null value string.");
+ return param;
+ }
+ });
+
+
+ parsers.put(Character.class, new PParser<Character>()
+ {
+ @Override Character parse(String param) throws ParserException
+ {
+ if(param.length()!=1)
+ throw new TestBug("Found Character type option of length != 1");
+ return Character.valueOf(param.charAt(0));
+ }
+ });
+
+ parsers.put(Byte.class, new PParser<Byte>()
+ {
+ @Override Byte parse(String param) throws ParserException
+ {
+ if ( param.startsWith("0x") )
+ return Byte.parseByte(param.substring(2));
+ else
+ return Byte.valueOf(param);
+ }
+ });
+
+ parsers.put(Short.class, new PParser<Short>()
+ {
+ @Override Short parse(String param) throws ParserException
+ {
+ if ( param.startsWith("0x") )
+ return Short.parseShort(param.substring(2));
+ else
+ return Short.valueOf(param);
+ }
+ });
+
+ parsers.put(Long.class, new PParser<Long>()
+ {
+ @Override Long parse(String param) throws ParserException
+ {
+ if ( param.startsWith("0x") )
+ return Long.parseLong(param.substring(2));
+ else
+ return Long.valueOf(param);
+ }
+ });
+
+ parsers.put(Float.class, new PParser<Float>()
+ {
+ @Override Float parse(String param) throws ParserException
+ {
+ return Float.valueOf(param);
+ }
+ });
+
+ parsers.put(Double.class, new PParser<Double>()
+ {
+ @Override Double parse(String param) throws ParserException
+ {
+ return Double.valueOf(param);
+ }
+ });
+ }
+
+
+/* Discussion
+ * 1. It was proposed to use instead of the convertPrimitive the following
+ *
+ * private static Map<Class<?>, Class<?>> wrapperClasses = new HashMap<Class<?>, Class<?>>();
+ *
+ * so we could do if(type.isPrimitive())
+ type = wrapperClasses.get(type);
+ static {
+ wrapperClasses.put(boolean.class, Boolean.class);
+ wrapperClasses.put(short.class, Short.class);
+ wrapperClasses.put(int.class, Integer.class);
+ wrapperClasses.put(Long.Type, Long.class); // we can do it this way!
+ wrapperClasses.put(float.class, Float.class);
+ wrapperClasses.put(double.class, Double.class);
+ }
+ * The alternative is to register PParsers with corresponding Primitive type too.
+ *
+ * Also canHandle() could use
+ return wrapperClasses.keySet().contains(type) || wrapperClasses.entrySet().contains(type);
+
+ * 2. Parsing can be implemented via reflection
+ return type.getMethod("valueOf", new Class[]{String.class}).invoke(null, string);
+
+ * I don't like using reflection as it prevents optimisation,
+ * also now Strings and Characters are handled in a nice fashion.
+ *
+ * As for convertToPrimitive trick both ways are good,
+ * but current looks more generic though tricky
+ */
+
+//// some test, should it be commented out?
+// public static void main(String[] args)
+// {
+// try
+// {
+// String str = "0";
+// Object o = null;
+// str = "0";
+// o = parse(str, String.class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+//
+// str = "0";
+// o = parse(str, int.class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+// str = "0";
+// o = parse(str, Integer.class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+//
+// str = "0,1,2";
+// o = parse(str, int[].class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + (int[]) o + "#");
+// System.out.println("DATA:" + java.util.Arrays.toString((int[])o));
+// // System.out.println("DATA:" + java.util.Arrays.deepToString( (int[]) o));
+//
+// str = "0";
+// o = parse(str, byte.class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+//
+// str = "0";
+// o = parse(str, HashMap.class);
+// System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+// } catch (ParserException ex)
+// {
+// System.out.println("" +ex);
+// }
+//// String str = "0"; Object o = parsePrimitiveString(help_option, type); System.out.println("value:" + str + " type: " + o.getClass() + " value:#" + o + "#");
+//
+// }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/package-info.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+
+
+/**
+ * This framework allows one to automate parsing of the test command line
+ * arguments (it automatically sets the corresponding fields of the
+ * test class).
+ <p>
+<h3>A simplified example</h3>
+Suppose we want to to define a test Test with an option "iterations",
+which can be run via
+</p>
+<pre> > java Test -iterations 10 </pre>
+or via
+<pre> java Test </pre>
+in the last case iterations defaults to 100.
+<p>
+We want to achieve this by annotating fields of the Test class by
+a special @Option annotation.
+<p>
+For simplicity suppose @Option is defined as follows:
+<pre>
+ @interface Option
+ { //here all the annotation fields are mandatory
+ String name();
+ String default();
+ String description();
+ }
+ </pre>
+ The test class uses an API like:
+ <pre>
+ public class OptionSupport {
+ public static void setup(Object test, String[] args);
+ }
+</pre>
+Now a simple example:
+<pre>
+public class Test {
+
+ @Option( name="iterations",
+ default="100",
+ description="Number of iterations")
+ int iterations;
+ public void run() {
+ // ..do actual testing here..
+ }
+
+ public static void main(String args) {
+ Test test = new Test();
+ OptionsSupport.setup(test, args); // instead of manually
+ // parsing arguments
+ // now test.iterations is set to 10 or 100.
+ test.run();
+ }
+}
+</pre>
+This test can be also run via
+<pre>
+- java Test -help
+</pre>
+Then OptionSupport.setup() shows
+help and exits (by throwing exception?):
+<pre>
+ Supported options:
+ -iterations <number>
+ Number of iterations (mandatory)
+</pre>
+We also want to be able to apply this to fields of non-simple types (via
+factories) and to other classes recursively (see @Options annotation
+below).
+<p>
+Please, see {@link vm.share.options.test.SimpleExample}
+for a working version of this.
+ * <h3> General description </h3>
+ Options are defined using annotations like this:
+<pre>
+public class StressOptions {
+ // [2]
+ @Option(name="stressTime",
+ default_value="60",
+ description="Stress time")
+ private long stressTime;
+
+ ...
+}
+</pre>
+<p> we want to use command line like
+<pre> java Test -stressTime 50 </pre>
+here 50 is passed to the StressOptions.stressTime field.
+see {@link vm.share.options.Options} below. </p>
+<pre>
+public class Test {
+ // [1]
+ @Options
+ StressOptions stressOptions = new StressOptions();
+
+ // [2]
+ @Option(name="iterations",
+ default_value="100",
+ description="Number of iterations")
+ int iterations;
+
+ // [3]
+ @Option(
+ name="garbageProducer",
+ default="byteArr",
+ description="Garbage producer",
+ factory="nsk.share.gc.gp.GarbageProducerFactory")
+ GarbageProducer garbageProducer;
+...
+
+ // [4]
+ @Option(name="logger",
+ description="Logger",
+ factory="nsk.share.log.LogFactory")
+ Log log;
+
+ public void run() {
+ log.info("Start test");
+ log.info("Finish test");
+ }
+
+ public static void main(String[] args) {
+ Test test = new Test();
+ OptionsSupport.setup(test, args);
+ test.run();
+ }
+}
+</pre>
+<p> The API is invoked via a call to {@link vm.share.options.OptionSupport#setup(Object, String[])}).
+ Also there is {@link vm.share.options.OptionSupport#setup(Object, String[], OptionHandler)}) method.
+ It allows the caller to pass a handler which takes
+ care of the options not defined via @Option annotation.
+</p>
+
+<h3>Requirements</h3>
+<p>
+ - The following field types are supported out-of-box: [2]
+ <ul>
+ <li/>All basic (primitive) types (int, long, ...) and corresponding wrapper types.
+ <li/> In the case of a boolean type option user is allowed to skip second argument,
+ i.e. write '-option_name'
+ instead of '-option_name true'.
+ <li/> Strings.
+ <li/> One dimentional arrays of the above (comma-separated).
+ <li/> Classes if a factory is specified, see below.
+ <emph>NOTE: currently there is no way to pass some options to the instantiated objects.</emph>
+ </ul>
+</p>
+<p> All non-static fields (including private and protected) of class and
+ it's superclasses are scanned for annotations.
+</p>
+<p>
+ (Possibly) Same annotations for setter methods ? (NOT IMPLEMENTED)
+</p>
+<p>
+ It is possible to inherit options of the field type
+ through @Options annotations, see {@link vm.share.options.Options}, and [1] above.
+</p>
+<p>
+ Option.name defaults to the name of the field.
+</p>
+<p> Object options are supported using {@link vm.share.options.OptionObjectFactory}, see [3] above.
+Please see {@link vm.share.options.OptionObjectFactory} interface, it should be
+implemented by the user and specified in the Option.factory attribute.
+</p>
+<p>
+As a shortcut we provide BasicOptionObjectFactory class, which allows user to
+create a factory via @{@link vm.share.options.Factory} annotation:
+<pre>
+@Factory (
+ placeholder_text="garbage producer", //used for generating <..> in the help message
+ default_value="byteArr",
+ classlist={
+ @FClass(key="byteArr",
+ type="nsk.share.gc.gp.array.ByteArrayProducer",
+ description="byte array producer")
+ @FClass(key="charArr",
+ type="nsk.share.gc.gp.array.CharArrayProducer",
+ description="char array producer")
+ ...
+ }
+)
+public class GarbageProducerFactory extends BasicOptionObjectFactory {
+}
+</pre>
+<p> <emph> note: for subclasses of BasicOptionObjectFactory
+factories can extend each other!!
+so the check for @OptionObjectFactory is done recursively.
+NOT SURE IF THIS IS IMPLEMENTED.
+</emph></p>
+<p> If there is no unknownOptionHandler then in case of unsupported
+option, a Runtime exception is thrown.
+</p>
+<p>
+ If there is no 'default' annotation attribute and there is no default
+for OptionObjectFactory, then option is mandatory and a Runtime exception is thrown if
+it's missing.
+</p>
+ <p> Both '-option value' and '-option=value' formats are supported.
+ </p>
+<p> If main class is given '-help', OptionSupport.setup() shows
+help and exits (by throwing a Runtime exception):
+<pre>
+Supported options:
+ -iterations <number>
+ Number of iterations (mandatory)
+ -stressTime <number>
+ Stress time (default 60)
+ -garbageProducer <garbage producer>
+ Garbage producer (default byteArr). Supported keys:
+ byteArr byte array producer
+ charArr char array producer
+ ...
+ ...
+</pre>
+
+<p> <emph> NOT IMPLEMENTED: </emph>
+Integer type boundaries are validated with RuntimeException with detailed
+meaningful error message. Other validations that are possible are also done.
+</p>
+ <p> <emph> NOT IMPLEMENTED: </emph>
+ Empty default ("") value for Object annotations [3] means null value.
+</p>
+<p> The object created via factory is also scanned for @Option annotations
+(like in the @Options case), i.e. it inherits options from the Test class.
+<emph> This is not implemented as it causes several problems, in particular, the
+object must be instanciated in order to be scanned for options, hence no meaningful
+help message could be generated for corresponding options.
+One of the possible solutions
+is to allow -object_opt_name.suboption syntax (or even with a colon), and to pass the
+corresponding suboptions Map to the OptionObjectFactory, it could use OptionFramework
+to take care of it. It is unclear, what other problems can arise.</emph>
+</p>
+ *
+ */
+package vm.share.options;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/BasicObjectFactoryUsageExample.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package vm.share.options.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import vm.share.options.BasicOptionObjectFactory;
+import vm.share.options.FClass;
+import vm.share.options.Factory;
+
+/**
+ * This is a simple example of BasicObjectFactory utility class,
+ * which allows us to produce {@link vm.share.options.ObjectFactory}
+ * implementations via annotations.
+ * @see vm.share.options.ObjectFactory
+ * @see vm.share.options.BasicObjectFactory
+ * @see vm.share.options.Factory
+ * @see vm.share.options.FClass
+ */
+@Factory(description="dummy factory", default_value="array_list", placeholder_text="a type",
+classlist={
+@FClass(description="a linked list", key="linked_list", type=LinkedList.class),
+@FClass(description="an array list", key="array_list", type=ArrayList.class)
+})
+ // MUST BE PUBLIC or it could not be istantiated!!
+public class BasicObjectFactoryUsageExample extends BasicOptionObjectFactory<Collection>
+{
+
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/ExampleWithNonprimitiveOptions.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package vm.share.options.test;
+
+import java.util.Collection;
+import vm.share.options.Option;
+import vm.share.options.OptionSupport;
+
+/**
+ * This example uses @Option annotation with an a factory attribute,
+ * to populate a field of a non-simple type.
+ */
+public class ExampleWithNonprimitiveOptions
+{
+
+ @Option(name = "iterations", default_value = "100", description = "Number of iterations")
+ int iterations;
+
+
+ @Option(description = "quiet or verbose")
+ private String running_mode;
+
+ @Option(description = "type of the list",
+ factory=vm.share.options.test.BasicObjectFactoryUsageExample.class)
+ private Collection list;
+
+ public void run()
+ {
+ // ..do actual testing here..
+ System.out.println("iterations = " + iterations);
+ System.out.println("RM : " + running_mode);
+ System.out.println("list is " + list.getClass());
+ }
+
+
+ public static void main(String[] args)
+ {
+ ExampleWithNonprimitiveOptions test = new ExampleWithNonprimitiveOptions();
+ OptionSupport.setup(test, args); // instead of manually // parsing arguments
+ // now test.iterations is set to 10 or 100.
+ test.run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExample.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * This is a very simple test for our framework.
+ */
+package vm.share.options.test;
+
+import vm.share.options.Option;
+import vm.share.options.OptionSupport;
+
+/**
+ * This is a very simple usage example of the framework
+ * @see vm.share.options.Option
+ * @see vm.share.options.OptionSupport
+ */
+public class SimpleExample
+{
+
+ @Option(name = "iterations", default_value = "100", description = "Number of iterations")
+ int iterations;
+
+
+ @Option(description = "quiet or verbose")
+ private String running_mode;
+
+ public void run()
+ {
+ // ..do actual testing here..
+ System.out.println("iterations = " + iterations);
+ System.out.println("RM : " + running_mode);
+ }
+
+
+ public static void main(String[] args)
+ {
+ SimpleExample test = new SimpleExample();
+ OptionSupport.setup(test, args); // instead of manually
+ // parsing arguments
+ // now test.iterations is set to 10 or 100 (default value).
+ test.run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SimpleExampleWithOptionsAnnotation.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package vm.share.options.test;
+
+import vm.share.options.Option;
+import vm.share.options.OptionSupport;
+import vm.share.options.Options;
+
+
+/**
+ * This is again a simple example which shows the power of @Options annotation.
+ * @see vm.share.options.Options
+ * @see vm.share.options.Option
+ * @see vm.share.options.OptionSupport
+ */
+
+public class SimpleExampleWithOptionsAnnotation
+{
+ @Options
+ StressOptions stressOptions = new StressOptions();
+ @Option(name = "iterations", default_value = "100", description = "Number of iterations")
+ int iterations;
+
+ @Option(description = "quiet or verbose")
+ String running_mode;
+
+ public void run()
+ {
+ // ..do actual testing here..
+ System.out.println("iterations = " + iterations);
+ System.out.println("RM: " + running_mode);
+ System.out.println("StressOptions " + stressOptions.getStressTime());
+ }
+
+
+ public static void main(String[] args)
+ {
+ SimpleExampleWithOptionsAnnotation test = new SimpleExampleWithOptionsAnnotation();
+ OptionSupport.setup(test, args); // instead of manually // parsing arguments
+ // now test.iterations is set to 10 or 100.
+ test.run();
+ }
+}
+
+class StressOptions
+{
+ @Option(default_value="60", description="Stress time")
+ private long stressTime;
+
+ public long getStressTime()
+ {
+ return stressTime;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/SubClassExample.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+ * This is a very simple test for our framework.
+ */
+package vm.share.options.test;
+
+import vm.share.options.Option;
+import vm.share.options.OptionSupport;
+
+/**
+ * This is an example with annotated superclasses
+ * @see vm.share.options.Option
+ * @see vm.share.options.OptionSupport
+ */
+public class SubClassExample extends SimpleExampleWithOptionsAnnotation
+{
+
+ @Option(name = "timeout", default_value = "100", description = "timeout")
+ int timeout;
+
+
+ @Option(name = "logging_mode", description = "quiet or verbose")
+ private String logging_mode;
+
+ @Override
+ public void run()
+ {
+ // ..do actual testing here..
+ System.out.println("iterations = " + iterations);
+ System.out.println("RM : " + running_mode);
+ System.out.println("logging_mode" + logging_mode);
+ System.out.println("timeout " + timeout);
+ System.out.println("stresstime " + stressOptions.getStressTime());
+ }
+
+
+ public static void main(String[] args)
+ {
+ SubClassExample test = new SubClassExample();
+ OptionSupport.setup(test, args); // instead of manually
+ // parsing arguments
+ // now test.iterations is set to 10 or 100 (default value).
+ test.run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/options/test/package-info.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008, 2018, 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.
+ */
+/*
+
+ */
+/**
+ * This package contains a number of short examples which demonstrate
+ * the most typical usage use this API, please, take a look at the source code.
+ */
+package vm.share.options.test;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/CmdExecutor.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.io.IOException;
+import java.util.Collection;
+
+public class CmdExecutor extends ProcessExecutor {
+ private final StringBuilder cmd = new StringBuilder();
+ @Override
+ public void clearArgs() {
+ cmd.setLength(0);
+ }
+
+ @Override
+ public void addArg(String arg) {
+ cmd.append(" " + arg);
+ }
+
+ @Override
+ public void addArgs(String[] args) {
+ for (String arg : args) {
+ addArg(arg);
+ }
+ }
+
+ @Override
+ public void addArgs(Collection<String> args) {
+ for (String arg : args) {
+ addArg(arg);
+ }
+ }
+
+ @Override
+ protected Process createProcess() throws IOException {
+ return Runtime.getRuntime().exec(cmd.toString());
+ }
+
+ @Override
+ public String toString() {
+ return cmd.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageInput.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.util.List;
+
+public interface MessageInput {
+ public boolean waitForStart(long timeout) throws InterruptedException;
+ public boolean waitForMessage(long timeout) throws InterruptedException;
+ public boolean waitForMessage(String msg, long timeout) throws InterruptedException;
+ public String getMessage();
+ public List<String> getMessages();
+ public List<String> getMessages(int to);
+ public List<String> getMessages(int from, int to);
+ public boolean waitForFinish(long timeout) throws InterruptedException;
+ public void reset();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/MessageOutput.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+public interface MessageOutput {
+ public void start();
+ public void send(String msg);
+ public void finish();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessExecutor.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import nsk.share.TestBug;
+import nsk.share.TestFailure;
+import nsk.share.log.Log;
+import vm.share.ProcessUtils;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.lang.reflect.Field;
+
+public class ProcessExecutor {
+ private static long CLEANUP_TIMEOUT = 60000;
+ private Process process;
+ private StreamReader stdoutReader = new StreamReader("stdout");
+ private StreamReader stderrReader = new StreamReader("stderr");
+ private Waiter waiter = new Waiter();
+ private OutputStream stdin;
+ private volatile boolean running;
+ private volatile int result = -1;
+ private List<String> args = new ArrayList<String>();
+
+ public int getResult() {
+ return result;
+ }
+
+ public void clearArgs() {
+ this.args.clear();
+ }
+
+ public void addArg(String arg) {
+ this.args.add(arg);
+ }
+
+ public void addArgs(String[] args) {
+ for (String arg : args) {
+ this.args.add(arg);
+ }
+ }
+
+ public void addArgs(Collection<String> args) {
+ this.args.addAll(args);
+ }
+
+ private void printCommandLine() {
+ for (String arg : args) {
+ System.out.println(arg);
+ }
+ }
+
+ /*
+ * Start process.
+ */
+ public void start() {
+ if (process != null) {
+ throw new TestBug("Process is already started");
+ }
+ printCommandLine();
+ try {
+ process = createProcess();
+ stdoutReader.setDescription("stdout: " + toString());
+ stdoutReader.setStream(process.getInputStream());
+ stderrReader.setDescription("stderr: " + toString());
+ stderrReader.setStream(process.getErrorStream());
+ stdin = process.getOutputStream();
+ stdoutReader.start();
+ stderrReader.start();
+ waiter.start();
+ } catch (IOException e) {
+ throw new TestFailure("Error running process: " + toString(), e);
+ }
+ }
+
+ protected Process createProcess() throws IOException {
+ String[] commandLine = args.toArray(new String[args.size()]);
+ return Runtime.getRuntime().exec(commandLine);
+ }
+
+ /**
+ * Run and wait for completion.
+ */
+ public int execute(long timeout) {
+ if (timeout <= 0) {
+ throw new TestBug("Positive timeout is required");
+ }
+ start();
+ return waitFor(timeout);
+ }
+
+ public int waitFor(long timeout) {
+ if (process == null) {
+ throw new TestBug("Process is not yet started");
+ }
+ if (timeout <= 0) {
+ throw new TestBug("Positive timeout is required");
+ }
+ long timeleft = timeout;
+ long startTime = 0;
+ while (timeleft > 0) {
+ try {
+ startTime = System.currentTimeMillis();
+ waiter.join(timeout);
+ return result;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ timeleft -= (System.currentTimeMillis() - startTime);
+ }
+ return -1;
+ }
+
+ public int getPid() {
+ return ProcessUtils.getPid(process);
+ }
+
+ public OutputStream getStdIn() {
+ if (process == null) {
+ throw new TestBug(
+ "Process is not running; prepare writers after it is started");
+ }
+ return stdin;
+ }
+
+ public PrintStream getStdInPrint() {
+ return new PrintStream(getStdIn(),
+ true); // Autoflush is important here.
+ }
+
+/*
+ public InputStream getStdOut() {
+ if (process != null)
+ throw new TestBug("Process is already running; prepare readers before it is started or some output may be missed");
+ return stdoutReader.getInputStream();
+ }
+
+ public BufferedReader getStdOutReader() {
+ return new BufferedReader(new InputStreamReader(getStdOut()));
+ }
+
+ public InputStream getStdErr() {
+ if (process != null)
+ throw new TestBug("Process is already running; prepare readers before it is started or some output may be missed");
+ return stderrReader.getInputStream();
+ }
+
+ public BufferedReader getStdErrReader() {
+ return new BufferedReader(new InputStreamReader(getStdOut()));
+ }
+
+ public String getStdoutOutput() {
+ if (stdoutReader == null)
+ throw new TestBug("Process is not running");
+ return stdoutReader.getOutput();
+ }
+
+ public String getStderrOutput() {
+ if (stderrReader == null)
+ throw new TestBug("Process is not running");
+ return stderrReader.getOutput();
+ }
+ */
+
+ public void addStdOutListener(StreamListener l) {
+ stdoutReader.addListener(l);
+ }
+
+ public void addStdErrListener(StreamListener l) {
+ stderrReader.addListener(l);
+ }
+
+ public void logStdOut(String prefix, Log log) {
+ stdoutReader.addListener(new StreamLogger(prefix, log));
+ }
+
+ public void logStdErr(String prefix, Log log) {
+ stderrReader.addListener(new StreamLogger(prefix, log));
+ }
+
+ public void logStdOutErr(String prefix, Log log) {
+ logStdOut(prefix, log);
+ logStdErr("(stderr)" + prefix, log);
+ }
+
+ public boolean isStarted() {
+ return (process != null);
+ }
+
+ public void kill() {
+ if (process == null) {
+ throw new TestBug("Process is not running");
+ }
+ process.destroy();
+ if (stdoutReader != null) {
+ stdoutReader.kill();
+ }
+ if (stderrReader != null) {
+ stderrReader.kill();
+ }
+ if (waiter != null && waiter.isAlive()) {
+ waiter.kill();
+ }
+ process = null;
+ }
+
+ public void finish() {
+ if (stdoutReader != null) {
+ try {
+ stdoutReader.join(CLEANUP_TIMEOUT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ stdoutReader = null;
+ }
+ if (stderrReader != null) {
+ try {
+ stderrReader.join(CLEANUP_TIMEOUT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ stderrReader = null;
+ }
+ process = null;
+ }
+
+ public String toString() {
+ String ts = "";
+ if (args != null) {
+ for (String s : args) {
+ ts += s;
+ ts += " ";
+ }
+ }
+ return ts;
+ }
+
+ private class Waiter extends Thread {
+ public Waiter() {
+ super("Process Waiter: (not setup)");
+ setDaemon(true);
+ }
+
+ public void run() {
+ setName("Process Waiter: " + ProcessExecutor.this);
+ try {
+ result = process.waitFor();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+
+ public void kill() {
+ this.interrupt();
+ long timeleft = CLEANUP_TIMEOUT;
+ long startTime = 0;
+ while (timeleft > 0) {
+ try {
+ startTime = System.currentTimeMillis();
+ this.join(timeleft);
+ return;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ timeleft -= (System.currentTimeMillis() - startTime);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/ProcessHandler.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.util.List;
+
+public class ProcessHandler implements MessageInput, MessageOutput {
+ private StreamMessageInput stdout = new StreamMessageInput();
+ private StreamMessageInput stderr = new StreamMessageInput();
+ private StreamMessageOutput stdin = new StreamMessageOutput();
+
+ public ProcessHandler() {
+ }
+
+ public ProcessHandler(ProcessExecutor exec) {
+ bind(exec);
+ }
+
+ public void bind(ProcessExecutor exec) {
+ exec.addStdOutListener(stdout.createListener());
+ exec.addStdErrListener(stderr.createListener());
+ exec.start();
+ stdin.bind(exec.getStdIn());
+ }
+
+ public boolean waitForStart(long timeout) throws InterruptedException {
+ return stdout.waitForStart(timeout) && stderr.waitForStart(timeout);
+ }
+
+ public boolean waitForMessage(long timeout) throws InterruptedException {
+ return stdout.waitForMessage(timeout);
+ }
+
+ public boolean waitForMessage(String msg, long timeout) throws InterruptedException {
+ return stdout.waitForMessage(msg, timeout);
+ }
+
+ public String getMessage() {
+ return stdout.getMessage();
+ }
+
+ public List<String> getMessages() {
+ return stdout.getMessages();
+ }
+
+ public List<String> getMessages(int to) {
+ return stdout.getMessages(to);
+ }
+
+ public List<String> getMessages(int from, int to) {
+ return stdout.getMessages(from, to);
+ }
+
+ public boolean waitForStdErrMessage(String msg, long timeout) throws InterruptedException {
+ return stderr.waitForMessage(msg, timeout);
+ }
+
+ public String getStdErrMessage() {
+ return stderr.getMessage();
+ }
+
+ public boolean waitForFinish(long timeout) throws InterruptedException {
+ return stdout.waitForFinish(timeout) && stderr.waitForFinish(timeout);
+ }
+
+ public void start() {
+ stdin.start();
+ }
+
+ public void send(String msg) {
+ stdin.send(msg);
+ }
+
+ public void finish() {
+ stdin.finish();
+ }
+
+ public void reset() {
+ stdout.reset();
+ stderr.reset();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamListener.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+/*
+ * StreamListener listens on events from BufferedInputStream.
+ *
+ * Note: StreamListener should not never block as it potentially
+ * runs in thread that reads the input.
+ */
+public interface StreamListener {
+ public void onStart();
+ public void onRead(String line);
+ public void onFinish();
+ public void onException(Throwable e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamLogger.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import nsk.share.log.Log;
+
+/*
+ * StreamListener that logs everything to Log at debug priority.
+ */
+public class StreamLogger implements StreamListener {
+ private String prefix;
+ private Log log;
+
+ public StreamLogger(String prefix, Log log) {
+ this.prefix = prefix;
+ this.log = log;
+ }
+
+ public void onStart() {
+ // do nothing
+ }
+
+ public void onFinish() {
+ // do nothing
+ }
+
+ public void onRead(String s) {
+ log.debug(prefix + s);
+ }
+
+ public void onException(Throwable e) {
+ log.debug(prefix + "Exception");
+ log.debug(e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageInput.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.util.List;
+import java.util.ArrayList;
+import nsk.share.TestBug;
+
+public class StreamMessageInput implements MessageInput {
+ private Object sync = new Object();
+ private List<String> lines = new ArrayList<String>();
+ private int position = 0;
+ private volatile boolean active = false;
+ private volatile Throwable exception;
+
+ public StreamMessageInput() {
+ }
+
+ public StreamMessageInput(StreamReader sd) {
+ bind(sd);
+ }
+
+ public StreamListener createListener() {
+ return new Listener();
+ }
+
+ public void bind(StreamReader sd) {
+ sd.addListener(createListener());
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public boolean isException() {
+ return exception != null;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public boolean waitForStart(long timeout) throws InterruptedException {
+ long startTime = System.currentTimeMillis();
+ long curTime = startTime;
+ synchronized (sync) {
+ while (!active && curTime - startTime < timeout) {
+ sync.wait(curTime - startTime);
+ curTime = System.currentTimeMillis();
+ }
+ }
+ return active;
+ }
+
+ public boolean waitForFinish(long timeout) throws InterruptedException {
+ long startTime = System.currentTimeMillis();
+ long curTime = startTime;
+ synchronized (sync) {
+ while (active && curTime - startTime < timeout) {
+ sync.wait(curTime - startTime);
+ curTime = System.currentTimeMillis();
+ }
+ }
+ return !active;
+ }
+
+ public boolean waitForMessage(String msg, long timeout) throws InterruptedException {
+ long startTime = System.currentTimeMillis();
+ long curTime = startTime;
+ int n = position;
+ synchronized (sync) {
+ while (curTime - startTime < timeout) {
+ while (n < lines.size()) {
+ // System.out.println("Check: " + lines.get(n));
+ if (msg == null || lines.get(n++).contains(msg)) {
+ return true;
+ }
+ }
+ sync.wait(timeout - (curTime - startTime));
+ curTime = System.currentTimeMillis();
+ }
+ return false;
+ }
+ }
+
+ public boolean waitForMessage(long timeout) throws InterruptedException {
+ return waitForMessage(null, timeout);
+ }
+
+ public String getMessage() {
+ if (position < lines.size())
+ return lines.get(position++);
+ else
+ return null;
+ }
+
+ public String getMessage(int index) {
+ return lines.get(index);
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ public int getMessageCount() {
+ return lines.size();
+ }
+
+ public List<String> getMessages() {
+ return getMessages(position, lines.size());
+ }
+
+ public List<String> getMessages(int to) {
+ return getMessages(position, to);
+ }
+
+ public List<String> getMessages(int from, int to) {
+ synchronized (sync) {
+ if (to < 0)
+ to = lines.size() + to;
+ position = Math.max(position, to);
+ return new ArrayList<String>(lines.subList(from, to));
+ }
+ }
+
+ public void reset() {
+ synchronized (sync) {
+ position = lines.size();
+ }
+ }
+
+ private class Listener implements StreamListener {
+ @Override
+ public void onStart() {
+ synchronized (sync) {
+ active = true;
+ sync.notifyAll();
+ }
+ }
+
+ @Override
+ public void onRead(String line) {
+ //System.out.println("onRead: " + line);
+ synchronized (sync) {
+ lines.add(line);
+ sync.notifyAll();
+ }
+ }
+
+ @Override
+ public void onFinish() {
+ synchronized (sync) {
+ active = false;
+ sync.notifyAll();
+ }
+ }
+
+ @Override
+ public void onException(Throwable e) {
+ exception = e;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamMessageOutput.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import nsk.share.TestFailure;
+
+public class StreamMessageOutput implements MessageOutput {
+ private OutputStream out;
+ private PrintStream pout;
+
+ public StreamMessageOutput() {
+ }
+
+ public StreamMessageOutput(OutputStream out) {
+ bind(out);
+ }
+
+ public void bind(OutputStream out) {
+ this.out = out;
+ this.pout = new PrintStream(out, true); // Autoflush is important
+ }
+
+ public void start() {
+ }
+
+ public void send(String msg) {
+ pout.println(msg);
+ }
+
+ public void finish() {
+ pout.close();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/process/StreamReader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.process;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+public class StreamReader extends Thread {
+ private InputStream in;
+ private List<StreamListener> listeners;
+ private volatile boolean terminate = false;
+ private static final long CLEANUP_TIMEOUT = 60000;
+
+ public StreamReader(String desc) {
+ super("Stream Reader: " + desc);
+ setDaemon(true);
+ }
+
+ public StreamReader(String desc, InputStream in) {
+ this(desc);
+ setStream(in);
+ }
+
+ public void setDescription(String desc) {
+ setName("Stream Reader: " + desc);
+ }
+
+ public void setStream(InputStream in) {
+ this.in = in;
+ }
+
+ public synchronized void addListener(StreamListener listener) {
+ if (listeners == null)
+ listeners = new ArrayList<StreamListener>();
+ listeners.add(listener);
+ }
+
+ public synchronized void removeListener(StreamListener listener) {
+ if (listeners != null) {
+ while (listeners.remove(listener))
+ ;
+ }
+ }
+
+ public void run() {
+ onStart();
+ BufferedReader rd;
+ try {
+ rd = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while (!terminate) {
+ line = rd.readLine();
+ if (line == null)
+ break;
+ onRead(line);
+ while (rd.ready()) {
+ line = rd.readLine();
+ if (line == null)
+ break;
+ onRead(line);
+ }
+ if (line == null)
+ break;
+ }
+ cleanup();
+ onFinish();
+ } catch (IOException e) {
+ if (!terminate)
+ onException(e);
+ else
+ onFinish();
+ }
+ }
+
+ protected void onStart() {
+ if (listeners != null) {
+ for (StreamListener l : listeners)
+ l.onStart();
+ }
+ }
+
+ protected void onRead(String line) {
+ //System.out.println("Read: " + line);
+ if (listeners != null) {
+ for (StreamListener l : listeners)
+ l.onRead(line);
+ }
+ }
+
+ protected void onFinish() {
+ if (listeners != null) {
+ for (StreamListener l : listeners)
+ l.onFinish();
+ }
+ }
+
+ protected void onException(Throwable e) {
+ if (listeners != null) {
+ for (StreamListener l : listeners)
+ l.onException(e);
+ }
+ }
+
+ private void cleanup() {
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void kill() {
+ terminate = true;
+ try {
+ this.join(CLEANUP_TIMEOUT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ this.interrupt();
+ try {
+ this.join(CLEANUP_TIMEOUT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/stack/StackUtils.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.stack;
+
+import java.util.List;
+import java.util.Map;
+
+import nsk.share.TestFailure;
+import nsk.share.log.Log;
+
+public final class StackUtils {
+ private StackUtils() {
+ }
+
+ private static String replace(String s) {
+ return (s == null || s.length() == 0) ? "?" : s;
+ }
+
+ /**
+ * String representation of stack trace element.
+ *
+ * Note that null and empty values are replaced with '?'.
+ */
+ public static String strStackTraceElement(StackTraceElement element) {
+ return "at " + replace(element.getClassName()) + "." + replace(element.getMethodName()) + "(" + replace(element.getFileName()) + ":" + element.getLineNumber() + ")";
+ }
+
+ public static void printStackTraceElement(Log log, StackTraceElement element) {
+ log.info(" " + strStackTraceElement(element));
+ }
+
+ public static void printStackTrace(Log log, StackTraceElement[] elements) {
+ for (StackTraceElement element : elements)
+ printStackTraceElement(log, element);
+ }
+
+ public static void printStackTrace(Log log, Iterable<StackTraceElement> elements) {
+ for (StackTraceElement element : elements)
+ printStackTraceElement(log, element);
+ }
+
+ /**
+ * Check that element matches expected element.
+ *
+ * Expected element is used as pattern for matching. A null or empty
+ * field value means that no comparison is done.
+ */
+ public static boolean matches(StackTraceElement element, StackTraceElement expected) {
+ return
+ (expected.getClassName() == null || expected.getClassName().length() == 0 || expected.getClassName().equals(element.getClassName())) &&
+ (expected.getMethodName() == null || expected.getMethodName().length() == 0 || expected.getMethodName().equals(element.getMethodName())) &&
+ (expected.isNativeMethod() == element.isNativeMethod());
+ }
+
+ public static StackTraceElement expectedTraceElement(String className, String methodName, boolean nativeMethod) {
+ // Replace null className with empty because StackTraceElement constructor does not allow null className.
+ return new StackTraceElement(className == null ? "" : className, methodName, null, (nativeMethod ? -2 : 0));
+ }
+
+ public static void addExpectedTraceElement(List<StackTraceElement> expectedTrace, String className, String methodName, boolean nativeMethod) {
+ expectedTrace.add(0, expectedTraceElement(className, methodName, nativeMethod));
+ }
+
+ /**
+ * Check that trace elements starting from given index match expected elements.
+ */
+ public static void checkMatches(StackTraceElement[] elements, List<StackTraceElement> expectedTrace, int i) {
+ if (elements.length - i < expectedTrace.size())
+ throw new TestFailure("Expected at least " + expectedTrace.size() + " trace elements, got only " + (i + 1));
+ for (int j = 0; j < expectedTrace.size(); ++j) {
+ StackTraceElement expected = expectedTrace.get((expectedTrace.size() - 1) - j);
+ int index = (elements.length - 1) - i - j;
+ StackTraceElement actual = elements[index];
+ if (!matches(actual, expected))
+ throw new TestFailure("Expected element at index " + index + " to match: " + strStackTraceElement(expected));
+ }
+ }
+
+ /**
+ * Find matching stack trace element starting from top of the stack.
+ */
+ public static int findMatch(StackTraceElement[] elements, StackTraceElement expected) {
+ for (int i = 0; i < elements.length; ++i)
+ if (StackUtils.matches(elements[elements.length - 1 - i], expected))
+ return i;
+ return -1;
+ }
+
+ /**
+ * Find the stack trace element that contains the "main(String[])" method
+ *
+ * @return StackTraceElement containing "main" function, null if there are more than one
+ */
+ public static StackTraceElement findMain() {
+ Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
+ StackTraceElement mainMethodFrame = null;
+ for(StackTraceElement[] current : stackTraces.values()) {
+ if (current.length > 0) {
+ StackTraceElement last = current[current.length - 1];
+ if ("main".equals(last.getMethodName())) {
+ if (mainMethodFrame == null) {
+ mainMethodFrame = last;
+ } else if (!mainMethodFrame.getClassName().equals(last.getClassName())) {
+ // more than one class has a "main"
+ return null;
+ }
+ }
+ }
+ }
+ return mainMethodFrame;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AbstractClassFileTransformer.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.transform;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+public abstract class AbstractClassFileTransformer
+ implements ClassFileTransformer {
+ protected abstract boolean shouldBeTransformed(String name);
+
+ protected abstract byte[] transformClass(byte[] bytes);
+
+ @Override
+ public byte[] transform(ClassLoader loader, String className,
+ Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
+ byte[] classfileBuffer) throws IllegalClassFormatException {
+ if (shouldBeTransformed(className)) {
+ return transformClass(classfileBuffer);
+ }
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/AnnotationAppender.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.transform;
+
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+
+public abstract class AnnotationAppender {
+ private final String desc;
+ private final boolean visible;
+ private boolean annotationPresent;
+
+ public AnnotationAppender(String desc, boolean visible) {
+ this.desc = desc;
+ this.visible = visible;
+ }
+
+ public void checkAnnotation(String desc, boolean isVisible) {
+ annotationPresent |= visible == isVisible && this.desc.equals(desc);
+ }
+
+ public void addAnnotation(VisitAnnotation func) {
+ if (shouldAdd()) {
+ AnnotationVisitor av = func.visit(desc, true);
+ if (av != null) {
+ postCreate(av);
+ av.visitEnd();
+ annotationPresent = true;
+ }
+ }
+ }
+
+ protected boolean shouldAdd() {
+ return !annotationPresent;
+ }
+
+ protected abstract void postCreate(AnnotationVisitor av);
+
+ @FunctionalInterface
+ public static interface VisitAnnotation {
+ AnnotationVisitor visit(String desc, boolean visible);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/transform/TransformingClassLoader.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.transform;
+
+import vm.share.FileUtils;
+
+public class TransformingClassLoader extends ClassLoader {
+ private final AbstractClassFileTransformer transformer;
+
+ protected TransformingClassLoader(ClassLoader parent,
+ AbstractClassFileTransformer transformer) {
+ super(parent);
+ this.transformer = transformer;
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+ if (!transformer.shouldBeTransformed(name)) {
+ return super.loadClass(name, resolve);
+ }
+ synchronized (getClassLoadingLock(name)) {
+ // First, check if the class has already been loaded
+ Class<?> c = findLoadedClass(name);
+ if (c == null) {
+ try {
+ byte[] bytes = FileUtils.readClass(name);
+ bytes = transformer.transformClass(bytes);
+ c = defineClass(name, bytes, 0, bytes.length);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return super.loadClass(name, resolve);
+ }
+ }
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/Crasher.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmcrasher;
+
+public abstract class Crasher implements Runnable {
+
+ public abstract void run();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/CrasherFactory.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmcrasher;
+
+import vm.share.options.BasicOptionObjectFactory;
+import vm.share.options.FClass;
+import vm.share.options.Factory;
+
+@Factory(placeholder_text="Crasher type", default_value="signal", classlist={
+ @FClass(key="signal", description="Crash VM with a signal", type=SignalCrasher.class),
+ @FClass(key="unsafe.gc", description="Crash VM in GC with Unsafe interface", type=UnsafeGCCrasher.class),
+ @FClass(key="unsafe.java", description="Crash VM in Java thread with Unsafe interface", type=UnsafeJavaCrasher.class),
+})
+public class CrasherFactory extends BasicOptionObjectFactory<Runnable> {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/SignalCrasher.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmcrasher;
+
+import vm.share.ProcessUtils;
+import vm.share.options.Option;
+
+public class SignalCrasher extends Crasher {
+ @Option(name="signalnum", description="signal number", default_value="2")
+ private int num;
+
+ public void run() {
+ ProcessUtils.sendSignal(num);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeGCCrasher.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmcrasher;
+
+import vm.share.UnsafeAccess;
+
+public class UnsafeGCCrasher extends Crasher {
+
+ private static class C {
+ C next;
+ }
+
+ private static C a = null;
+
+ @SuppressWarnings("restriction")
+ @Override
+ public void run() {
+ try {
+ a = new C();
+ a.next = new C();
+ a.next.next = new C();
+ a.next.next.next = new C();
+ UnsafeAccess.unsafe.putInt(a.next, UnsafeAccess.unsafe.objectFieldOffset(C.class.getDeclaredField("next")), 0xDEADCAFE);
+ System.gc();
+ Thread.sleep(1000);
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmcrasher/UnsafeJavaCrasher.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmcrasher;
+
+import vm.share.UnsafeAccess;
+
+public class UnsafeJavaCrasher extends Crasher {
+
+ private static class C {
+ C next;
+ }
+
+ @SuppressWarnings("restriction")
+ @Override
+ public void run() {
+ try {
+ C a = new C();
+ a.next = new C();
+ a.next.next = new C();
+ UnsafeAccess.unsafe.putInt(a.next, UnsafeAccess.unsafe.objectFieldOffset(C.class.getDeclaredField("next")), 0xDEADCAFE);
+ a.next.next.next = new C();
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmstresser;
+
+public class CompileAndDeoptimize implements Runnable {
+
+ public static int v = 0;
+
+ private abstract static class A {
+ public abstract void incv();
+ }
+
+ private static class B extends A {
+ public void incv() {
+ v++;
+ }
+ }
+
+ public static class C extends A {
+ public void incv() {
+ v += (new int[1][1][1][1][1][1][1][1]).length;
+ }
+ }
+
+ private volatile boolean done = false;
+ public volatile A a = new B();
+
+ private void incv() {
+ a.incv();
+ }
+
+ private void inc() {
+ while ( ! done ) {
+ incv();
+ }
+ //while ( ! done ) {
+ // incv();
+ //}
+ //while ( ! done ) {
+ // incv();
+ //}
+ }
+
+ public void run() {
+ try {
+ Thread t = new Thread(new Runnable() { @Override public void run() { inc(); } });
+ t.start();
+ Thread.sleep(100);
+ a = (A) CompileAndDeoptimize.class.getClassLoader().loadClass(B.class.getName().replaceAll("B$", "C")).getConstructors()[0].newInstance(new Object[0]);
+ //Thread.sleep(1000);
+ //done = true;
+ //t.join();
+
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package vm.share.vmstresser;
+
+import java.util.*;
+import java.util.concurrent.locks.*;
+
+import nsk.share.*;
+import nsk.share.classload.*;
+import nsk.share.test.*;
+
+/**
+ * Stresser that load classes until OOME, then unload some of them and continue loading.
+ */
+public class MetaspaceStresser extends Thread {
+
+ /**
+ * Capacity of class containers.
+ * This amount of classes will be unloaded on reset call.
+ */
+ public static final int DEFAULT_BUCKET_SIZE = 4000;
+
+ public static final int DEFAULT_PAUSE_TIME = 0;
+
+ /*
+ * Loaded classes stored in ClassContainer instances.
+ * Such instances organized in array-based stack as it is
+ * one of the simplest way to minimize possibility
+ * to get OOME and guarntee that after replacing
+ * reference to class container by null there will be
+ * no cached refereces and container will be reclaimed by
+ * GC and classes will become unloadable.
+ */
+ // Maximum available amount of arrays with class containers.
+ private static final int CONTAINERS_ARRAY_LENGTH = 1000;
+ // Maximum length array with class containers.
+ private static final int CONTAINER_ARRAYS_COUNT = 100;
+
+ private ClassContainersStack containersStack = new ClassContainersStack(CONTAINER_ARRAYS_COUNT * CONTAINERS_ARRAY_LENGTH,
+ CONTAINERS_ARRAY_LENGTH);
+ private ClassContainer newContainer = null;
+
+ private ExecutionController controller = null;
+ private int bucketSize = DEFAULT_BUCKET_SIZE;
+ private int pauseTime = DEFAULT_PAUSE_TIME;
+
+ private ReentrantLock lock = new ReentrantLock();
+
+ /**
+ * Construct MetaspaceStrresser with default bucket size
+ * and pause time.
+ * @param c controller to control execution time.
+ */
+ public MetaspaceStresser(ExecutionController c) {
+ controller = c;
+ }
+
+ /**
+ * Construct MetaspaceStrresser with custom bucket size
+ * and pause time.
+ * @param c controller to control execution time.
+ * @param bucketSize classes to be unloaded on reset.
+ * @param pauseTime pause after reset.
+ */
+ public MetaspaceStresser(ExecutionController c, int bucketSize, int pauseTime) {
+ this(c);
+ this.bucketSize = bucketSize;
+ this.pauseTime = pauseTime;
+ }
+
+ /**
+ * Fill Metaspace with classes.
+ * Classes will be loaded until OOME, then some of them will be unloaded.
+ */
+ public synchronized void prepare() {
+ while (controller.continueExecution()) {
+ try {
+ fillContainerStack();
+ } catch (OutOfMemoryError oome) {
+ unloadLastClassBucket();
+ return;
+ } catch (ClassNotFoundException cnfe) {
+ throw new TestBug("Unexpected exception in stresser.", cnfe);
+ }
+ }
+ }
+
+ /**
+ * Load new class to container, fill containerStack.
+ * Classes will be loaded until OOME
+ * @throws ClassNotFoundException
+ */
+ private void fillContainerStack() throws ClassNotFoundException {
+ newContainer = new ClassContainer();
+ while (newContainer.size() < bucketSize && controller.continueExecution()) {
+ newContainer.loadClass();
+ }
+ containersStack.push(newContainer);
+ newContainer = null;
+ }
+
+ /**
+ * Run stresser.
+ * Stresser will load classes until OOME, then bucketSize classes
+ * will be unloaded and stresser will wait pauseTime millisiconds
+ * before continuing class loading.
+ */
+ public void run() {
+ try {
+ while (controller.continueExecution()) {
+ try {
+ fillContainerStack();
+ } catch (OutOfMemoryError oome) {
+ unloadLastClassBucket();
+ try {
+ Thread.sleep(pauseTime);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ } catch (Throwable e) {
+ throw new TestBug("Unexpected exception in stresser.", e);
+ } finally {
+ containersStack.free();
+ }
+ }
+
+ /**
+ * Unload most recently loaded bucket of classes.
+ */
+ public void unloadLastClassBucket() {
+ while (controller.continueExecution()) {
+ try {
+ containersStack.pop();
+ System.gc();
+ break;
+ } catch (OutOfMemoryError oome) {
+ oome.printStackTrace();
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Array-based stack for ClassContainer's.
+ */
+ private class ClassContainersStack {
+
+ private int arrayLength = 0;
+ private int arraysCount = 0;
+ private int arrayIndex = 0;
+ private int elemIndex = 0;
+
+ private ClassContainer data[][];
+
+ /**
+ * Create ClassContainersStack that will be able
+ * to store size classes in arrays of segmentSize length.
+ */
+ public ClassContainersStack(int size, int segementSize) {
+ arrayLength = segementSize;
+ arraysCount = size / arrayLength;
+ data = new ClassContainer[arraysCount][];
+ data[0] = new ClassContainer[arrayLength];
+ }
+
+ /**
+ * Push ClassContainer c into stack.
+ */
+ public synchronized void push(ClassContainer c) {
+ data[arrayIndex][elemIndex] = c;
+ elemIndex++;
+ if (elemIndex == arrayLength) {
+ if (arrayIndex == arraysCount) {
+ throw new TestBug("ClassContainersStack ran out of available slots");
+ }
+ data[arrayIndex + 1] = new ClassContainer[arrayLength];
+ arrayIndex++;
+ elemIndex = 0;
+ }
+ }
+
+ /**
+ * Remove reference to top ClassContainer.
+ */
+ public synchronized void pop() {
+ data[arrayIndex][elemIndex] = null;
+ if (elemIndex > 0) {
+ elemIndex--;
+ } else if (arrayIndex > 0) {
+ data[arrayIndex] = null;
+ arrayIndex--;
+ elemIndex = arrayLength - 1;
+ }
+ }
+
+ /**
+ * Remove all stored ClassContainers.
+ */
+ public synchronized void free() {
+ data = null;
+ System.gc();
+ data = new ClassContainer[arraysCount][];
+ data[0] = new ClassContainer[arrayLength];
+ arrayIndex = 0;
+ elemIndex = 0;
+ }
+
+ }
+
+ /// Variable used to create uniqe name for generated classes.
+ private static long lastClass = 0;
+
+ /**
+ * Class container consists of classes and their ClassLoader, so
+ * if there will be no references to container and classes inside it then
+ * it could be easely collected by GC.
+ */
+ private class ClassContainer {
+
+ private List<Class> classes = new LinkedList<Class>();
+ private GeneratingClassLoader loader = new GeneratingClassLoader();
+ private String prefix = loader.getPrefix();
+ private int length = loader.getNameLength();
+
+ public void loadClass() throws ClassNotFoundException {
+ String newName = prefix + "c" + lastClass;
+ lastClass++;
+ while (newName.length() < length) {
+ newName = newName + "c";
+ }
+ classes.add(loader.loadClass(newName));
+ }
+
+ public int size() {
+ return classes.size();
+ }
+ }
+
+}