changeset 2254:6d01bcd91f8a

Merge
author lana
date Fri, 02 Sep 2016 02:40:58 +0000
parents 7ef51cfe867e e7038398e5a9
children 82b94cb5f342
files test/lib/share/classes/jdk/test/lib/Asserts.java test/lib/share/classes/jdk/test/lib/JDKToolFinder.java test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java test/lib/share/classes/jdk/test/lib/Platform.java test/lib/share/classes/jdk/test/lib/Utils.java test/lib/share/classes/jdk/test/lib/apps/LingeredApp.java test/lib/share/classes/jdk/test/lib/apps/LingeredAppWithDeadlock.java test/lib/share/classes/jdk/test/lib/hprof/HprofParser.java test/lib/share/classes/jdk/test/lib/hprof/README test/lib/share/classes/jdk/test/lib/hprof/model/AbstractJavaHeapObjectVisitor.java test/lib/share/classes/jdk/test/lib/hprof/model/ArrayTypeCodes.java test/lib/share/classes/jdk/test/lib/hprof/model/HackJavaValue.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaBoolean.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaByte.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaChar.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaClass.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaDouble.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaField.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaFloat.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaHeapObject.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaHeapObjectVisitor.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaInt.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaLazyReadObject.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaLong.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaObject.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaObjectArray.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaObjectRef.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaShort.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaStatic.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaThing.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaValue.java test/lib/share/classes/jdk/test/lib/hprof/model/JavaValueArray.java test/lib/share/classes/jdk/test/lib/hprof/model/ReachableExcludes.java test/lib/share/classes/jdk/test/lib/hprof/model/ReachableExcludesImpl.java test/lib/share/classes/jdk/test/lib/hprof/model/ReachableObjects.java test/lib/share/classes/jdk/test/lib/hprof/model/ReferenceChain.java test/lib/share/classes/jdk/test/lib/hprof/model/Root.java test/lib/share/classes/jdk/test/lib/hprof/model/Snapshot.java test/lib/share/classes/jdk/test/lib/hprof/model/StackFrame.java test/lib/share/classes/jdk/test/lib/hprof/model/StackTrace.java test/lib/share/classes/jdk/test/lib/hprof/parser/FileReadBuffer.java test/lib/share/classes/jdk/test/lib/hprof/parser/HprofReader.java test/lib/share/classes/jdk/test/lib/hprof/parser/MappedReadBuffer.java test/lib/share/classes/jdk/test/lib/hprof/parser/PositionDataInputStream.java test/lib/share/classes/jdk/test/lib/hprof/parser/PositionInputStream.java test/lib/share/classes/jdk/test/lib/hprof/parser/ReadBuffer.java test/lib/share/classes/jdk/test/lib/hprof/parser/Reader.java test/lib/share/classes/jdk/test/lib/hprof/util/ArraySorter.java test/lib/share/classes/jdk/test/lib/hprof/util/Comparer.java test/lib/share/classes/jdk/test/lib/hprof/util/CompositeEnumeration.java test/lib/share/classes/jdk/test/lib/hprof/util/Misc.java test/lib/share/classes/jdk/test/lib/hprof/util/VectorSorter.java test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java test/lib/share/classes/jdk/test/lib/process/ProcessTools.java test/lib/share/classes/jdk/test/lib/process/StreamPumper.java
diffstat 144 files changed, 12576 insertions(+), 9849 deletions(-) [+]
line wrap: on
line diff
--- a/common/autoconf/generated-configure.sh	Thu Sep 01 23:20:09 2016 +0000
+++ b/common/autoconf/generated-configure.sh	Fri Sep 02 02:40:58 2016 +0000
@@ -5095,7 +5095,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1470863189
+DATE_WHEN_GENERATED=1472718471
 
 ###############################################################################
 #
@@ -15944,6 +15944,8 @@
     HOTSPOT_TARGET_CPU_DEFINE=S390
   elif test "x$OPENJDK_TARGET_CPU" = xs390x; then
     HOTSPOT_TARGET_CPU_DEFINE=S390
+  elif test "x$OPENJDK_TARGET_CPU" != x; then
+    HOTSPOT_TARGET_CPU_DEFINE=$(echo $OPENJDK_TARGET_CPU | tr a-z A-Z)
   fi
 
 
@@ -16117,6 +16119,8 @@
     HOTSPOT_BUILD_CPU_DEFINE=S390
   elif test "x$OPENJDK_BUILD_CPU" = xs390x; then
     HOTSPOT_BUILD_CPU_DEFINE=S390
+  elif test "x$OPENJDK_BUILD_CPU" != x; then
+    HOTSPOT_BUILD_CPU_DEFINE=$(echo $OPENJDK_BUILD_CPU | tr a-z A-Z)
   fi
 
 
--- a/common/autoconf/platform.m4	Thu Sep 01 23:20:09 2016 +0000
+++ b/common/autoconf/platform.m4	Fri Sep 02 02:40:58 2016 +0000
@@ -454,6 +454,8 @@
     HOTSPOT_$1_CPU_DEFINE=S390
   elif test "x$OPENJDK_$1_CPU" = xs390x; then
     HOTSPOT_$1_CPU_DEFINE=S390
+  elif test "x$OPENJDK_$1_CPU" != x; then
+    HOTSPOT_$1_CPU_DEFINE=$(echo $OPENJDK_$1_CPU | tr a-z A-Z)
   fi
   AC_SUBST(HOTSPOT_$1_CPU_DEFINE)
 
--- a/make/CompileJavaModules.gmk	Thu Sep 01 23:20:09 2016 +0000
+++ b/make/CompileJavaModules.gmk	Fri Sep 02 02:40:58 2016 +0000
@@ -504,7 +504,7 @@
         $($(MODULE)_ADD_JAVAC_FLAGS) \
         --module-source-path $(MODULESOURCEPATH) \
         --module-path $(MODULEPATH) \
-        -system none, \
+        --system none, \
 ))
 
 TARGETS += $($(MODULE)) $($(MODULE)_COPY_EXTRA)
--- a/make/Images.gmk	Thu Sep 01 23:20:09 2016 +0000
+++ b/make/Images.gmk	Fri Sep 02 02:40:58 2016 +0000
@@ -116,8 +116,10 @@
 JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX)
 
 JLINK_ORDER_RESOURCES := **module-info.class
+JLINK_JLI_CLASSES :=
 ifeq ($(ENABLE_GENERATE_CLASSLIST), true)
   JLINK_ORDER_RESOURCES += @$(SUPPORT_OUTPUTDIR)/classlist/classlist
+  JLINK_JLI_CLASSES := --generate-jli-classes=@$(SUPPORT_OUTPUTDIR)/classlist/jli_trace.out
 endif
 JLINK_ORDER_RESOURCES += \
     /java.base/java/** \
@@ -131,6 +133,7 @@
     --endian $(OPENJDK_BUILD_CPU_ENDIAN) \
     --release-info $(BASE_RELEASE_FILE) \
     --order-resources=$(call CommaList, $(JLINK_ORDER_RESOURCES)) \
+    $(JLINK_JLI_CLASSES) \
     #
 
 ifeq ($(JLINK_KEEP_PACKAGED_MODULES), true)
--- a/make/common/SetupJavaCompilers.gmk	Thu Sep 01 23:20:09 2016 +0000
+++ b/make/common/SetupJavaCompilers.gmk	Fri Sep 02 02:40:58 2016 +0000
@@ -88,7 +88,7 @@
 $(eval $(call SetupJavaCompiler,GENERATE_USINGJDKBYTECODE, \
     JVM := $(JAVA_SMALL), \
     JAVAC := $(NEW_JAVAC), \
-    FLAGS := --upgrade-module-path $(JDK_OUTPUTDIR)/modules -system none $(DISABLE_WARNINGS), \
+    FLAGS := --upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none $(DISABLE_WARNINGS), \
     SERVER_DIR := $(SJAVAC_SERVER_DIR), \
     SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
 
--- a/make/common/TestFilesCompilation.gmk	Thu Sep 01 23:20:09 2016 +0000
+++ b/make/common/TestFilesCompilation.gmk	Fri Sep 02 02:40:58 2016 +0000
@@ -86,6 +86,7 @@
         LANG := C, \
         CFLAGS := $$($1_CFLAGS) $$($1_CFLAGS_$$($1_PREFIX)$$(name)), \
         LDFLAGS := $$($1_LDFLAGS) $$($1_LDFLAGS_$$($1_PREFIX)$$(name)), \
+        LIBS := $$($1_LIBS_$$($1_PREFIX)$$(name)), \
         OPTIMIZATION := LOW, \
     )) \
     $$(eval $1 += $$(BUILD_TEST_$$(name)) )  \
--- a/make/test/BuildTestLib.gmk	Thu Sep 01 23:20:09 2016 +0000
+++ b/make/test/BuildTestLib.gmk	Fri Sep 02 02:40:58 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -48,7 +48,7 @@
 # test-lib.jar will contain only hprof classes until JDK-8081381 is resolved
 $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \
     SETUP := GENERATE_USINGJDKBYTECODE, \
-    SRC := $(TEST_LIB_SOURCE_DIR)/share/classes/jdk/test/lib/hprof, \
+    SRC := $(TEST_LIB_SOURCE_DIR)/jdk/test/lib/hprof, \
     BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \
     JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \
 ))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/ClassFileInstaller.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Dump a class file for a class on the class path in the current directory, or
+ * in the specified JAR file. This class is usually used when you build a class
+ * from a test library, but want to use this class in a sub-process.
+ *
+ * For example, to build the following library class:
+ * test/lib/sun/hotspot/WhiteBox.java
+ *
+ * You would use the following tags:
+ *
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ *
+ * JTREG would build the class file under
+ * ${JTWork}/classes/test/lib/sun/hotspot/WhiteBox.class
+ *
+ * With you run your main test class using "@run main MyMainClass", JTREG would setup the
+ * -classpath to include "${JTWork}/classes/test/lib/", so MyMainClass would be able to
+ * load the WhiteBox class.
+ *
+ * However, if you run a sub process, and do not wish to use the exact same -classpath,
+ * You can use ClassFileInstaller to ensure that WhiteBox is available in the current
+ * directory of your test:
+ *
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *
+ * Or, you can use the -jar option to store the class in the specified JAR file. If a relative
+ * path name is given, the JAR file would be relative to the current directory of
+ *
+ * @run main ClassFileInstaller -jar myjar.jar sun.hotspot.WhiteBox
+ */
+public class ClassFileInstaller {
+    /**
+     * You can enable debug tracing of ClassFileInstaller by running JTREG with
+     * jtreg -DClassFileInstaller.debug=true ... <names of tests>
+     */
+    public static boolean DEBUG = Boolean.getBoolean("ClassFileInstaller.debug");
+
+    /**
+     * @param args The names of the classes to dump
+     * @throws Exception
+     */
+    public static void main(String... args) throws Exception {
+        if (args.length > 1 && args[0].equals("-jar")) {
+            if (args.length < 2) {
+                throw new RuntimeException("Usage: ClassFileInstaller <options> <classes>\n" +
+                                           "where possible options include:\n" +
+                                           "  -jar <path>             Write to the JAR file <path>");
+            }
+            writeJar(args[1], null, args, 2, args.length);
+        } else {
+            if (DEBUG) {
+                System.out.println("ClassFileInstaller: Writing to " + System.getProperty("user.dir"));
+            }
+            for (String arg : args) {
+                writeClassToDisk(arg);
+            }
+        }
+    }
+
+    public static class Manifest {
+        private InputStream in;
+
+        private Manifest(InputStream in) {
+            this.in = in;
+        }
+
+        static Manifest fromSourceFile(String fileName) throws Exception {
+            String pathName = System.getProperty("test.src") + File.separator + fileName;
+            return new Manifest(new FileInputStream(pathName));
+        }
+
+        // Example:
+        //  String manifest = "Premain-Class: RedefineClassHelper\n" +
+        //                "Can-Redefine-Classes: true\n";
+        //  ClassFileInstaller.writeJar("redefineagent.jar",
+        //    ClassFileInstaller.Manifest.fromString(manifest),
+        //    "RedefineClassHelper");
+        static Manifest fromString(String manifest) throws Exception {
+            return new Manifest(new ByteArrayInputStream(manifest.getBytes()));
+        }
+
+        public InputStream getInputStream() {
+            return in;
+        }
+    }
+
+    private static void writeJar(String jarFile, Manifest manifest, String classes[], int from, int to) throws Exception {
+        if (DEBUG) {
+            System.out.println("ClassFileInstaller: Writing to " + getJarPath(jarFile));
+        }
+
+        (new File(jarFile)).delete();
+        FileOutputStream fos = new FileOutputStream(jarFile);
+        ZipOutputStream zos = new ZipOutputStream(fos);
+
+        // The manifest must be the first or second entry. See comments in JarInputStream
+        // constructor and JDK-5046178.
+        if (manifest != null) {
+            writeToDisk(zos, "META-INF/MANIFEST.MF", manifest.getInputStream());
+        }
+
+        for (int i=from; i<to; i++) {
+            writeClassToDisk(zos, classes[i]);
+        }
+
+        zos.close();
+        fos.close();
+    }
+
+    /*
+     * You can call ClassFileInstaller.writeJar() from your main test class instead of
+     * using "@run ClassFileInstaller -jar ...". E.g.,
+     *
+     * String jarPath = ClassFileInstaller.getJarPath("myjar.jar", "sun.hotspot.WhiteBox")
+     *
+     * If you call this API, make sure you build ClassFileInstaller with the following tags:
+     *
+     * @library testlibrary
+     * @build ClassFileInstaller
+     */
+    public static String writeJar(String jarFile, String... classes) throws Exception {
+        writeJar(jarFile, null, classes, 0, classes.length);
+        return getJarPath(jarFile);
+    }
+
+    public static String writeJar(String jarFile, Manifest manifest, String... classes) throws Exception {
+        writeJar(jarFile, manifest, classes, 0, classes.length);
+        return getJarPath(jarFile);
+    }
+
+    /**
+     * This returns the absolute path to the file specified in "@ClassFileInstaller -jar myjar.jar",
+     * In your test program, instead of using the JAR file name directly:
+     *
+     * String jarPath = "myjar.jar";
+     *
+     * you should call this function, like:
+     *
+     * String jarPath = ClassFileInstaller.getJarPath("myjar.jar")
+     *
+     * The reasons are:
+     * (1) Using absolute path makes it easy to cut-and-paste from the JTR file and rerun your
+     *     test in any directory.
+     * (2) In the future, we may make the JAR file name unique to avoid clobbering
+     *     during parallel JTREG execution.
+     *
+     */
+    public static String getJarPath(String jarFileName) {
+        return new File(jarFileName).getAbsolutePath();
+    }
+
+    public static void writeClassToDisk(String className) throws Exception {
+        writeClassToDisk((ZipOutputStream)null, className);
+    }
+    private static void writeClassToDisk(ZipOutputStream zos, String className) throws Exception {
+        writeClassToDisk(zos, className, "");
+    }
+
+    public static void writeClassToDisk(String className, String prependPath) throws Exception {
+        writeClassToDisk(null, className, prependPath);
+    }
+    private static void writeClassToDisk(ZipOutputStream zos, String className, String prependPath) throws Exception {
+        ClassLoader cl = ClassFileInstaller.class.getClassLoader();
+
+        // Convert dotted class name to a path to a class file
+        String pathName = className.replace('.', '/').concat(".class");
+        InputStream is = cl.getResourceAsStream(pathName);
+        if (is == null) {
+            throw new RuntimeException("Failed to find " + pathName);
+        }
+        if (prependPath.length() > 0) {
+            pathName = prependPath + "/" + pathName;
+        }
+        writeToDisk(zos, pathName, is);
+    }
+
+    public static void writeClassToDisk(String className, byte[] bytecode) throws Exception {
+        writeClassToDisk(null, className, bytecode);
+    }
+    private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode) throws Exception {
+        writeClassToDisk(zos, className, bytecode, "");
+    }
+
+    public static void writeClassToDisk(String className, byte[] bytecode, String prependPath) throws Exception {
+        writeClassToDisk(null, className, bytecode, prependPath);
+    }
+    private static void writeClassToDisk(ZipOutputStream zos, String className, byte[] bytecode, String prependPath) throws Exception {
+        // Convert dotted class name to a path to a class file
+        String pathName = className.replace('.', '/').concat(".class");
+        if (prependPath.length() > 0) {
+            pathName = prependPath + "/" + pathName;
+        }
+        writeToDisk(zos, pathName, new ByteArrayInputStream(bytecode));
+    }
+
+    private static void writeToDisk(ZipOutputStream zos, String pathName, InputStream is) throws Exception {
+        if (DEBUG) {
+            System.out.println("ClassFileInstaller: Writing " + pathName);
+        }
+        if (zos != null) {
+            ZipEntry ze = new ZipEntry(pathName);
+            zos.putNextEntry(ze);
+            byte[] buf = new byte[1024];
+            int len;
+            while ((len = is.read(buf))>0){
+                zos.write(buf, 0, len);
+            }
+        } else {
+            // Create the class file's package directory
+            Path p = Paths.get(pathName);
+            if (pathName.contains("/")) {
+                Files.createDirectories(p.getParent());
+            }
+            // Create the class file
+            Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING);
+        }
+        is.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/RedefineClassHelper.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.PrintWriter;
+import java.lang.instrument.*;
+import jdk.test.lib.InMemoryJavaCompiler;
+
+/*
+ * Helper class to write tests that redefine classes.
+ * When main method is run, it will create a redefineagent.jar that can be used
+ * with the -javaagent option to support redefining classes in jtreg tests.
+ *
+ * See sample test in test/testlibrary_tests/RedefineClassTest.java
+ */
+public class RedefineClassHelper {
+
+    public static Instrumentation instrumentation;
+    public static void premain(String agentArgs, Instrumentation inst) {
+        instrumentation = inst;
+    }
+
+    /**
+     * Redefine a class
+     *
+     * @param clazz Class to redefine
+     * @param javacode String with the new java code for the class to be redefined
+     */
+    public static void redefineClass(Class clazz, String javacode) throws Exception {
+        byte[] bytecode = InMemoryJavaCompiler.compile(clazz.getName(), javacode);
+        redefineClass(clazz, bytecode);
+    }
+
+    /**
+     * Redefine a class
+     *
+     * @param clazz Class to redefine
+     * @param bytecode byte[] with the new class
+     */
+    public static void redefineClass(Class clazz, byte[] bytecode) throws Exception {
+        instrumentation.redefineClasses(new ClassDefinition(clazz, bytecode));
+    }
+
+    /**
+     * Main method to be invoked before test to create the redefineagent.jar
+     */
+    public static void main(String[] args) throws Exception {
+        ClassFileInstaller.main("RedefineClassHelper");
+
+        PrintWriter pw = new PrintWriter("MANIFEST.MF");
+        pw.println("Premain-Class: RedefineClassHelper");
+        pw.println("Can-Redefine-Classes: true");
+        pw.close();
+
+        sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+        if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineClassHelper.class" })) {
+            throw new Exception("jar operation failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/Asserts.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.util.Objects;
+
+/**
+ * Asserts that can be used for verifying assumptions in tests.
+ *
+ * An assertion will throw a {@link RuntimeException} if the assertion isn't true.
+ * All the asserts can be imported into a test by using a static import:
+ *
+ * <pre>
+ * {@code
+ * import static jdk.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * </pre>
+ */
+public class Asserts {
+
+    /**
+     * Shorthand for {@link #assertLessThan(Comparable, Comparable)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertLessThan(Comparable, Comparable)
+     */
+    public static <T extends Comparable<T>> void assertLT(T lhs, T rhs) {
+        assertLessThan(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertLessThan(Comparable, Comparable, String)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertLessThan(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertLT(T lhs, T rhs, String msg) {
+        assertLessThan(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertLessThan(Comparable, Comparable, String)} with a default message.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertLessThan(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertLessThan(T lhs, T rhs) {
+        assertLessThan(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is less than {@code rhs}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static <T extends Comparable<T>>void assertLessThan(T lhs, T rhs, String msg) {
+        if (!(compare(lhs, rhs, msg) < 0)) {
+            msg = Objects.toString(msg, "assertLessThan")
+                    + ": expected that " + Objects.toString(lhs)
+                    + " < " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertLessThanOrEqual(Comparable, Comparable)
+     */
+    public static <T extends Comparable<T>> void assertLTE(T lhs, T rhs) {
+        assertLessThanOrEqual(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable, String)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertLessThanOrEqual(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertLTE(T lhs, T rhs, String msg) {
+        assertLessThanOrEqual(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertLessThanOrEqual(Comparable, Comparable, String)} with a default message.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertLessThanOrEqual(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs) {
+        assertLessThanOrEqual(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is less than or equal to {@code rhs}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs, String msg) {
+        if (!(compare(lhs, rhs, msg) <= 0)) {
+            msg = Objects.toString(msg, "assertLessThanOrEqual")
+                    + ": expected that " + Objects.toString(lhs)
+                    + " <= " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Shorthand for {@link #assertEquals(Object, Object)}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertEquals(Object, Object)
+     */
+    public static void assertEQ(Object lhs, Object rhs) {
+        assertEquals(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertEquals(Object, Object, String)}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertEquals(Object, Object, String)
+     */
+    public static void assertEQ(Object lhs, Object rhs, String msg) {
+        assertEquals(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertEquals(java.lang.Object, java.lang.Object, java.lang.String)} with a default message.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertEquals(Object, Object, String)
+     */
+    public static void assertEquals(Object lhs, Object rhs) {
+        assertEquals(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is equal to {@code rhs}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertEquals(Object lhs, Object rhs, String msg) {
+        if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) {
+            msg = Objects.toString(msg, "assertEquals")
+                    + ": expected " + Objects.toString(lhs)
+                    + " to equal " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertSame(Object, Object, String)
+     */
+    public static void assertSame(Object lhs, Object rhs) {
+        assertSame(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is the same as {@code rhs}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertSame(Object lhs, Object rhs, String msg) {
+        if (lhs != rhs) {
+            msg = Objects.toString(msg, "assertSame")
+                    + ": expected " + Objects.toString(lhs)
+                    + " to equal " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertGreaterThanOrEqual(Comparable, Comparable)
+     */
+    public static <T extends Comparable<T>> void assertGTE(T lhs, T rhs) {
+        assertGreaterThanOrEqual(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertGreaterThanOrEqual(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertGTE(T lhs, T rhs, String msg) {
+        assertGreaterThanOrEqual(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)} with a default message.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertGreaterThanOrEqual(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs) {
+        assertGreaterThanOrEqual(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is greater than or equal to {@code rhs}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs, String msg) {
+        if (!(compare(lhs, rhs, msg) >= 0)) {
+            msg = Objects.toString(msg, "assertGreaterThanOrEqual")
+                    + ": expected " + Objects.toString(lhs)
+                    + " >= " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Shorthand for {@link #assertGreaterThan(Comparable, Comparable)}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertGreaterThan(Comparable, Comparable)
+     */
+    public static <T extends Comparable<T>> void assertGT(T lhs, T rhs) {
+        assertGreaterThan(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertGreaterThan(Comparable, Comparable, String)}.
+     *
+     * @param <T> a type
+     * @param lhs the left hand value
+     * @param rhs the right hand value
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertGreaterThan(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertGT(T lhs, T rhs, String msg) {
+        assertGreaterThan(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertGreaterThan(Comparable, Comparable, String)} with a default message.
+     *
+     * @param <T> a type
+     * @param lhs the left hand value
+     * @param rhs the right hand value
+     * @see #assertGreaterThan(Comparable, Comparable, String)
+     */
+    public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs) {
+        assertGreaterThan(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is greater than {@code rhs}.
+     *
+     * @param <T> a type
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs, String msg) {
+        if (!(compare(lhs, rhs, msg) > 0)) {
+            msg = Objects.toString(msg, "assertGreaterThan")
+                    + ": expected " + Objects.toString(lhs)
+                    + " > " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Shorthand for {@link #assertNotEquals(Object, Object)}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertNotEquals(Object, Object)
+     */
+    public static void assertNE(Object lhs, Object rhs) {
+        assertNotEquals(lhs, rhs);
+    }
+
+    /**
+     * Shorthand for {@link #assertNotEquals(Object, Object, String)}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @see #assertNotEquals(Object, Object, String)
+     */
+    public static void assertNE(Object lhs, Object rhs, String msg) {
+        assertNotEquals(lhs, rhs, msg);
+    }
+
+    /**
+     * Calls {@link #assertNotEquals(Object, Object, String)} with a default message.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @see #assertNotEquals(Object, Object, String)
+     */
+    public static void assertNotEquals(Object lhs, Object rhs) {
+        assertNotEquals(lhs, rhs, null);
+    }
+
+    /**
+     * Asserts that {@code lhs} is not equal to {@code rhs}.
+     *
+     * @param lhs The left hand side of the comparison.
+     * @param rhs The right hand side of the comparison.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertNotEquals(Object lhs, Object rhs, String msg) {
+        if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) {
+            msg = Objects.toString(msg, "assertNotEquals")
+                    + ": expected " + Objects.toString(lhs)
+                    + " to not equal " + Objects.toString(rhs);
+            fail(msg);
+        }
+    }
+
+    /**
+     * Calls {@link #assertNull(Object, String)} with a default message.
+     *
+     * @param o The reference assumed to be null.
+     * @see #assertNull(Object, String)
+     */
+    public static void assertNull(Object o) {
+        assertNull(o, null);
+    }
+
+    /**
+     * Asserts that {@code o} is null.
+     *
+     * @param o The reference assumed to be null.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertNull(Object o, String msg) {
+        assertEquals(o, null, msg);
+    }
+
+    /**
+     * Calls {@link #assertNotNull(Object, String)} with a default message.
+     *
+     * @param o The reference assumed <i>not</i> to be null,
+     * @see #assertNotNull(Object, String)
+     */
+    public static void assertNotNull(Object o) {
+        assertNotNull(o, null);
+    }
+
+    /**
+     * Asserts that {@code o} is <i>not</i> null.
+     *
+     * @param o The reference assumed <i>not</i> to be null,
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertNotNull(Object o, String msg) {
+        assertNotEquals(o, null, msg);
+    }
+
+    /**
+     * Calls {@link #assertFalse(boolean, String)} with a default message.
+     *
+     * @param value The value assumed to be false.
+     * @see #assertFalse(boolean, String)
+     */
+    public static void assertFalse(boolean value) {
+        assertFalse(value, null);
+    }
+
+    /**
+     * Asserts that {@code value} is {@code false}.
+     *
+     * @param value The value assumed to be false.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertFalse(boolean value, String msg) {
+        if (value) {
+            msg = Objects.toString(msg, "assertFalse")
+                    + ": expected false, was true";
+            fail(msg);
+        }
+    }
+
+    /**
+     * Calls {@link #assertTrue(boolean, String)} with a default message.
+     *
+     * @param value The value assumed to be true.
+     * @see #assertTrue(boolean, String)
+     */
+    public static void assertTrue(boolean value) {
+        assertTrue(value, null);
+    }
+
+    /**
+     * Asserts that {@code value} is {@code true}.
+     *
+     * @param value The value assumed to be true.
+     * @param msg A description of the assumption; {@code null} for a default message.
+     * @throws RuntimeException if the assertion is not true.
+     */
+    public static void assertTrue(boolean value, String msg) {
+        if (!value) {
+            msg = Objects.toString(msg, "assertTrue")
+                    + ": expected true, was false";
+            fail(msg);
+        }
+    }
+
+    private static <T extends Comparable<T>> int compare(T lhs, T rhs, String msg) {
+        if (lhs == null || rhs == null) {
+            fail(lhs, rhs, msg + ": values must be non-null:", ",");
+        }
+        return lhs.compareTo(rhs);
+    }
+
+/**
+     * Asserts that two strings are equal.
+     *
+     * If strings are not equals, then exception message
+     * will contain {@code msg} followed by list of mismatched lines.
+     *
+     * @param str1 First string to compare.
+     * @param str2 Second string to compare.
+     * @param msg A description of the assumption.
+     * @throws RuntimeException if strings are not equal.
+     */
+    public static void assertStringsEqual(String str1, String str2,
+                                          String msg) {
+        String lineSeparator = System.getProperty("line.separator");
+        String str1Lines[] = str1.split(lineSeparator);
+        String str2Lines[] = str2.split(lineSeparator);
+
+        int minLength = Math.min(str1Lines.length, str2Lines.length);
+        String longestStringLines[] = ((str1Lines.length == minLength) ?
+                                       str2Lines : str1Lines);
+
+        boolean stringsAreDifferent = false;
+
+        StringBuilder messageBuilder = new StringBuilder(msg);
+
+        messageBuilder.append("\n");
+
+        for (int line = 0; line < minLength; line++) {
+            if (!str1Lines[line].equals(str2Lines[line])) {
+                messageBuilder.append(String.
+                                      format("[line %d] '%s' differs " +
+                                             "from '%s'\n",
+                                             line,
+                                             str1Lines[line],
+                                             str2Lines[line]));
+                stringsAreDifferent = true;
+            }
+        }
+
+        if (minLength < longestStringLines.length) {
+            String stringName = ((longestStringLines == str1Lines) ?
+                                 "first" : "second");
+            messageBuilder.append(String.format("Only %s string contains " +
+                                                "following lines:\n",
+                                                stringName));
+            stringsAreDifferent = true;
+            for(int line = minLength; line < longestStringLines.length; line++) {
+                messageBuilder.append(String.
+                                      format("[line %d] '%s'", line,
+                                             longestStringLines[line]));
+            }
+        }
+
+        if (stringsAreDifferent) {
+            fail(messageBuilder.toString());
+        }
+    }
+
+    /**
+     * Returns a string formatted with a message and expected and actual values.
+     * @param lhs the actual value
+     * @param rhs  the expected value
+     * @param message the actual value
+     * @param relation the asserted relationship between lhs and rhs
+     * @return a formatted string
+     */
+    public static String format(Object lhs, Object rhs, String message, String relation) {
+        StringBuilder sb = new StringBuilder(80);
+        if (message != null) {
+            sb.append(message);
+            sb.append(' ');
+        }
+        sb.append("<");
+        sb.append(Objects.toString(lhs));
+        sb.append("> ");
+        sb.append(Objects.toString(relation, ","));
+        sb.append(" <");
+        sb.append(Objects.toString(rhs));
+        sb.append(">");
+        return sb.toString();
+    }
+
+    /**
+     * Fail reports a failure with message fail.
+     *
+     * @throws RuntimeException always
+     */
+    public static void fail() {
+        fail("fail");
+    }
+
+    /**
+     * Fail reports a failure with a message.
+     * @param message for the failure
+     * @throws RuntimeException always
+     */
+    public static void fail(String message) {
+        throw new RuntimeException(message);
+    }
+
+    /**
+     * Fail reports a failure with a formatted message.
+     *
+     * @param lhs the actual value
+     * @param rhs the expected value
+     * @param message to be format before the expected and actual values
+     * @param relation the asserted relationship between lhs and rhs
+     * @throws RuntimeException always
+     */
+    public static void fail(Object lhs, Object rhs, String message, String relation) {
+        throw new RuntimeException(format(lhs, rhs, message, relation));
+    }
+
+    /**
+     * Fail reports a failure with a message and a cause.
+     * @param message to be format before the expected and actual values
+     * @param cause the exception that caused this failure
+     * @throws RuntimeException always
+     */
+    public static void fail(String message, Throwable cause) {
+        throw new RuntimeException(message, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/BuildHelper.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.io.File;
+import java.io.FileReader;
+import java.util.Properties;
+
+public class BuildHelper {
+
+    /**
+     * Commercial builds should have the BUILD_TYPE set to commercial
+     * within the release file, found at the root of the JDK.
+     */
+    public static boolean isCommercialBuild() throws Exception {
+        String buildType = getReleaseProperty("BUILD_TYPE","notFound");
+        return buildType.equals("commercial");
+    }
+
+
+    /**
+     * Return the value for property key, or defaultValue if no property not found.
+     * If present, double quotes are trimmed.
+     */
+    public static String getReleaseProperty(String key, String defaultValue) throws Exception {
+        Properties properties = getReleaseProperties();
+        String value = properties.getProperty(key, defaultValue);
+        return trimDoubleQuotes(value);
+    }
+
+    /**
+     * Return the value for property key, or null if no property not found.
+     * If present, double quotes are trimmed.
+     */
+    public static String getReleaseProperty(String key) throws Exception {
+        return getReleaseProperty(key, null);
+    }
+
+    /**
+     * Get properties from the release file
+     */
+    public static Properties getReleaseProperties() throws Exception {
+        Properties properties = new Properties();
+        properties.load(new FileReader(getReleaseFile()));
+        return properties;
+    }
+
+    /**
+     * Every JDK has a release file in its root.
+     * @return A handler to the release file.
+     */
+    public static File getReleaseFile() throws Exception {
+        String jdkPath = getJDKRoot();
+        File releaseFile = new File(jdkPath,"release");
+        if ( ! releaseFile.canRead() ) {
+            throw new Exception("Release file is not readable, or it is absent: " +
+                    releaseFile.getCanonicalPath());
+        }
+        return releaseFile;
+    }
+
+    /**
+     * Returns path to the JDK under test.
+     * This path is obtained through the test.jdk property, usually set by JTREG.
+     */
+    public static String getJDKRoot() {
+        String jdkPath = System.getProperty("test.jdk");
+        if (jdkPath == null) {
+            throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
+                    + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+        }
+        return jdkPath;
+    }
+
+    /**
+     * Trim double quotes from the beginning and the end of the given string.
+     * @param original string to trim.
+     * @return a new trimmed string.
+     */
+    public static String trimDoubleQuotes(String original) {
+        if (original == null) { return null; }
+        String trimmed = original.replaceAll("^\"+|\"+$", "");
+        return trimmed;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/ByteCodeLoader.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.security.SecureClassLoader;
+
+/**
+ * {@code ByteCodeLoader} can be used for easy loading of byte code already
+ * present in memory.
+ *
+ * {@code InMemoryCompiler} can be used for compiling source code in a string
+ * into byte code, which then can be loaded with {@code ByteCodeLoader}.
+ *
+ * @see InMemoryCompiler
+ */
+public class ByteCodeLoader extends SecureClassLoader {
+    private final String className;
+    private final byte[] byteCode;
+    private volatile Class<?> holder;
+
+    /**
+     * Creates a new {@code ByteCodeLoader} ready to load a class with the
+     * given name and the given byte code.
+     *
+     * @param className The name of the class
+     * @param byteCode The byte code of the class
+     */
+    public ByteCodeLoader(String className, byte[] byteCode) {
+        this.className = className;
+        this.byteCode = byteCode;
+    }
+
+    @Override
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        if (!name.equals(className)) {
+            return super.loadClass(name);
+        }
+        if (holder == null) {
+            synchronized(this) {
+                if (holder == null) {
+                    holder = findClass(name);
+                }
+            }
+        }
+        return holder;
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        if (!name.equals(className)) {
+            throw new ClassNotFoundException(name);
+        }
+
+        return defineClass(name, byteCode, 0, byteCode.length);
+    }
+
+    /**
+     * Utility method for creating a new {@code ByteCodeLoader} and then
+     * directly load the given byte code.
+     *
+     * @param className The name of the class
+     * @param byteCode The byte code for the class
+     * @throws ClassNotFoundException if the class can't be loaded
+     * @return A {@see Class} object representing the class
+     */
+    public static Class<?> load(String className, byte[] byteCode) throws ClassNotFoundException {
+        return new ByteCodeLoader(className, byteCode).loadClass(className);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/DynamicVMOption.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import java.lang.management.ManagementFactory;
+
+/**
+ * A utility class to work with VM options which could be altered during
+ * execution.
+ *
+ * This class is a wrapper around {@code com.sun.management.VMOption}.
+ * It provides more convenient interface to read/write the values.
+ *
+ */
+public class DynamicVMOption {
+
+    private final HotSpotDiagnosticMXBean mxBean;
+
+    /**
+     * VM option name, like "MinHeapFreeRatio".
+     */
+    public final String name;
+
+    /**
+     * Creates an instance of DynamicVMOption.
+     *
+     * @param name the VM option name
+     */
+    public DynamicVMOption(String name) {
+        this.name = name;
+        mxBean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+    }
+
+    /**
+     * Sets a new value for the option.
+     * Trying to set not applicable value will cause IllegalArgumentException.
+     * Behavior with null is undefined, most likely NPE will be thrown.
+     *
+     * @param newValue the value to be set
+     * @see #getValue()
+     * @throws IllegalArgumentException if newValue is not applicable to the option
+     */
+    public final void setValue(String newValue) {
+        mxBean.setVMOption(name, newValue);
+    }
+
+    /**
+     * Returns the value of option.
+     *
+     * @return the current option value
+     * @see #setValue(java.lang.String)
+     */
+    public final String getValue() {
+        return mxBean.getVMOption(name).getValue();
+    }
+
+    /**
+     * Returns true, if option is writable, false otherwise.
+     *
+     * @return true, if option is writable, false otherwise
+     */
+    public final boolean isWriteable() {
+        return mxBean.getVMOption(name).isWriteable();
+    }
+
+    /**
+     * Checks if the given value is applicable for the option.
+     *
+     * This method tries to set the option to the new value. If no exception
+     * has been thrown the value is treated as valid.
+     *
+     * Calling this method will not change the option value. After an attempt
+     * to set a new value, the option will be restored to its previous value.
+     *
+     * @param value the value to verify
+     * @return true if option could be set to the given value
+     */
+    public boolean isValidValue(String value) {
+        boolean isValid = true;
+        String oldValue = getValue();
+        try {
+            setValue(value);
+        } catch (NullPointerException e) {
+            if (value == null) {
+                isValid = false;
+            }
+        } catch (IllegalArgumentException e) {
+            isValid = false;
+        } finally {
+            setValue(oldValue);
+        }
+        return isValid;
+    }
+
+    /**
+     * Returns the value of the given VM option as String.
+     *
+     * This is a simple shortcut for {@code new DynamicVMOption(name).getValue()}
+     *
+     * @param name the name of VM option
+     * @return value as a string
+     * @see #getValue()
+     */
+    public static String getString(String name) {
+        return new DynamicVMOption(name).getValue();
+    }
+
+    /**
+     * Returns the value of the given option as int.
+     *
+     * @param name the name of VM option
+     * @return value parsed as integer
+     * @see #getString(java.lang.String)
+     *
+     */
+    public static int getInt(String name) {
+        return Integer.parseInt(getString(name));
+    }
+
+    /**
+     * Sets the VM option to a new value.
+     *
+     * This is a simple shortcut for {@code new DynamicVMOption(name).setValue(value)}
+     *
+     * @param name the name of VM option
+     * @param value the value to be set
+     * @see #setValue(java.lang.String)
+     */
+    public static void setString(String name, String value) {
+        new DynamicVMOption(name).setValue(value);
+    }
+
+    /**
+     * Sets the VM option value to a new integer value.
+     *
+     * @param name the name of VM option
+     * @param value the integer value to be set
+     * @see #setString(java.lang.String, java.lang.String)
+     */
+    public static void setInt(String name, int value) {
+        new DynamicVMOption(name).setValue(Integer.toString(value));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/FileInstaller.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/**
+ * Copy a resource: file or directory recursively, using relative path(src and dst)
+ * which are applied to test source directory(src) and current directory(dst)
+ */
+public class FileInstaller {
+    /**
+     * @param args source and destination
+     * @throws IOException if an I/O error occurs
+     */
+    public static void main(String[] args) throws IOException {
+        if (args.length != 2) {
+            throw new IllegalArgumentException("Unexpected number of arguments for file copy");
+        }
+        Path src = Paths.get(Utils.TEST_SRC, args[0]).toAbsolutePath();
+        Path dst = Paths.get(args[1]).toAbsolutePath();
+        if (src.toFile().exists()) {
+            if (src.toFile().isDirectory()) {
+                Files.walkFileTree(src, new CopyFileVisitor(src, dst));
+            } else {
+                Path dstDir = dst.getParent();
+                if (!dstDir.toFile().exists()) {
+                    Files.createDirectories(dstDir);
+                }
+                Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
+            }
+        } else {
+            throw new IOException("Can't find source " + src);
+        }
+    }
+
+    private static class CopyFileVisitor extends SimpleFileVisitor<Path> {
+        private final Path copyFrom;
+        private final Path copyTo;
+
+        public CopyFileVisitor(Path copyFrom, Path copyTo) {
+            this.copyFrom = copyFrom;
+            this.copyTo = copyTo;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            Path relativePath = file.relativize(copyFrom);
+            Path destination = copyTo.resolve(relativePath);
+            if (!destination.toFile().exists()) {
+                Files.createDirectories(destination);
+            }
+            return FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            if (!file.toFile().isFile()) {
+                return FileVisitResult.CONTINUE;
+            }
+            Path relativePath = copyFrom.relativize(file);
+            Path destination = copyTo.resolve(relativePath);
+            Files.copy(file, destination, StandardCopyOption.COPY_ATTRIBUTES);
+            return FileVisitResult.CONTINUE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/InMemoryJavaCompiler.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.URI;
+import java.util.Arrays;
+
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.FileObject;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+/**
+ * {@code InMemoryJavaCompiler} can be used for compiling a {@link
+ * CharSequence} to a {@code byte[]}.
+ *
+ * The compiler will not use the file system at all, instead using a {@link
+ * ByteArrayOutputStream} for storing the byte code. For the source code, any
+ * kind of {@link CharSequence} can be used, e.g. {@link String}, {@link
+ * StringBuffer} or {@link StringBuilder}.
+ *
+ * The {@code InMemoryCompiler} can easily be used together with a {@code
+ * ByteClassLoader} to easily compile and load source code in a {@link String}:
+ *
+ * <pre>
+ * {@code
+ * import jdk.test.lib.InMemoryJavaCompiler;
+ * import jdk.test.lib.ByteClassLoader;
+ *
+ * class Example {
+ *     public static void main(String[] args) {
+ *         String className = "Foo";
+ *         String sourceCode = "public class " + className + " {" +
+ *                             "    public void bar() {" +
+ *                             "        System.out.println("Hello from bar!");" +
+ *                             "    }" +
+ *                             "}";
+ *         byte[] byteCode = InMemoryJavaCompiler.compile(className, sourceCode);
+ *         Class fooClass = ByteClassLoader.load(className, byteCode);
+ *     }
+ * }
+ * }
+ * </pre>
+ */
+public class InMemoryJavaCompiler {
+    private static class MemoryJavaFileObject extends SimpleJavaFileObject {
+        private final String className;
+        private final CharSequence sourceCode;
+        private final ByteArrayOutputStream byteCode;
+
+        public MemoryJavaFileObject(String className, CharSequence sourceCode) {
+            super(URI.create("string:///" + className.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
+            this.className = className;
+            this.sourceCode = sourceCode;
+            this.byteCode = new ByteArrayOutputStream();
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return sourceCode;
+        }
+
+        @Override
+        public OutputStream openOutputStream() throws IOException {
+            return byteCode;
+        }
+
+        public byte[] getByteCode() {
+            return byteCode.toByteArray();
+        }
+
+        public String getClassName() {
+            return className;
+        }
+    }
+
+    private static class FileManagerWrapper extends ForwardingJavaFileManager {
+        private MemoryJavaFileObject file;
+
+        public FileManagerWrapper(MemoryJavaFileObject file) {
+            super(getCompiler().getStandardFileManager(null, null, null));
+            this.file = file;
+        }
+
+        @Override
+        public JavaFileObject getJavaFileForOutput(Location location, String className,
+                                                   Kind kind, FileObject sibling)
+            throws IOException {
+            if (!file.getClassName().equals(className)) {
+                throw new IOException("Expected class with name " + file.getClassName() +
+                                      ", but got " + className);
+            }
+            return file;
+        }
+    }
+
+    /**
+     * Compiles the class with the given name and source code.
+     *
+     * @param className The name of the class
+     * @param sourceCode The source code for the class with name {@code className}
+     * @param options additional command line options
+     * @throws RuntimeException if the compilation did not succeed
+     * @return The resulting byte code from the compilation
+     */
+    public static byte[] compile(String className, CharSequence sourceCode, String... options) {
+        MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode);
+        CompilationTask task = getCompilationTask(file, options);
+
+        if(!task.call()) {
+            throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode);
+        }
+
+        return file.getByteCode();
+    }
+
+    private static JavaCompiler getCompiler() {
+        return ToolProvider.getSystemJavaCompiler();
+    }
+
+    private static CompilationTask getCompilationTask(MemoryJavaFileObject file, String... options) {
+        return getCompiler().getTask(null, new FileManagerWrapper(file), null, Arrays.asList(options), null, Arrays.asList(file));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/JDKToolFinder.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.io.FileNotFoundException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public final class JDKToolFinder {
+
+    private JDKToolFinder() {
+    }
+
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getJDKTool(String tool) {
+
+        // First try to find the executable in test.jdk
+        try {
+            return getTool(tool, "test.jdk");
+        } catch (FileNotFoundException e) {
+
+        }
+
+        // Now see if it's available in compile.jdk
+        try {
+            return getTool(tool, "compile.jdk");
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException("Failed to find " + tool +
+                    ", looked in test.jdk (" + System.getProperty("test.jdk") +
+                    ") and compile.jdk (" + System.getProperty("compile.jdk") + ")");
+        }
+    }
+
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code compile.jdk}
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getCompileJDKTool(String tool) {
+        try {
+            return getTool(tool, "compile.jdk");
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code test.jdk}
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getTestJDKTool(String tool) {
+        try {
+            return getTool(tool, "test.jdk");
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String getTool(String tool, String property) throws FileNotFoundException {
+        String jdkPath = System.getProperty(property);
+
+        if (jdkPath == null) {
+            throw new RuntimeException(
+                    "System property '" + property + "' not set. This property is normally set by jtreg. "
+                    + "When running test separately, set this property using '-D" + property + "=/path/to/jdk'.");
+        }
+
+        Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : ""));
+
+        Path jdkTool = Paths.get(jdkPath, toolName.toString());
+        if (!jdkTool.toFile().exists()) {
+            throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath());
+        }
+
+        return jdkTool.toAbsolutePath().toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/JDKToolLauncher.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import jdk.test.lib.process.ProcessTools;
+
+/**
+ * A utility for constructing command lines for starting JDK tool processes.
+ *
+ * The JDKToolLauncher can in particular be combined with a
+ * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following
+ * code run {@code jmap -heap} against a process with GC logging turned on for
+ * the {@code jmap} process:
+ *
+ * <pre>
+ * {@code
+ * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ *                                       .addVMArg("-XX:+PrintGC");
+ *                                       .addVMArg("-XX:+PrintGCDetails")
+ *                                       .addToolArg("-heap")
+ *                                       .addToolArg(pid);
+ * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ * Process p = pb.start();
+ * }
+ * </pre>
+ */
+public class JDKToolLauncher {
+    private final String executable;
+    private final List<String> vmArgs = new ArrayList<String>();
+    private final List<String> toolArgs = new ArrayList<String>();
+
+    private JDKToolLauncher(String tool, boolean useCompilerJDK) {
+        if (useCompilerJDK) {
+            executable = JDKToolFinder.getJDKTool(tool);
+        } else {
+            executable = JDKToolFinder.getTestJDKTool(tool);
+        }
+        vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs()));
+    }
+
+    /**
+     * Creates a new JDKToolLauncher for the specified tool. Using tools path
+     * from the compiler JDK.
+     *
+     * @param tool
+     *            The name of the tool
+     * @return A new JDKToolLauncher
+     */
+    public static JDKToolLauncher create(String tool) {
+        return new JDKToolLauncher(tool, true);
+    }
+
+    /**
+     * Creates a new JDKToolLauncher for the specified tool in the Tested JDK.
+     *
+     * @param tool
+     *            The name of the tool
+     *
+     * @return A new JDKToolLauncher
+     */
+    public static JDKToolLauncher createUsingTestJDK(String tool) {
+        return new JDKToolLauncher(tool, false);
+    }
+
+    /**
+     * Adds an argument to the JVM running the tool.
+     *
+     * The JVM arguments are passed to the underlying JVM running the tool.
+     * Arguments will automatically be prepended with "-J".
+     *
+     * Any platform specific arguments required for running the tool are
+     * automatically added.
+     *
+     *
+     * @param arg
+     *            The argument to VM running the tool
+     * @return The JDKToolLauncher instance
+     */
+    public JDKToolLauncher addVMArg(String arg) {
+        vmArgs.add(arg);
+        return this;
+    }
+
+    /**
+     * Adds an argument to the tool.
+     *
+     * @param arg
+     *            The argument to the tool
+     * @return The JDKToolLauncher instance
+     */
+    public JDKToolLauncher addToolArg(String arg) {
+        toolArgs.add(arg);
+        return this;
+    }
+
+    /**
+     * Returns the command that can be used for running the tool.
+     *
+     * @return An array whose elements are the arguments of the command.
+     */
+    public String[] getCommand() {
+        List<String> command = new ArrayList<String>();
+        command.add(executable);
+        // Add -J in front of all vmArgs
+        for (String arg : vmArgs) {
+            command.add("-J" + arg);
+        }
+        command.addAll(toolArgs);
+        return command.toArray(new String[command.size()]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/Platform.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.util.regex.Pattern;
+
+public class Platform {
+    public  static final String vmName      = System.getProperty("java.vm.name");
+    public  static final String vmInfo      = System.getProperty("java.vm.info");
+    private static final String osName      = System.getProperty("os.name");
+    private static final String dataModel   = System.getProperty("sun.arch.data.model");
+    private static final String vmVersion   = System.getProperty("java.vm.version");
+    private static final String jdkDebug    = System.getProperty("jdk.debug");
+    private static final String osArch      = System.getProperty("os.arch");
+    private static final String userName    = System.getProperty("user.name");
+    private static final String compiler    = System.getProperty("sun.management.compiler");
+
+    public static boolean isClient() {
+        return vmName.endsWith(" Client VM");
+    }
+
+    public static boolean isServer() {
+        return vmName.endsWith(" Server VM");
+    }
+
+    public static boolean isGraal() {
+        return vmName.endsWith(" Graal VM");
+    }
+
+    public static boolean isZero() {
+        return vmName.endsWith(" Zero VM");
+    }
+
+    public static boolean isMinimal() {
+        return vmName.endsWith(" Minimal VM");
+    }
+
+    public static boolean isEmbedded() {
+        return vmName.contains("Embedded");
+    }
+
+    public static boolean isTieredSupported() {
+        return compiler.contains("Tiered Compilers");
+    }
+
+    public static boolean isInt() {
+        return vmInfo.contains("interpreted");
+    }
+
+    public static boolean isMixed() {
+        return vmInfo.contains("mixed");
+    }
+
+    public static boolean isComp() {
+        return vmInfo.contains("compiled");
+    }
+
+    public static boolean is32bit() {
+        return dataModel.equals("32");
+    }
+
+    public static boolean is64bit() {
+        return dataModel.equals("64");
+    }
+
+    public static boolean isAix() {
+        return isOs("aix");
+    }
+
+    public static boolean isLinux() {
+        return isOs("linux");
+    }
+
+    public static boolean isOSX() {
+        return isOs("mac");
+    }
+
+    public static boolean isSolaris() {
+        return isOs("sunos");
+    }
+
+    public static boolean isWindows() {
+        return isOs("win");
+    }
+
+    private static boolean isOs(String osname) {
+        return osName.toLowerCase().startsWith(osname.toLowerCase());
+    }
+
+    public static String getOsName() {
+        return osName;
+    }
+
+    public static boolean isDebugBuild() {
+        return (jdkDebug.toLowerCase().contains("debug"));
+    }
+
+    public static String getVMVersion() {
+        return vmVersion;
+    }
+
+    // Returns true for sparc and sparcv9.
+    public static boolean isSparc() {
+        return isArch("sparc.*");
+    }
+
+    public static boolean isARM() {
+        return isArch("arm.*");
+    }
+
+    public static boolean isPPC() {
+        return isArch("ppc.*");
+    }
+
+    public static boolean isX86() {
+        // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
+        return isArch("(i386)|(x86(?!_64))");
+    }
+
+    public static boolean isX64() {
+        // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64'
+        return isArch("(amd64)|(x86_64)");
+    }
+
+    public static boolean isAArch64() {
+        return isArch("aarch64");
+    }
+
+    public static String getOsArch() {
+        return osArch;
+    }
+
+    /**
+     * Return a boolean for whether we expect to be able to attach
+     * the SA to our own processes on this system.
+     */
+    public static boolean shouldSAAttach() throws Exception {
+
+        if (isAix()) {
+            return false;   // SA not implemented.
+        } else if (isLinux()) {
+            return canPtraceAttachLinux();
+        } else if (isOSX()) {
+            return canAttachOSX();
+        } else {
+            // Other platforms expected to work:
+            return true;
+        }
+    }
+
+    /**
+     * On Linux, first check the SELinux boolean "deny_ptrace" and return false
+     * as we expect to be denied if that is "1".  Then expect permission to attach
+     * if we are root, so return true.  Then return false for an expected denial
+     * if "ptrace_scope" is 1, and true otherwise.
+     */
+    public static boolean canPtraceAttachLinux() throws Exception {
+
+        // SELinux deny_ptrace:
+        String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace");
+        if (deny_ptrace != null && deny_ptrace.contains("1")) {
+            // ptrace will be denied:
+            return false;
+        }
+
+        // YAMA enhanced security ptrace_scope:
+        // 0 - a process can PTRACE_ATTACH to any other process running under the same uid
+        // 1 - restricted ptrace: a process must be a children of the inferior or user is root
+        // 2 - only processes with CAP_SYS_PTRACE may use ptrace or user is root
+        // 3 - no attach: no processes may use ptrace with PTRACE_ATTACH
+        String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope");
+        if (ptrace_scope != null) {
+            if (ptrace_scope.startsWith("3")) {
+                return false;
+            }
+            if (!userName.equals("root") && !ptrace_scope.startsWith("0")) {
+                // ptrace will be denied:
+                return false;
+            }
+        }
+        // Otherwise expect to be permitted:
+        return true;
+    }
+
+    /**
+     * On OSX, expect permission to attach only if we are root.
+     */
+    public static boolean canAttachOSX() throws Exception {
+        return userName.equals("root");
+    }
+
+    private static boolean isArch(String archnameRE) {
+        return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
+                      .matcher(osArch)
+                      .matches();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/Utils.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.function.BooleanSupplier;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import jdk.internal.misc.Unsafe;
+
+import static jdk.test.lib.Asserts.assertTrue;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/**
+ * Common library for various test helper functions.
+ */
+public final class Utils {
+
+    /**
+     * Returns the value of 'test.class.path' system property.
+     */
+    public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", ".");
+
+    /**
+     * Returns the sequence used by operating system to separate lines.
+     */
+    public static final String NEW_LINE = System.getProperty("line.separator");
+
+    /**
+     * Returns the value of 'test.vm.opts' system property.
+     */
+    public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
+
+    /**
+     * Returns the value of 'test.java.opts' system property.
+     */
+    public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim();
+
+    /**
+     * Returns the value of 'test.src' system property.
+     */
+    public static final String TEST_SRC = System.getProperty("test.src", "").trim();
+
+    private static Unsafe unsafe = null;
+
+    /**
+     * Defines property name for seed value.
+     */
+    public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed";
+
+    /* (non-javadoc)
+     * Random generator with (or without) predefined seed. Depends on
+     * "jdk.test.lib.random.seed" property value.
+     */
+    private static volatile Random RANDOM_GENERATOR;
+
+    /**
+     * Contains the seed value used for {@link java.util.Random} creation.
+     */
+    public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong());
+    /**
+    * Returns the value of 'test.timeout.factor' system property
+    * converted to {@code double}.
+    */
+    public static final double TIMEOUT_FACTOR;
+    static {
+        String toFactor = System.getProperty("test.timeout.factor", "1.0");
+        TIMEOUT_FACTOR = Double.parseDouble(toFactor);
+    }
+
+    /**
+    * Returns the value of JTREG default test timeout in milliseconds
+    * converted to {@code long}.
+    */
+    public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120);
+
+    private Utils() {
+        // Private constructor to prevent class instantiation
+    }
+
+    /**
+     * Returns the list of VM options.
+     *
+     * @return List of VM options
+     */
+    public static List<String> getVmOptions() {
+        return Arrays.asList(safeSplitString(VM_OPTIONS));
+    }
+
+    /**
+     * Returns the list of VM options with -J prefix.
+     *
+     * @return The list of VM options with -J prefix
+     */
+    public static List<String> getForwardVmOptions() {
+        String[] opts = safeSplitString(VM_OPTIONS);
+        for (int i = 0; i < opts.length; i++) {
+            opts[i] = "-J" + opts[i];
+        }
+        return Arrays.asList(opts);
+    }
+
+    /**
+     * Returns the default JTReg arguments for a jvm running a test.
+     * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+     * @return An array of options, or an empty array if no options.
+     */
+    public static String[] getTestJavaOpts() {
+        List<String> opts = new ArrayList<String>();
+        Collections.addAll(opts, safeSplitString(VM_OPTIONS));
+        Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
+        return opts.toArray(new String[0]);
+    }
+
+    /**
+     * Combines given arguments with default JTReg arguments for a jvm running a test.
+     * This is the combination of JTReg arguments test.vm.opts and test.java.opts
+     * @return The combination of JTReg test java options and user args.
+     */
+    public static String[] addTestJavaOpts(String... userArgs) {
+        List<String> opts = new ArrayList<String>();
+        Collections.addAll(opts, getTestJavaOpts());
+        Collections.addAll(opts, userArgs);
+        return opts.toArray(new String[0]);
+    }
+
+    /**
+     * Removes any options specifying which GC to use, for example "-XX:+UseG1GC".
+     * Removes any options matching: -XX:(+/-)Use*GC
+     * Used when a test need to set its own GC version. Then any
+     * GC specified by the framework must first be removed.
+     * @return A copy of given opts with all GC options removed.
+     */
+    private static final Pattern useGcPattern = Pattern.compile(
+            "(?:\\-XX\\:[\\+\\-]Use.+GC)"
+            + "|(?:\\-Xconcgc)");
+    public static List<String> removeGcOpts(List<String> opts) {
+        List<String> optsWithoutGC = new ArrayList<String>();
+        for (String opt : opts) {
+            if (useGcPattern.matcher(opt).matches()) {
+                System.out.println("removeGcOpts: removed " + opt);
+            } else {
+                optsWithoutGC.add(opt);
+            }
+        }
+        return optsWithoutGC;
+    }
+
+    /**
+     * Returns the default JTReg arguments for a jvm running a test without
+     * options that matches regular expressions in {@code filters}.
+     * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+     * @param filters Regular expressions used to filter out options.
+     * @return An array of options, or an empty array if no options.
+     */
+    public static String[] getFilteredTestJavaOpts(String... filters) {
+        String options[] = getTestJavaOpts();
+
+        if (filters.length == 0) {
+            return options;
+        }
+
+        List<String> filteredOptions = new ArrayList<String>(options.length);
+        Pattern patterns[] = new Pattern[filters.length];
+        for (int i = 0; i < filters.length; i++) {
+            patterns[i] = Pattern.compile(filters[i]);
+        }
+
+        for (String option : options) {
+            boolean matched = false;
+            for (int i = 0; i < patterns.length && !matched; i++) {
+                Matcher matcher = patterns[i].matcher(option);
+                matched = matcher.find();
+            }
+            if (!matched) {
+                filteredOptions.add(option);
+            }
+        }
+
+        return filteredOptions.toArray(new String[filteredOptions.size()]);
+    }
+
+    /**
+     * Splits a string by white space.
+     * Works like String.split(), but returns an empty array
+     * if the string is null or empty.
+     */
+    private static String[] safeSplitString(String s) {
+        if (s == null || s.trim().isEmpty()) {
+            return new String[] {};
+        }
+        return s.trim().split("\\s+");
+    }
+
+    /**
+     * @return The full command line for the ProcessBuilder.
+     */
+    public static String getCommandLine(ProcessBuilder pb) {
+        StringBuilder cmd = new StringBuilder();
+        for (String s : pb.command()) {
+            cmd.append(s).append(" ");
+        }
+        return cmd.toString();
+    }
+
+    /**
+     * Returns the free port on the local host.
+     * The function will spin until a valid port number is found.
+     *
+     * @return The port number
+     * @throws InterruptedException if any thread has interrupted the current thread
+     * @throws IOException if an I/O error occurs when opening the socket
+     */
+    public static int getFreePort() throws InterruptedException, IOException {
+        int port = -1;
+
+        while (port <= 0) {
+            Thread.sleep(100);
+
+            ServerSocket serverSocket = null;
+            try {
+                serverSocket = new ServerSocket(0);
+                port = serverSocket.getLocalPort();
+            } finally {
+                serverSocket.close();
+            }
+        }
+
+        return port;
+    }
+
+    /**
+     * Returns the name of the local host.
+     *
+     * @return The host name
+     * @throws UnknownHostException if IP address of a host could not be determined
+     */
+    public static String getHostname() throws UnknownHostException {
+        InetAddress inetAddress = InetAddress.getLocalHost();
+        String hostName = inetAddress.getHostName();
+
+        assertTrue((hostName != null && !hostName.isEmpty()),
+                "Cannot get hostname");
+
+        return hostName;
+    }
+
+    /**
+     * Uses "jcmd -l" to search for a jvm pid. This function will wait
+     * forever (until jtreg timeout) for the pid to be found.
+     * @param key Regular expression to search for
+     * @return The found pid.
+     */
+    public static int waitForJvmPid(String key) throws Throwable {
+        final long iterationSleepMillis = 250;
+        System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
+        System.out.flush();
+        while (true) {
+            int pid = tryFindJvmPid(key);
+            if (pid >= 0) {
+                return pid;
+            }
+            Thread.sleep(iterationSleepMillis);
+        }
+    }
+
+    /**
+     * Searches for a jvm pid in the output from "jcmd -l".
+     *
+     * Example output from jcmd is:
+     * 12498 sun.tools.jcmd.JCmd -l
+     * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
+     *
+     * @param key A regular expression to search for.
+     * @return The found pid, or -1 if not found.
+     * @throws Exception If multiple matching jvms are found.
+     */
+    public static int tryFindJvmPid(String key) throws Throwable {
+        OutputAnalyzer output = null;
+        try {
+            JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
+            jcmdLauncher.addToolArg("-l");
+            output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
+            output.shouldHaveExitValue(0);
+
+            // Search for a line starting with numbers (pid), follwed by the key.
+            Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
+            Matcher matcher = pattern.matcher(output.getStdout());
+
+            int pid = -1;
+            if (matcher.find()) {
+                pid = Integer.parseInt(matcher.group(1));
+                System.out.println("findJvmPid.pid: " + pid);
+                if (matcher.find()) {
+                    throw new Exception("Found multiple JVM pids for key: " + key);
+                }
+            }
+            return pid;
+        } catch (Throwable t) {
+            System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
+            throw t;
+        }
+    }
+
+    /**
+     * Adjusts the provided timeout value for the TIMEOUT_FACTOR
+     * @param tOut the timeout value to be adjusted
+     * @return The timeout value adjusted for the value of "test.timeout.factor"
+     *         system property
+     */
+    public static long adjustTimeout(long tOut) {
+        return Math.round(tOut * Utils.TIMEOUT_FACTOR);
+    }
+
+    /**
+     * Return the contents of the named file as a single String,
+     * or null if not found.
+     * @param filename name of the file to read
+     * @return String contents of file, or null if file not found.
+     * @throws  IOException
+     *          if an I/O error occurs reading from the file or a malformed or
+     *          unmappable byte sequence is read
+     */
+    public static String fileAsString(String filename) throws IOException {
+        Path filePath = Paths.get(filename);
+        if (!Files.exists(filePath)) return null;
+        return new String(Files.readAllBytes(filePath));
+    }
+
+    /**
+     * @return Unsafe instance.
+     */
+    public static synchronized Unsafe getUnsafe() {
+        if (unsafe == null) {
+            try {
+                Field f = Unsafe.class.getDeclaredField("theUnsafe");
+                f.setAccessible(true);
+                unsafe = (Unsafe) f.get(null);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new RuntimeException("Unable to get Unsafe instance.", e);
+            }
+        }
+        return unsafe;
+    }
+    private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    /**
+     * Returns hex view of byte array
+     *
+     * @param bytes byte array to process
+     * @return Space separated hexadecimal string representation of bytes
+     */
+
+    public static String toHexString(byte[] bytes) {
+        char[] hexView = new char[bytes.length * 3];
+        int i = 0;
+        for (byte b : bytes) {
+            hexView[i++] = hexArray[(b >> 4) & 0x0F];
+            hexView[i++] = hexArray[b & 0x0F];
+            hexView[i++] = ' ';
+        }
+        return new String(hexView);
+    }
+
+    /**
+     * Returns {@link java.util.Random} generator initialized with particular seed.
+     * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME}
+     * In case no seed is provided, the method uses a random number.
+     * The used seed printed to stdout.
+     * @return {@link java.util.Random} generator with particular seed.
+     */
+    public static Random getRandomInstance() {
+        if (RANDOM_GENERATOR == null) {
+            synchronized (Utils.class) {
+                if (RANDOM_GENERATOR == null) {
+                    RANDOM_GENERATOR = new Random(SEED);
+                    System.out.printf("For random generator using seed: %d%n", SEED);
+                    System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED);
+                }
+            }
+        }
+        return RANDOM_GENERATOR;
+    }
+
+    /**
+     * Returns random element of non empty collection
+     *
+     * @param <T> a type of collection element
+     * @param collection collection of elements
+     * @return random element of collection
+     * @throws IllegalArgumentException if collection is empty
+     */
+    public static <T> T getRandomElement(Collection<T> collection)
+            throws IllegalArgumentException {
+        if (collection.isEmpty()) {
+            throw new IllegalArgumentException("Empty collection");
+        }
+        Random random = getRandomInstance();
+        int elementIndex = 1 + random.nextInt(collection.size() - 1);
+        Iterator<T> iterator = collection.iterator();
+        while (--elementIndex != 0) {
+            iterator.next();
+        }
+        return iterator.next();
+    }
+
+    /**
+     * Returns random element of non empty array
+     *
+     * @param <T> a type of array element
+     * @param array array of elements
+     * @return random element of array
+     * @throws IllegalArgumentException if array is empty
+     */
+    public static <T> T getRandomElement(T[] array)
+            throws IllegalArgumentException {
+        if (array == null || array.length == 0) {
+            throw new IllegalArgumentException("Empty or null array");
+        }
+        Random random = getRandomInstance();
+        return array[random.nextInt(array.length)];
+    }
+
+    /**
+     * Wait for condition to be true
+     *
+     * @param condition, a condition to wait for
+     */
+    public static final void waitForCondition(BooleanSupplier condition) {
+        waitForCondition(condition, -1L, 100L);
+    }
+
+    /**
+     * Wait until timeout for condition to be true
+     *
+     * @param condition, a condition to wait for
+     * @param timeout a time in milliseconds to wait for condition to be true
+     * specifying -1 will wait forever
+     * @return condition value, to determine if wait was successful
+     */
+    public static final boolean waitForCondition(BooleanSupplier condition,
+            long timeout) {
+        return waitForCondition(condition, timeout, 100L);
+    }
+
+    /**
+     * Wait until timeout for condition to be true for specified time
+     *
+     * @param condition, a condition to wait for
+     * @param timeout a time in milliseconds to wait for condition to be true,
+     * specifying -1 will wait forever
+     * @param sleepTime a time to sleep value in milliseconds
+     * @return condition value, to determine if wait was successful
+     */
+    public static final boolean waitForCondition(BooleanSupplier condition,
+            long timeout, long sleepTime) {
+        long startTime = System.currentTimeMillis();
+        while (!(condition.getAsBoolean() || (timeout != -1L
+                && ((System.currentTimeMillis() - startTime) > timeout)))) {
+            try {
+                Thread.sleep(sleepTime);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new Error(e);
+            }
+        }
+        return condition.getAsBoolean();
+    }
+
+    /**
+     * Interface same as java.lang.Runnable but with
+     * method {@code run()} able to throw any Throwable.
+     */
+    public static interface ThrowingRunnable {
+        void run() throws Throwable;
+    }
+
+    /**
+     * Filters out an exception that may be thrown by the given
+     * test according to the given filter.
+     *
+     * @param test - method that is invoked and checked for exception.
+     * @param filter - function that checks if the thrown exception matches
+     *                 criteria given in the filter's implementation.
+     * @return - exception that matches the filter if it has been thrown or
+     *           {@code null} otherwise.
+     * @throws Throwable - if test has thrown an exception that does not
+     *                     match the filter.
+     */
+    public static Throwable filterException(ThrowingRunnable test,
+            Function<Throwable, Boolean> filter) throws Throwable {
+        try {
+            test.run();
+        } catch (Throwable t) {
+            if (filter.apply(t)) {
+                return t;
+            } else {
+                throw t;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Ensures a requested class is loaded
+     * @param aClass class to load
+     */
+    public static void ensureClassIsLoaded(Class<?> aClass) {
+        if (aClass == null) {
+            throw new Error("Requested null class");
+        }
+        try {
+            Class.forName(aClass.getName(), /* initialize = */ true,
+                    ClassLoader.getSystemClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new Error("Class not found", e);
+        }
+    }
+    /**
+     * @param parent a class loader to be the parent for the returned one
+     * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg
+     *         property and with the given parent
+     */
+    public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) {
+        URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator))
+                .map(Paths::get)
+                .map(Path::toUri)
+                .map(x -> {
+                    try {
+                        return x.toURL();
+                    } catch (MalformedURLException ex) {
+                        throw new Error("Test issue. JTREG property"
+                                + " 'test.class.path'"
+                                + " is not defined correctly", ex);
+                    }
+                }).toArray(URL[]::new);
+        return new URLClassLoader(urls, parent);
+    }
+
+    /**
+     * Runs runnable and checks that it throws expected exception. If exceptionException is null it means
+     * that we expect no exception to be thrown.
+     * @param runnable what we run
+     * @param expectedException expected exception
+     */
+    public static void runAndCheckException(Runnable runnable, Class<? extends Throwable> expectedException) {
+        runAndCheckException(runnable, t -> {
+            if (t == null) {
+                if (expectedException != null) {
+                    throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName());
+                }
+            } else {
+                String message = "Got unexpected exception " + t.getClass().getSimpleName();
+                if (expectedException == null) {
+                    throw new AssertionError(message, t);
+                } else if (!expectedException.isAssignableFrom(t.getClass())) {
+                    message += " instead of " + expectedException.getSimpleName();
+                    throw new AssertionError(message, t);
+                }
+            }
+        });
+    }
+
+    /**
+     * Runs runnable and makes some checks to ensure that it throws expected exception.
+     * @param runnable what we run
+     * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise
+     */
+    public static void runAndCheckException(Runnable runnable, Consumer<Throwable> checkException) {
+        try {
+            runnable.run();
+            checkException.accept(null);
+        } catch (Throwable t) {
+            checkException.accept(t);
+        }
+    }
+
+    /**
+     * Converts to VM type signature
+     *
+     * @param type Java type to convert
+     * @return string representation of VM type
+     */
+    public static String toJVMTypeSignature(Class<?> type) {
+        if (type.isPrimitive()) {
+            if (type == boolean.class) {
+                return "Z";
+            } else if (type == byte.class) {
+                return "B";
+            } else if (type == char.class) {
+                return "C";
+            } else if (type == double.class) {
+                return "D";
+            } else if (type == float.class) {
+                return "F";
+            } else if (type == int.class) {
+                return "I";
+            } else if (type == long.class) {
+                return "J";
+            } else if (type == short.class) {
+                return "S";
+            } else if (type == void.class) {
+                return "V";
+            } else {
+                throw new Error("Unsupported type: " + type);
+            }
+        }
+        String result = type.getName().replaceAll("\\.", "/");
+        if (!type.isArray()) {
+            return "L" + result + ";";
+        }
+        return result;
+    }
+
+    public static Object[] getNullValues(Class<?>... types) {
+        Object[] result = new Object[types.length];
+        int i = 0;
+        for (Class<?> type : types) {
+            result[i++] = NULL_VALUES.get(type);
+        }
+        return result;
+    }
+    private static Map<Class<?>, Object> NULL_VALUES = new HashMap<>();
+    static {
+        NULL_VALUES.put(boolean.class, false);
+        NULL_VALUES.put(byte.class, (byte) 0);
+        NULL_VALUES.put(short.class, (short) 0);
+        NULL_VALUES.put(char.class, '\0');
+        NULL_VALUES.put(int.class, 0);
+        NULL_VALUES.put(long.class, 0L);
+        NULL_VALUES.put(float.class, 0.0f);
+        NULL_VALUES.put(double.class, 0.0d);
+    }
+
+    /**
+     * Returns mandatory property value
+     * @param propName is a name of property to request
+     * @return a String with requested property value
+     */
+    public static String getMandatoryProperty(String propName) {
+        Objects.requireNonNull(propName, "Requested null property");
+        String prop = System.getProperty(propName);
+        Objects.requireNonNull(prop,
+                String.format("A mandatory property '%s' isn't set", propName));
+        return prop;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/apps/LingeredApp.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.apps;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * This is a framework to launch an app that could be synchronized with caller
+ * to make further attach actions reliable across supported platforms
+
+ * Caller example:
+ *   SmartTestApp a = SmartTestApp.startApp(cmd);
+ *     // do something
+ *   a.stopApp();
+ *
+ *   or fine grained control
+ *
+ *   a = new SmartTestApp("MyLock.lck");
+ *   a.createLock();
+ *   a.runApp();
+ *   a.waitAppReady();
+ *     // do something
+ *   a.deleteLock();
+ *   a.waitAppTerminate();
+ *
+ *  Then you can work with app output and process object
+ *
+ *   output = a.getAppOutput();
+ *   process = a.getProcess();
+ *
+ */
+public class LingeredApp {
+
+    private static final long spinDelay = 1000;
+    private static final int appWaitTime = 100;
+
+    private final String lockFileName;
+    private long lockCreationTime;
+    private Process appProcess;
+    private final ArrayList<String> storedAppOutput;
+
+    /*
+     * Drain child process output, store it into string array
+     */
+    class InputGobbler extends Thread {
+
+        InputStream is;
+        List<String> astr;
+
+        InputGobbler(InputStream is, List<String> astr) {
+            this.is = is;
+            this.astr = astr;
+        }
+
+        public void run() {
+            try {
+                InputStreamReader isr = new InputStreamReader(is);
+                BufferedReader br = new BufferedReader(isr);
+                String line = null;
+                while ((line = br.readLine()) != null) {
+                    astr.add(line);
+                }
+            } catch (IOException ex) {
+                // pass
+            }
+        }
+    }
+
+    /**
+     * Create LingeredApp object on caller side. Lock file have be a valid filename
+     * at writable location
+     *
+     * @param lockFileName - the name of lock file
+     */
+    public LingeredApp(String lockFileName) {
+        this.lockFileName = lockFileName;
+        this.storedAppOutput = new ArrayList<String>();
+    }
+
+    public LingeredApp() {
+        final String lockName = UUID.randomUUID().toString() + ".lck";
+        this.lockFileName = lockName;
+        this.storedAppOutput = new ArrayList<String>();
+    }
+
+    /**
+     *
+     * @return name of lock file
+     */
+    public String getLockFileName() {
+        return this.lockFileName;
+    }
+
+    /**
+     *
+     * @return name of testapp
+     */
+    public String getAppName() {
+        return this.getClass().getName();
+    }
+
+    /**
+     *
+     *  @return pid of java process running testapp
+     */
+    public long getPid() {
+        if (appProcess == null) {
+            throw new RuntimeException("Process is not alive");
+        }
+        return appProcess.getPid();
+    }
+
+    /**
+     *
+     * @return process object
+     */
+    public Process getProcess() {
+        return appProcess;
+    }
+
+    /**
+     *
+     * @return application output as string array. Empty array if application produced no output
+     */
+    public List<String> getAppOutput() {
+        if (appProcess.isAlive()) {
+            throw new RuntimeException("Process is still alive. Can't get its output.");
+        }
+        return storedAppOutput;
+    }
+
+    /* Make sure all part of the app use the same method to get dates,
+     as different methods could produce different results
+     */
+    private static long epoch() {
+        return new Date().getTime();
+    }
+
+    private static long lastModified(String fileName) throws IOException {
+        Path path = Paths.get(fileName);
+        BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
+        return attr.lastModifiedTime().toMillis();
+    }
+
+    private static void setLastModified(String fileName, long newTime) throws IOException {
+        Path path = Paths.get(fileName);
+        FileTime fileTime = FileTime.fromMillis(newTime);
+        Files.setLastModifiedTime(path, fileTime);
+    }
+
+    /**
+     * create lock
+     *
+     * @throws IOException
+     */
+    public void createLock() throws IOException {
+        Path path = Paths.get(lockFileName);
+        // Files.deleteIfExists(path);
+        Files.createFile(path);
+        lockCreationTime = lastModified(lockFileName);
+    }
+
+    /**
+     * Delete lock
+     *
+     * @throws IOException
+     */
+    public void deleteLock() throws IOException {
+        try {
+            Path path = Paths.get(lockFileName);
+            Files.delete(path);
+        } catch (NoSuchFileException ex) {
+            // Lock already deleted. Ignore error
+        }
+    }
+
+    public void waitAppTerminate() {
+        while (true) {
+            try {
+                appProcess.waitFor();
+                break;
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+    }
+
+    /**
+     * The app touches the lock file when it's started
+     * wait while it happens. Caller have to delete lock on wait error.
+     *
+     * @param timeout
+     * @throws java.io.IOException
+     */
+    public void waitAppReady(long timeout) throws IOException {
+        long here = epoch();
+        while (true) {
+            long epoch = epoch();
+            if (epoch - here > (timeout * 1000)) {
+                throw new IOException("App waiting timeout");
+            }
+
+            // Live process should touch lock file every second
+            long lm = lastModified(lockFileName);
+            if (lm > lockCreationTime) {
+                break;
+            }
+
+            // Make sure process didn't already exit
+            if (!appProcess.isAlive()) {
+                throw new IOException("App exited unexpectedly with " + appProcess.exitValue());
+            }
+
+            try {
+                Thread.sleep(spinDelay);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+    }
+
+    /**
+     * Run the app
+     *
+     * @param vmArguments
+     * @throws IOException
+     */
+    public void runApp(List<String> vmArguments)
+            throws IOException {
+
+        // We should always use testjava or throw an exception,
+        // so we can't use JDKToolFinder.getJDKTool("java");
+        // that falls back to compile java on error
+        String jdkPath = System.getProperty("test.jdk");
+        if (jdkPath == null) {
+            // we are not under jtreg, try env
+            Map<String, String> env = System.getenv();
+            jdkPath = env.get("TESTJAVA");
+        }
+
+        if (jdkPath == null) {
+            throw new RuntimeException("Can't determine jdk path neither test.jdk property no TESTJAVA env are set");
+        }
+
+        String osname = System.getProperty("os.name");
+        String javapath = jdkPath + ((osname.startsWith("window")) ? "/bin/java.exe" : "/bin/java");
+
+        List<String> cmd = new ArrayList<String>();
+        cmd.add(javapath);
+
+
+        if (vmArguments == null) {
+            // Propagate test.vm.options to LingeredApp, filter out possible empty options
+            String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+");
+            for (String s : testVmOpts) {
+                if (!s.equals("")) {
+                    cmd.add(s);
+                }
+            }
+        }
+        else{
+            // Lets user manage LingeredApp options
+            cmd.addAll(vmArguments);
+        }
+
+        // Make sure we set correct classpath to run the app
+        cmd.add("-cp");
+        String classpath = System.getProperty("test.class.path");
+        cmd.add((classpath == null) ? "." : classpath);
+
+        cmd.add(this.getAppName());
+        cmd.add(lockFileName);
+
+        // Reporting
+        StringBuilder cmdLine = new StringBuilder();
+        for (String strCmd : cmd) {
+            cmdLine.append("'").append(strCmd).append("' ");
+        }
+
+        // A bit of verbosity
+        System.out.println("Command line: [" + cmdLine.toString() + "]");
+
+        ProcessBuilder pb = new ProcessBuilder(cmd);
+        // we don't expect any error output but make sure we are not stuck on pipe
+        // pb.redirectErrorStream(false);
+        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
+
+        appProcess = pb.start();
+
+        // Create pipe reader for process, and read stdin and stderr to array of strings
+        InputGobbler gb = new InputGobbler(appProcess.getInputStream(), storedAppOutput);
+        gb.start();
+    }
+
+    /**
+     * Delete lock file that signals app to terminate, then
+     * wait until app is actually terminated.
+     * @throws IOException
+     */
+    public void stopApp() throws IOException {
+        deleteLock();
+        waitAppTerminate();
+        int exitcode = appProcess.exitValue();
+        if (exitcode != 0) {
+            throw new IOException("LingeredApp terminated with non-zero exit code " + exitcode);
+        }
+    }
+
+    /**
+     *  High level interface for test writers
+     */
+    /**
+     * Factory method that creates LingeredApp object with ready to use application
+     * lock name is autogenerated
+     * @param cmd - vm options, could be null to auto add testvm.options
+     * @return LingeredApp object
+     * @throws IOException
+     */
+    public static LingeredApp startApp(List<String> cmd) throws IOException {
+        LingeredApp a = new LingeredApp();
+        a.createLock();
+        try {
+            a.runApp(cmd);
+            a.waitAppReady(appWaitTime);
+        } catch (Exception ex) {
+            a.deleteLock();
+            throw ex;
+        }
+
+        return a;
+    }
+
+    /**
+     * Factory method that starts pre-created LingeredApp
+     * lock name is autogenerated
+     * @param cmd - vm options, could be null to auto add testvm.options
+     * @param theApp - app to start
+     * @return LingeredApp object
+     * @throws IOException
+     */
+
+    public static void startApp(List<String> cmd, LingeredApp theApp) throws IOException {
+        theApp.createLock();
+        try {
+            theApp.runApp(cmd);
+            theApp.waitAppReady(appWaitTime);
+        } catch (Exception ex) {
+            theApp.deleteLock();
+            throw ex;
+        }
+    }
+
+    public static LingeredApp startApp() throws IOException {
+        return startApp(null);
+    }
+
+    public static void stopApp(LingeredApp app) throws IOException {
+        if (app != null) {
+            // LingeredApp can throw an exception during the intialization,
+            // make sure we don't have cascade NPE
+            app.stopApp();
+        }
+    }
+
+    /**
+     * LastModified time might not work correctly in some cases it might
+     * cause later failures
+     */
+
+    public static boolean isLastModifiedWorking() {
+        boolean sane = true;
+        try {
+            long lm = lastModified(".");
+            if (lm == 0) {
+                System.err.println("SANITY Warning! The lastModifiedTime() doesn't work on this system, it returns 0");
+                sane = false;
+            }
+
+            long now = epoch();
+            if (lm > now) {
+                System.err.println("SANITY Warning! The Clock is wrong on this system lastModifiedTime() > getTime()");
+                sane = false;
+            }
+
+            setLastModified(".", epoch());
+            long lm1 = lastModified(".");
+            if (lm1 <= lm) {
+                System.err.println("SANITY Warning! The setLastModified doesn't work on this system");
+                sane = false;
+            }
+        }
+        catch(IOException e) {
+            System.err.println("SANITY Warning! IOException during sanity check " + e);
+            sane = false;
+        }
+
+        return sane;
+    }
+
+    /**
+     * This part is the application it self
+     */
+    public static void main(String args[]) {
+
+        if (args.length != 1) {
+            System.err.println("Lock file name is not specified");
+            System.exit(7);
+        }
+
+        String theLockFileName = args[0];
+
+        try {
+            Path path = Paths.get(theLockFileName);
+
+            while (Files.exists(path)) {
+                // Touch the lock to indicate our readiness
+                setLastModified(theLockFileName, epoch());
+                Thread.sleep(spinDelay);
+            }
+        } catch (NoSuchFileException ex) {
+            // Lock deleted while we are setting last modified time.
+            // Ignore error and lets the app exits
+        } catch (Exception ex) {
+            System.err.println("LingeredApp ERROR: " + ex);
+            // Leave exit_code = 1 to Java launcher
+            System.exit(3);
+        }
+
+        System.exit(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/apps/LingeredAppWithDeadlock.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.test.lib.apps;
+
+import java.util.concurrent.Phaser;
+
+public class LingeredAppWithDeadlock extends LingeredApp {
+
+    private static final Object Lock1 = new Object();
+    private static final Object Lock2 = new Object();
+
+    private static volatile int reachCount = 0;
+
+    private static final Phaser p = new Phaser(2);
+
+    private static class ThreadOne extends Thread {
+        public void run() {
+            // wait Lock2 is locked
+            p.arriveAndAwaitAdvance();
+            synchronized (Lock1) {
+                // signal Lock1 is locked
+                p.arriveAndAwaitAdvance();
+                synchronized (Lock2) {
+                    reachCount += 1;
+                }
+            }
+        }
+    }
+
+    private static class ThreadTwo extends Thread {
+        public void run() {
+            synchronized (Lock2) {
+                // signal Lock2 is locked
+                p.arriveAndAwaitAdvance();
+                // wait Lock1 is locked
+                p.arriveAndAwaitAdvance();
+                synchronized (Lock1) {
+                    reachCount += 1;
+                }
+            }
+        }
+    }
+
+    public static void main(String args[]) {
+        if (args.length != 1) {
+            System.err.println("Lock file name is not specified");
+            System.exit(7);
+        }
+
+        // Run two theads that should come to deadlock
+        new ThreadOne().start();
+        new ThreadTwo().start();
+
+        if (reachCount > 0) {
+            // Not able to deadlock, exiting
+            System.exit(3);
+        }
+
+        LingeredApp.main(args);
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/CPUSpecificCommandLineOptionTest.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.cli;
+
+import jdk.test.lib.cli.predicate.CPUSpecificPredicate;
+
+/**
+ * Base class for command line options tests that
+ * requires specific CPU arch or specific CPU features.
+ */
+public abstract class CPUSpecificCommandLineOptionTest
+        extends CommandLineOptionTest {
+    /**
+     * Creates new CPU specific test instance that does not
+     * require any CPU features.
+     *
+     * @param cpuArchPattern Regular expression that should
+     *                       match os.arch.
+     */
+    public CPUSpecificCommandLineOptionTest(String cpuArchPattern) {
+        this(cpuArchPattern, null, null);
+    }
+
+    /**
+     * Creates new CPU specific test instance that does not
+     * require from CPU support of {@code supportedCPUFeatures} features
+     * and no support of {@code unsupportedCPUFeatures}.
+     *
+     * @param cpuArchPattern Regular expression that should
+     *                       match os.arch.
+     * @param supportedCPUFeatures Array with names of features that
+     *                             should be supported by CPU. If {@code null},
+     *                             then no features have to be supported.
+     * @param unsupportedCPUFeatures Array with names of features that
+     *                               should not be supported by CPU.
+     *                               If {@code null}, then CPU may support any
+     *                               features.
+     */
+    public CPUSpecificCommandLineOptionTest(String cpuArchPattern,
+            String supportedCPUFeatures[], String unsupportedCPUFeatures[]) {
+        super(new CPUSpecificPredicate(cpuArchPattern, supportedCPUFeatures,
+                unsupportedCPUFeatures));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/CommandLineOptionTest.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.cli;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.function.BooleanSupplier;
+
+import jdk.test.lib.process.ExitCode;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.Utils;
+
+/**
+ * Base class for command line option tests.
+ */
+public abstract class CommandLineOptionTest {
+    public static final String UNLOCK_DIAGNOSTIC_VM_OPTIONS
+            = "-XX:+UnlockDiagnosticVMOptions";
+    public static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS
+            = "-XX:+UnlockExperimentalVMOptions";
+    protected static final String UNRECOGNIZED_OPTION_ERROR_FORMAT
+            = "Unrecognized VM option '[+-]?%s(=.*)?'";
+    protected static final String EXPERIMENTAL_OPTION_ERROR_FORMAT
+            = "VM option '%s' is experimental and must be enabled via "
+            + "-XX:\\+UnlockExperimentalVMOptions.";
+    protected static final String DIAGNOSTIC_OPTION_ERROR_FORMAT
+            = " VM option '%s' is diagnostic and must be enabled via "
+            + "-XX:\\+UnlockDiagnosticVMOptions.";
+    private static final String PRINT_FLAGS_FINAL_FORMAT = "%s\\s*:?=\\s*%s";
+
+    /**
+     * Verifies that JVM startup behavior matches our expectations.
+     *
+     * @param option an option that should be passed to JVM
+     * @param expectedMessages an array of patterns that should occur
+     *                          in JVM output. If {@code null} then
+     *                          JVM output could be empty.
+     * @param unexpectedMessages an array of patterns that should not
+     *                           occur in JVM output. If {@code null} then
+     *                           JVM output could be empty.
+     * @param exitErrorMessage message that will be shown if exit code is not
+     *                           as expected.
+     * @param wrongWarningMessage message that will be shown if warning
+     *                           messages are not as expected.
+     * @param exitCode expected exit code.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyJVMStartup(String option,
+            String expectedMessages[], String unexpectedMessages[],
+            String exitErrorMessage, String wrongWarningMessage,
+            ExitCode exitCode) throws Throwable {
+        CommandLineOptionTest.verifyJVMStartup(expectedMessages,
+                unexpectedMessages, exitErrorMessage,
+                wrongWarningMessage, exitCode, false, option);
+    }
+
+    /**
+     * Verifies that JVM startup behavior matches our expectations.
+     *
+     * @param expectedMessages an array of patterns that should occur
+     *                         in JVM output. If {@code null} then
+     *                         JVM output could be empty.
+     * @param unexpectedMessages an array of patterns that should not
+     *                           occur in JVM output. If {@code null} then
+     *                           JVM output could be empty.
+     * @param exitErrorMessage message that will be shown if exit code is not
+     *                           as expected.
+     * @param wrongWarningMessage message that will be shown if warning
+     *                           messages are not as expected.
+     * @param exitCode expected exit code.
+     * @param addTestVMOptions if {@code true} then test VM options will be
+     *                         passed to VM.
+     * @param options options that should be passed to VM in addition to mode
+     *                flag.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyJVMStartup(String expectedMessages[],
+            String unexpectedMessages[], String exitErrorMessage,
+            String wrongWarningMessage, ExitCode exitCode,
+            boolean addTestVMOptions, String... options)
+                    throws Throwable {
+        List<String> finalOptions = new ArrayList<>();
+        if (addTestVMOptions) {
+            Collections.addAll(finalOptions, ProcessTools.getVmInputArgs());
+            Collections.addAll(finalOptions, Utils.getTestJavaOpts());
+        }
+        Collections.addAll(finalOptions, options);
+        finalOptions.add("-version");
+
+        ProcessBuilder processBuilder
+                = ProcessTools.createJavaProcessBuilder(finalOptions.toArray(
+                new String[finalOptions.size()]));
+        OutputAnalyzer outputAnalyzer
+                = new OutputAnalyzer(processBuilder.start());
+
+        try {
+                outputAnalyzer.shouldHaveExitValue(exitCode.value);
+        } catch (RuntimeException e) {
+            String errorMessage = String.format(
+                    "JVM process should have exit value '%d'.%n%s",
+                    exitCode.value, exitErrorMessage);
+            throw new AssertionError(errorMessage, e);
+        }
+
+        verifyOutput(expectedMessages, unexpectedMessages,
+                wrongWarningMessage, outputAnalyzer);
+    }
+
+    /**
+     * Verifies that JVM startup behavior matches our expectations.
+     *
+     * @param expectedMessages an array of patterns that should occur in JVM
+     *                         output. If {@code null} then
+     *                         JVM output could be empty.
+     * @param unexpectedMessages an array of patterns that should not occur
+     *                           in JVM output. If {@code null} then
+     *                           JVM output could be empty.
+     * @param wrongWarningMessage message that will be shown if messages are
+     *                            not as expected.
+     * @param outputAnalyzer OutputAnalyzer instance
+     * @throws AssertionError if verification fails.
+     */
+    public static void verifyOutput(String[] expectedMessages,
+            String[] unexpectedMessages, String wrongWarningMessage,
+            OutputAnalyzer outputAnalyzer) {
+        if (expectedMessages != null) {
+            for (String expectedMessage : expectedMessages) {
+                try {
+                    outputAnalyzer.shouldMatch(expectedMessage);
+                } catch (RuntimeException e) {
+                    String errorMessage = String.format(
+                            "Expected message not found: '%s'.%n%s",
+                            expectedMessage, wrongWarningMessage);
+                    throw new AssertionError(errorMessage, e);
+                }
+            }
+        }
+
+        if (unexpectedMessages != null) {
+            for (String unexpectedMessage : unexpectedMessages) {
+                try {
+                    outputAnalyzer.shouldNotMatch(unexpectedMessage);
+                } catch (RuntimeException e) {
+                    String errorMessage = String.format(
+                            "Unexpected message found: '%s'.%n%s",
+                            unexpectedMessage, wrongWarningMessage);
+                    throw new AssertionError(errorMessage, e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies that JVM startup behavior matches our expectations when type
+     * of newly started VM is the same as the type of current.
+     *
+     * @param expectedMessages an array of patterns that should occur
+     *                         in JVM output. If {@code null} then
+     *                         JVM output could be empty.
+     * @param unexpectedMessages an array of patterns that should not
+     *                           occur in JVM output. If {@code null} then
+     *                           JVM output could be empty.
+     * @param exitErrorMessage Message that will be shown if exit value is not
+     *                           as expected.
+     * @param wrongWarningMessage message that will be shown if warning
+     *                           messages are not as expected.
+     * @param exitCode expected exit code.
+     * @param options options that should be passed to VM in addition to mode
+     *                flag.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifySameJVMStartup(String expectedMessages[],
+            String unexpectedMessages[], String exitErrorMessage,
+            String wrongWarningMessage, ExitCode exitCode, String... options)
+            throws Throwable {
+        List<String> finalOptions = new ArrayList<>();
+        finalOptions.add(CommandLineOptionTest.getVMTypeOption());
+        Collections.addAll(finalOptions, options);
+
+        CommandLineOptionTest.verifyJVMStartup(expectedMessages,
+                unexpectedMessages, exitErrorMessage,
+                wrongWarningMessage, exitCode, false,
+                finalOptions.toArray(new String[finalOptions.size()]));
+    }
+
+    /**
+     * Verifies that value of specified JVM option is the same as
+     * expected value.
+     * This method filter out option with {@code optionName}
+     * name from test java options.
+     *
+     * @param optionName a name of tested option.
+     * @param expectedValue expected value of tested option.
+     * @param optionErrorString message will be shown if option value is not as
+     *                         expected.
+     * @param additionalVMOpts additional options that should be
+     *                         passed to JVM.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyOptionValue(String optionName,
+            String expectedValue, String optionErrorString,
+            String... additionalVMOpts) throws Throwable {
+        verifyOptionValue(optionName, expectedValue, optionErrorString,
+                true, additionalVMOpts);
+    }
+
+    /**
+     * Verifies that value of specified JVM option is the same as
+     * expected value.
+     * This method filter out option with {@code optionName}
+     * name from test java options.
+     *
+     * @param optionName a name of tested option.
+     * @param expectedValue expected value of tested option.
+     * @param addTestVmOptions if {@code true}, then test VM options
+     *                         will be used.
+     * @param optionErrorString message will be shown if option value is not as
+     *                         expected.
+     * @param additionalVMOpts additional options that should be
+     *                         passed to JVM.
+     * @throws Throwable if verification fails or some other issues
+     *                          occur.
+     */
+    public static void verifyOptionValue(String optionName,
+            String expectedValue, String optionErrorString,
+            boolean addTestVmOptions, String... additionalVMOpts)
+                    throws Throwable {
+        List<String> vmOpts = new ArrayList<>();
+
+        if (addTestVmOptions) {
+            Collections.addAll(vmOpts,
+                               Utils.getFilteredTestJavaOpts(optionName));
+        }
+        Collections.addAll(vmOpts, additionalVMOpts);
+        Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version");
+
+        ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
+                vmOpts.toArray(new String[vmOpts.size()]));
+
+        OutputAnalyzer outputAnalyzer
+                = new OutputAnalyzer(processBuilder.start());
+
+        try {
+            outputAnalyzer.shouldHaveExitValue(0);
+        } catch (RuntimeException e) {
+            String errorMessage = String.format(
+                    "JVM should start with option '%s' without errors.",
+                    optionName);
+            throw new AssertionError(errorMessage, e);
+        }
+        verifyOptionValue(optionName, expectedValue, optionErrorString,
+                outputAnalyzer);
+    }
+
+    /**
+     * Verifies that value of specified JVM option is the same as
+     * expected value.
+     *
+     * @param optionName a name of tested option.
+     * @param expectedValue expected value of tested option.
+     * @param optionErrorString message will be shown if option value is not
+     *                          as expected.
+     * @param outputAnalyzer OutputAnalyzer instance
+     * @throws AssertionError if verification fails
+     */
+    public static void verifyOptionValue(String optionName,
+            String expectedValue, String optionErrorString,
+            OutputAnalyzer outputAnalyzer) {
+        try {
+            outputAnalyzer.shouldMatch(String.format(
+                    CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT,
+                    optionName, expectedValue));
+        } catch (RuntimeException e) {
+            String errorMessage = String.format(
+                    "Option '%s' is expected to have '%s' value%n%s",
+                    optionName, expectedValue,
+                    optionErrorString);
+            throw new AssertionError(errorMessage, e);
+        }
+    }
+
+    /**
+     * Start VM with given options and values.
+     * Generates command line option flags from
+     * {@code optionNames} and {@code optionValues}.
+     *
+     * @param optionNames names of options to pass in
+     * @param optionValues  values of option
+     * @param additionalVMOpts additional options that should be
+     *                         passed to JVM.
+     * @return output from vm process
+     */
+    public static OutputAnalyzer startVMWithOptions(String[] optionNames,
+            String[] optionValues,
+            String... additionalVMOpts) throws Throwable {
+        List<String> vmOpts = new ArrayList<>();
+        if (optionNames == null || optionValues == null || optionNames.length != optionValues.length) {
+            throw new IllegalArgumentException("optionNames and/or optionValues");
+        }
+
+        for (int i = 0; i < optionNames.length; i++) {
+          vmOpts.add(prepareFlag(optionNames[i], optionValues[i]));
+        }
+        Collections.addAll(vmOpts, additionalVMOpts);
+        Collections.addAll(vmOpts, "-version");
+
+        ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
+                vmOpts.toArray(new String[vmOpts.size()]));
+
+        return new OutputAnalyzer(processBuilder.start());
+    }
+
+    /**
+     * Verifies from the output that values of specified JVM options were the same as
+     * expected values.
+     *
+     * @param outputAnalyzer search output for expect options and values.
+     * @param optionNames names of tested options.
+     * @param expectedValues expected values of tested options.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyOptionValuesFromOutput(OutputAnalyzer outputAnalyzer,
+            String[] optionNames,
+            String[] expectedValues) throws Throwable {
+        outputAnalyzer.shouldHaveExitValue(0);
+        for (int i = 0; i < optionNames.length; i++) {
+          outputAnalyzer.shouldMatch(String.format(
+                CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT,
+                optionNames[i], expectedValues[i]));
+        }
+    }
+
+   /**
+     * Verifies that value of specified JVM options are the same as
+     * expected values.
+     * Generates command line option flags from
+     * {@code optionNames} and {@code expectedValues}.
+     *
+     * @param optionNames names of tested options.
+     * @param expectedValues expected values of tested options.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyOptionValues(String[] optionNames,
+            String[] expectedValues) throws Throwable {
+       OutputAnalyzer outputAnalyzer = startVMWithOptions(optionNames, expectedValues, "-XX:+PrintFlagsFinal");
+       verifyOptionValuesFromOutput(outputAnalyzer, optionNames, expectedValues);
+    }
+
+    /**
+     * Verifies that value of specified JVM when type of newly started VM
+     * is the same as the type of current.
+     * This method filter out option with {@code optionName}
+     * name from test java options.
+     * Only mode flag will be passed to VM in addition to
+     * {@code additionalVMOpts}
+     *
+     * @param optionName name of tested option.
+     * @param expectedValue expected value of tested option.
+     * @param optionErrorString message to show if option has another value
+     * @param additionalVMOpts additional options that should be
+     *                         passed to JVM.
+     * @throws Throwable if verification fails or some other issues occur.
+     */
+    public static void verifyOptionValueForSameVM(String optionName,
+            String expectedValue, String optionErrorString,
+            String... additionalVMOpts) throws Throwable {
+        List<String> finalOptions = new ArrayList<>();
+        finalOptions.add(CommandLineOptionTest.getVMTypeOption());
+        Collections.addAll(finalOptions, additionalVMOpts);
+
+        CommandLineOptionTest.verifyOptionValue(optionName, expectedValue,
+                optionErrorString, false,
+                finalOptions.toArray(new String[finalOptions.size()]));
+    }
+
+    /**
+     * Prepares boolean command line flag with name {@code name} according
+     * to it's {@code value}.
+     *
+     * @param name the name of option to be prepared
+     * @param value the value of option
+     * @return prepared command line flag
+     */
+    public static String prepareBooleanFlag(String name, boolean value) {
+        return String.format("-XX:%c%s", (value ? '+' : '-'), name);
+    }
+
+    /**
+     * Prepares numeric command line flag with name {@code name} by setting
+     * it's value to {@code value}.
+     *
+     * @param name the name of option to be prepared
+     * @param value the value of option
+     * @return prepared command line flag
+     */
+    public static String prepareNumericFlag(String name, Number value) {
+        return String.format("-XX:%s=%s", name, value.toString());
+    }
+
+    /**
+     * Prepares generic command line flag with name {@code name} by setting
+     * it's value to {@code value}.
+     *
+     * @param name the name of option to be prepared
+     * @param value the value of option ("+" or "-" can be used instead of "true" or "false")
+     * @return prepared command line flag
+     */
+    public static String prepareFlag(String name, String value) {
+        if (value.equals("+") || value.equalsIgnoreCase("true")) {
+          return "-XX:+" + name;
+      } else if (value.equals("-") || value.equalsIgnoreCase("false")) {
+        return "-XX:-" + name;
+      } else {
+        return "-XX:" + name + "=" + value;
+      }
+    }
+
+    /**
+     * Returns message that should occur in VM output if option
+     * {@code optionName} if unrecognized.
+     *
+     * @param optionName the name of option for which message should be returned
+     * @return message saying that option {@code optionName} is unrecognized
+     */
+    public static String getUnrecognizedOptionErrorMessage(String optionName) {
+        return String.format(
+                CommandLineOptionTest.UNRECOGNIZED_OPTION_ERROR_FORMAT,
+                optionName);
+    }
+
+    /**
+     * Returns message that should occur in VM output if option
+     * {@code optionName} is experimental and
+     * -XX:+UnlockExperimentalVMOptions was not passed to VM.
+     *
+     * @param optionName the name of option for which message should be returned
+     * @return message saying that option {@code optionName} is experimental
+     */
+    public static String getExperimentalOptionErrorMessage(String optionName) {
+        return String.format(
+                CommandLineOptionTest.EXPERIMENTAL_OPTION_ERROR_FORMAT,
+                optionName);
+    }
+
+    /**
+     * Returns message that should occur in VM output if option
+     * {@code optionName} is diagnostic and -XX:+UnlockDiagnosticVMOptions
+     * was not passed to VM.
+     *
+     * @param optionName the name of option for which message should be returned
+     * @return message saying that option {@code optionName} is diganostic
+     */
+    public static String getDiagnosticOptionErrorMessage(String optionName) {
+        return String.format(
+                CommandLineOptionTest.DIAGNOSTIC_OPTION_ERROR_FORMAT,
+                optionName);
+    }
+
+    /**
+     * @return option required to start a new VM with the same type as current.
+     * @throws RuntimeException when VM type is unknown.
+     */
+    private static String getVMTypeOption() {
+        if (Platform.isServer()) {
+            return "-server";
+        } else if (Platform.isClient()) {
+            return "-client";
+        } else if (Platform.isMinimal()) {
+            return "-minimal";
+        } else if (Platform.isGraal()) {
+            return "-graal";
+        }
+        throw new RuntimeException("Unknown VM mode.");
+    }
+
+    private final BooleanSupplier predicate;
+
+    /**
+     * Constructs new CommandLineOptionTest that will be executed only if
+     * predicate {@code predicate} return {@code true}.
+     * @param predicate a predicate responsible for test's preconditions check.
+     */
+    public CommandLineOptionTest(BooleanSupplier predicate) {
+        this.predicate = predicate;
+    }
+
+    /**
+     * Runs command line option test.
+     */
+    public final void test() throws Throwable {
+        if (predicate.getAsBoolean()) {
+            runTestCases();
+        }
+    }
+
+    /**
+     * @throws Throwable if some issue happened during test cases execution.
+     */
+    protected abstract void runTestCases() throws Throwable;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/predicate/AndPredicate.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.cli.predicate;
+
+import java.util.function.BooleanSupplier;
+
+public class AndPredicate implements BooleanSupplier {
+    private final BooleanSupplier a;
+    private final BooleanSupplier b;
+
+    public AndPredicate(BooleanSupplier a, BooleanSupplier b) {
+        this.a = a;
+        this.b = b;
+    }
+
+    @Override
+    public boolean getAsBoolean() {
+        return a.getAsBoolean() && b.getAsBoolean();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/predicate/CPUSpecificPredicate.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.cli.predicate;
+
+import jdk.test.lib.Platform;
+import sun.hotspot.cpuinfo.CPUInfo;
+
+import java.util.function.BooleanSupplier;
+
+public class CPUSpecificPredicate implements BooleanSupplier {
+    private final String cpuArchPattern;
+    private final String supportedCPUFeatures[];
+    private final String unsupportedCPUFeatures[];
+
+    public CPUSpecificPredicate(String cpuArchPattern,
+            String supportedCPUFeatures[],
+            String unsupportedCPUFeatures[]) {
+        this.cpuArchPattern = cpuArchPattern;
+        this.supportedCPUFeatures = supportedCPUFeatures;
+        this.unsupportedCPUFeatures = unsupportedCPUFeatures;
+    }
+
+    @Override
+    public boolean getAsBoolean() {
+        if (!Platform.getOsArch().matches(cpuArchPattern)) {
+            System.out.println("CPU arch " + Platform.getOsArch() + " does not match " + cpuArchPattern);
+            return false;
+        }
+
+        if (supportedCPUFeatures != null) {
+            for (String feature : supportedCPUFeatures) {
+                if (!CPUInfo.hasFeature(feature)) {
+                    System.out.println("CPU does not support " + feature
+                            + " feature");
+                    return false;
+                }
+            }
+        }
+
+        if (unsupportedCPUFeatures != null) {
+            for (String feature : unsupportedCPUFeatures) {
+                if (CPUInfo.hasFeature(feature)) {
+                    System.out.println("CPU support " + feature + " feature");
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/predicate/NotPredicate.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package jdk.test.lib.cli.predicate;
+
+import java.util.function.BooleanSupplier;
+
+public class NotPredicate implements BooleanSupplier {
+    private final BooleanSupplier s;
+
+    public NotPredicate(BooleanSupplier s) {
+        this.s = s;
+    }
+
+    @Override
+    public boolean getAsBoolean() {
+        return !s.getAsBoolean();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/cli/predicate/OrPredicate.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package jdk.test.lib.cli.predicate;
+
+import java.util.function.BooleanSupplier;
+
+public class OrPredicate implements BooleanSupplier {
+    private final BooleanSupplier a;
+    private final BooleanSupplier b;
+
+    public OrPredicate(BooleanSupplier a, BooleanSupplier b) {
+        this.a = a;
+        this.b = b;
+    }
+
+    @Override
+    public boolean getAsBoolean() {
+        return a.getAsBoolean() || b.getAsBoolean();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/CommandExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+/**
+ * Abstract base class for Diagnostic Command executors
+ */
+public abstract class CommandExecutor {
+
+    /**
+     * Execute a diagnostic command
+     *
+     * @param cmd The diagnostic command to execute
+     * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command
+     * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the
+     *          Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in
+     *          stderr, regardless of the specific executor used.
+     */
+    public final OutputAnalyzer execute(String cmd) throws CommandExecutorException {
+        return execute(cmd, false);
+    }
+
+    /**
+     * Execute a diagnostic command
+     *
+     * @param cmd The diagnostic command to execute
+     * @param silent Do not print the command output
+     * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command
+     * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the
+     *          Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in
+     *          stderr, regardless of the specific executor used.
+     */
+    public final OutputAnalyzer execute(String cmd, boolean silent) throws CommandExecutorException {
+        if (!silent) {
+            System.out.printf("Running DCMD '%s' through '%s'%n", cmd, this.getClass().getSimpleName());
+        }
+
+        OutputAnalyzer oa = executeImpl(cmd);
+
+        if (!silent) {
+            System.out.println("---------------- stdout ----------------");
+            System.out.println(oa.getStdout());
+            System.out.println("---------------- stderr ----------------");
+            System.out.println(oa.getStderr());
+            System.out.println("----------------------------------------");
+            System.out.println();
+        }
+        return oa;
+    }
+
+    protected abstract OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/CommandExecutorException.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+/**
+ * CommandExecutorException encapsulates exceptions thrown (on the "calling side") from the execution of Diagnostic
+ * Commands
+ */
+public class CommandExecutorException extends RuntimeException {
+    private static final long serialVersionUID = -7039597746579144280L;
+
+    public CommandExecutorException(String message, Throwable e) {
+        super(message, e);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/FileJcmdExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by pid) using the jcmd tool and its ability to read
+ *          Diagnostic Commands from a file.
+ */
+public class FileJcmdExecutor extends PidJcmdExecutor {
+
+    /**
+     * Instantiates a new FileJcmdExecutor targeting the current VM
+     */
+    public FileJcmdExecutor() {
+        super();
+    }
+
+    /**
+     * Instantiates a new FileJcmdExecutor targeting the VM indicated by the given pid
+     *
+     * @param target Pid of the target VM
+     */
+    public FileJcmdExecutor(String target) {
+        super(target);
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        File cmdFile = createTempFile();
+        writeCommandToTemporaryFile(cmd, cmdFile);
+
+        return Arrays.asList(jcmdBinary, Long.toString(pid),
+                "-f", cmdFile.getAbsolutePath());
+    }
+
+    private void writeCommandToTemporaryFile(String cmd, File cmdFile) {
+        try (PrintWriter pw = new PrintWriter(cmdFile)) {
+            pw.println(cmd);
+        } catch (IOException e) {
+            String message = "Could not write to file: " + cmdFile.getAbsolutePath();
+            throw new CommandExecutorException(message, e);
+        }
+    }
+
+    private File createTempFile() {
+        try {
+            File cmdFile = File.createTempFile("input", "jcmd");
+            cmdFile.deleteOnExit();
+            return cmdFile;
+        } catch (IOException e) {
+            throw new CommandExecutorException("Could not create temporary file", e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/JMXExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+import javax.management.*;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.management.ManagementFactory;
+
+import java.util.HashMap;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by a host/port combination or a full JMX Service URL) using
+ * the JMX interface. If the target is not the current VM, the JMX Remote interface must be enabled beforehand.
+ */
+public class JMXExecutor extends CommandExecutor {
+
+    private final MBeanServerConnection mbs;
+
+    /**
+     * Instantiates a new JMXExecutor targeting the current VM
+     */
+    public JMXExecutor() {
+        super();
+        mbs = ManagementFactory.getPlatformMBeanServer();
+    }
+
+    /**
+     * Instantiates a new JMXExecutor targeting the VM indicated by the given host/port combination or a full JMX
+     * Service URL
+     *
+     * @param target a host/port combination on the format "host:port" or a full JMX Service URL of the target VM
+     */
+    public JMXExecutor(String target) {
+        String urlStr;
+
+        if (target.matches("^\\w[\\w\\-]*(\\.[\\w\\-]+)*:\\d+$")) {
+            /* Matches "hostname:port" */
+            urlStr = String.format("service:jmx:rmi:///jndi/rmi://%s/jmxrmi", target);
+        } else if (target.startsWith("service:")) {
+            urlStr = target;
+        } else {
+            throw new IllegalArgumentException("Could not recognize target string: " + target);
+        }
+
+        try {
+            JMXServiceURL url = new JMXServiceURL(urlStr);
+            JMXConnector c = JMXConnectorFactory.connect(url, new HashMap<>());
+            mbs = c.getMBeanServerConnection();
+        } catch (IOException e) {
+            throw new CommandExecutorException("Could not initiate connection to target: " + target, e);
+        }
+    }
+
+    protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException {
+        String stdout = "";
+        String stderr = "";
+
+        String[] cmdParts = cmd.split(" ", 2);
+        String operation = commandToMethodName(cmdParts[0]);
+        Object[] dcmdArgs = produceArguments(cmdParts);
+        String[] signature = {String[].class.getName()};
+
+        ObjectName beanName = getMBeanName();
+
+        try {
+            stdout = (String) mbs.invoke(beanName, operation, dcmdArgs, signature);
+        }
+
+        /* Failures on the "local" side, the one invoking the command. */
+        catch (ReflectionException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof NoSuchMethodException) {
+                /* We want JMXExecutor to match the behavior of the other CommandExecutors */
+                String message = "Unknown diagnostic command: " + operation;
+                stderr = exceptionTraceAsString(new IllegalArgumentException(message, e));
+            } else {
+                rethrowExecutorException(operation, dcmdArgs, e);
+            }
+        }
+
+        /* Failures on the "local" side, the one invoking the command. */
+        catch (InstanceNotFoundException | IOException e) {
+            rethrowExecutorException(operation, dcmdArgs, e);
+        }
+
+        /* Failures on the remote side, the one executing the invoked command. */
+        catch (MBeanException e) {
+            stdout = exceptionTraceAsString(e);
+        }
+
+        return new OutputAnalyzer(stdout, stderr);
+    }
+
+    private void rethrowExecutorException(String operation, Object[] dcmdArgs,
+                                          Exception e) throws CommandExecutorException {
+        String message = String.format("Could not invoke: %s %s", operation,
+                String.join(" ", (String[]) dcmdArgs[0]));
+        throw new CommandExecutorException(message, e);
+    }
+
+    private ObjectName getMBeanName() throws CommandExecutorException {
+        String MBeanName = "com.sun.management:type=DiagnosticCommand";
+
+        try {
+            return new ObjectName(MBeanName);
+        } catch (MalformedObjectNameException e) {
+            String message = "MBean not found: " + MBeanName;
+            throw new CommandExecutorException(message, e);
+        }
+    }
+
+    private Object[] produceArguments(String[] cmdParts) {
+        Object[] dcmdArgs = {new String[0]}; /* Default: No arguments */
+
+        if (cmdParts.length == 2) {
+            dcmdArgs[0] = cmdParts[1].split(" ");
+        }
+        return dcmdArgs;
+    }
+
+    /**
+     * Convert from diagnostic command to MBean method name
+     *
+     * Examples:
+     * help            --> help
+     * VM.version      --> vmVersion
+     * VM.command_line --> vmCommandLine
+     */
+    private static String commandToMethodName(String cmd) {
+        String operation = "";
+        boolean up = false; /* First letter is to be lower case */
+
+        /*
+         * If a '.' or '_' is encountered it is not copied,
+         * instead the next character will be converted to upper case
+         */
+        for (char c : cmd.toCharArray()) {
+            if (('.' == c) || ('_' == c)) {
+                up = true;
+            } else if (up) {
+                operation = operation.concat(Character.toString(c).toUpperCase());
+                up = false;
+            } else {
+                operation = operation.concat(Character.toString(c).toLowerCase());
+            }
+        }
+
+        return operation;
+    }
+
+    private static String exceptionTraceAsString(Throwable cause) {
+        StringWriter sw = new StringWriter();
+        cause.printStackTrace(new PrintWriter(sw));
+        return sw.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/JcmdExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+import java.util.List;
+
+/**
+ * Base class for Diagnostic Command Executors using the jcmd tool
+ */
+public abstract class JcmdExecutor extends CommandExecutor {
+    protected String jcmdBinary;
+
+    protected abstract List<String> createCommandLine(String cmd) throws CommandExecutorException;
+
+    protected JcmdExecutor() {
+        jcmdBinary = JDKToolFinder.getJDKTool("jcmd");
+    }
+
+    protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException {
+        List<String> commandLine = createCommandLine(cmd);
+
+        try {
+            System.out.printf("Executing command '%s'%n", commandLine);
+            OutputAnalyzer output = ProcessTools.executeProcess(new ProcessBuilder(commandLine));
+            System.out.printf("Command returned with exit code %d%n", output.getExitValue());
+
+            return output;
+        } catch (Exception e) {
+            String message = String.format("Caught exception while executing '%s'", commandLine);
+            throw new CommandExecutorException(message, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/MainClassJcmdExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by main class) using the jcmd tool
+ */
+public class MainClassJcmdExecutor extends JcmdExecutor {
+    private final String mainClass;
+
+    /**
+     * Instantiates a new MainClassJcmdExecutor targeting the current VM
+     */
+    public MainClassJcmdExecutor() {
+        super();
+        mainClass = System.getProperty("sun.java.command").split(" ")[0];
+    }
+
+    /**
+     * Instantiates a new MainClassJcmdExecutor targeting the VM indicated by the given main class
+     *
+     * @param target Main class of the target VM
+     */
+    public MainClassJcmdExecutor(String target) {
+        super();
+        mainClass = target;
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        return Arrays.asList(jcmdBinary, mainClass, cmd);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/dcmd/PidJcmdExecutor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.dcmd;
+
+import jdk.test.lib.process.ProcessTools;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by pid) using the jcmd tool
+ */
+public class PidJcmdExecutor extends JcmdExecutor {
+    protected final long pid;
+
+    /**
+     * Instantiates a new PidJcmdExecutor targeting the current VM
+     */
+    public PidJcmdExecutor() {
+        super();
+        try {
+            pid = ProcessTools.getProcessId();
+        } catch (Exception e) {
+            throw new CommandExecutorException("Could not determine own pid", e);
+        }
+    }
+
+    /**
+     * Instantiates a new PidJcmdExecutor targeting the VM indicated by the given pid
+     *
+     * @param target Pid of the target VM
+     */
+    public PidJcmdExecutor(String target) {
+        super();
+        pid = Long.valueOf(target);
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        return Arrays.asList(jcmdBinary, Long.toString(pid), cmd);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/HprofParser.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.hprof;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+import jdk.test.lib.hprof.model.Snapshot;
+import jdk.test.lib.hprof.parser.Reader;
+
+/**
+ * Helper class to parse a java heap dump file.
+ */
+public class HprofParser {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            System.out.println("No arguments supplied");
+        }
+        File dump = new File(args[0]);
+        if (!dump.exists() || !dump.isFile()) {
+            throw new RuntimeException("The dump file does not exist or not a file");
+        }
+        parse(dump);
+    }
+
+    /**
+     * @see #parse(File, boolean, boolean, boolean)
+     */
+    public static File parse(File dump) throws Exception {
+        return parse(dump, false, true, true);
+    }
+
+    /**
+     * @see #parse(File, boolean, boolean, boolean)
+     */
+    public static File parseWithDebugInfo(File dump) throws Exception {
+        return parse(dump, true, true, true);
+    }
+
+    /**
+     * Parse a java heap dump file
+     *
+     * @param dump Heap dump file to parse
+     * @param debug Turn on/off debug file parsing
+     * @param callStack Turn on/off tracking of object allocation call stack
+     * @param calculateRefs Turn on/off tracking object allocation call stack
+     * @throws Exception
+     * @return File containing output from the parser
+     */
+    public static File parse(File dump, boolean debug, boolean callStack, boolean calculateRefs) throws Exception {
+        File out = new File("hprof." + System.currentTimeMillis() + ".out");
+        if (out.exists()) {
+            out.delete();
+        }
+
+        PrintStream psSystemOut = System.out;
+        try (PrintStream psHprof = new PrintStream(new BufferedOutputStream(new FileOutputStream(out.getAbsolutePath())))) {
+            System.setOut(psHprof);
+
+            int debugLevel = debug ? 2 : 0;
+            try (Snapshot snapshot = Reader.readFile(dump.getAbsolutePath(), callStack, debugLevel)) {
+                System.out.println("Snapshot read, resolving...");
+                snapshot.resolve(calculateRefs);
+                System.out.println("Snapshot resolved.");
+            }
+       } finally {
+           System.setOut(psSystemOut);
+       }
+
+        return out;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/README	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,13 @@
+The jhat tool has been removed. jhat hprof file parser/validator
+are needed for tests. The old packages for jhat were moved here:
+com.sun.tools.hat.internal.model -> jdk.test.lib.hprof.model
+com.sun.tools.hat.internal.parser -> jdk.test.lib.hprof.parser
+com.sun.tools.hat.internal.util -> jdk.test.lib.hprof.util
+ 
+jhat was added in JDK 6 and its original implementation was from 
+java.net HAT project [1]. jhat is an experimental, unsupported tool. 
+There hasn't been much update to jhat tool in the JDK. In addition, 
+there are several better heap dump visualizer/analyzer emerged since 
+JDK 5/6 serviceability support.
+
+[1] https://java.net/projects/hat
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/AbstractJavaHeapObjectVisitor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * A visitor for a JavaThing.  @see JavaObject#visitReferencedObjects()
+ *
+ */
+
+
+abstract public class AbstractJavaHeapObjectVisitor
+                implements JavaHeapObjectVisitor {
+    abstract public void visit(JavaHeapObject other);
+
+    /**
+     * Should the given field be excluded from the set of things visited?
+     * @return true if it should.
+     */
+    public boolean exclude(JavaClass clazz, JavaField f) {
+        return false;
+    }
+
+    /**
+     * @return true iff exclude might ever return true
+     */
+    public boolean mightExclude() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/ArrayTypeCodes.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Primitive array type codes as defined by VM specification.
+ *
+ */
+public interface ArrayTypeCodes {
+    // Typecodes for array elements.
+    // Refer to newarray instruction in VM Spec.
+    public static final int T_BOOLEAN = 4;
+    public static final int T_CHAR    = 5;
+    public static final int T_FLOAT   = 6;
+    public static final int T_DOUBLE  = 7;
+    public static final int T_BYTE    = 8;
+    public static final int T_SHORT   = 9;
+    public static final int T_INT     = 10;
+    public static final int T_LONG    = 11;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/HackJavaValue.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * This is used to represent values that the program doesn't really understand.
+ * This includes the null vlaue, and unresolved references (which shouldn't
+ * happen in well-formed hprof files).
+ *
+ *
+ * @author      Bill Foote
+ */
+
+
+
+
+public class HackJavaValue extends JavaValue {
+
+    private String value;
+    private int size;
+
+    public HackJavaValue(String value, int size) {
+        this.value = value;
+        this.size = size;
+    }
+
+    public String toString() {
+        return value;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaBoolean.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a boolean (i.e. a boolean field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaBoolean extends JavaValue {
+
+    boolean value;
+
+    public JavaBoolean(boolean value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return "" + value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaByte.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents an byte (i.e. a byte field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaByte extends JavaValue {
+
+    byte value;
+
+    public JavaByte(byte value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return "0x" + Integer.toString(((int) value) & 0xff, 16);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaChar.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a char (i.e. a char field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaChar extends JavaValue {
+
+    char value;
+
+    public JavaChar(char value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return "" + value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaClass.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import jdk.test.lib.hprof.util.CompositeEnumeration;
+import jdk.test.lib.hprof.parser.ReadBuffer;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaClass extends JavaHeapObject {
+    // my id
+    private long id;
+    // my name
+    private String name;
+
+    // These are JavaObjectRef before resolve
+    private JavaThing superclass;
+    private JavaThing loader;
+    private JavaThing signers;
+    private JavaThing protectionDomain;
+
+    // non-static fields
+    private JavaField[] fields;
+    // static fields
+    private JavaStatic[] statics;
+
+    private static final JavaClass[] EMPTY_CLASS_ARRAY = new JavaClass[0];
+    // my subclasses
+    private JavaClass[] subclasses = EMPTY_CLASS_ARRAY;
+
+    // my instances
+    private Vector<JavaHeapObject> instances = new Vector<JavaHeapObject>();
+
+    // Who I belong to.  Set on resolve.
+    private Snapshot mySnapshot;
+
+    // Size of an instance, including VM overhead
+    private int instanceSize;
+    // Total number of fields including inherited ones
+    private int totalNumFields;
+
+
+    public JavaClass(long id, String name, long superclassId, long loaderId,
+                     long signersId, long protDomainId,
+                     JavaField[] fields, JavaStatic[] statics,
+                     int instanceSize) {
+        this.id = id;
+        this.name = name;
+        this.superclass = new JavaObjectRef(superclassId);
+        this.loader = new JavaObjectRef(loaderId);
+        this.signers = new JavaObjectRef(signersId);
+        this.protectionDomain = new JavaObjectRef(protDomainId);
+        this.fields = fields;
+        this.statics = statics;
+        this.instanceSize = instanceSize;
+    }
+
+    public JavaClass(String name, long superclassId, long loaderId,
+                     long signersId, long protDomainId,
+                     JavaField[] fields, JavaStatic[] statics,
+                     int instanceSize) {
+        this(-1L, name, superclassId, loaderId, signersId,
+             protDomainId, fields, statics, instanceSize);
+    }
+
+    public final JavaClass getClazz() {
+        return mySnapshot.getJavaLangClass();
+    }
+
+    public final int getIdentifierSize() {
+        return mySnapshot.getIdentifierSize();
+    }
+
+    public final int getMinimumObjectSize() {
+        return mySnapshot.getMinimumObjectSize();
+    }
+
+    public void resolve(Snapshot snapshot) {
+        if (mySnapshot != null) {
+            return;
+        }
+        mySnapshot = snapshot;
+        resolveSuperclass(snapshot);
+        if (superclass != null) {
+            ((JavaClass) superclass).addSubclass(this);
+        }
+
+        loader  = loader.dereference(snapshot, null);
+        signers  = signers.dereference(snapshot, null);
+        protectionDomain  = protectionDomain.dereference(snapshot, null);
+
+        for (int i = 0; i < statics.length; i++) {
+            statics[i].resolve(this, snapshot);
+        }
+        snapshot.getJavaLangClass().addInstance(this);
+        super.resolve(snapshot);
+        return;
+    }
+
+    /**
+     * Resolve our superclass.  This might be called well before
+     * all instances are available (like when reading deferred
+     * instances in a 1.2 dump file :-)  Calling this is sufficient
+     * to be able to explore this class' fields.
+     */
+    public void resolveSuperclass(Snapshot snapshot) {
+        if (superclass == null) {
+            // We must be java.lang.Object, so we have no superclass.
+        } else {
+            totalNumFields = fields.length;
+            superclass = superclass.dereference(snapshot, null);
+            if (superclass == snapshot.getNullThing()) {
+                superclass = null;
+            } else {
+                try {
+                    JavaClass sc = (JavaClass) superclass;
+                    sc.resolveSuperclass(snapshot);
+                    totalNumFields += sc.totalNumFields;
+                } catch (ClassCastException ex) {
+                    System.out.println("Warning!  Superclass of " + name + " is " + superclass);
+                    superclass = null;
+                }
+            }
+        }
+    }
+
+    public boolean isString() {
+        return mySnapshot.getJavaLangString() == this;
+    }
+
+    public boolean isClassLoader() {
+        return mySnapshot.getJavaLangClassLoader().isAssignableFrom(this);
+    }
+
+    /**
+     * Get a numbered field from this class
+     */
+    public JavaField getField(int i) {
+        if (i < 0 || i >= fields.length) {
+            throw new Error("No field " + i + " for " + name);
+        }
+        return fields[i];
+    }
+
+    /**
+     * Get the total number of fields that are part of an instance of
+     * this class.  That is, include superclasses.
+     */
+    public int getNumFieldsForInstance() {
+        return totalNumFields;
+    }
+
+    /**
+     * Get a numbered field from all the fields that are part of instance
+     * of this class.  That is, include superclasses.
+     */
+    public JavaField getFieldForInstance(int i) {
+        if (superclass != null) {
+            JavaClass sc = (JavaClass) superclass;
+            if (i < sc.totalNumFields) {
+                return sc.getFieldForInstance(i);
+            }
+            i -= sc.totalNumFields;
+        }
+        return getField(i);
+    }
+
+    /**
+     * Get the class responsible for field i, where i is a field number that
+     * could be passed into getFieldForInstance.
+     *
+     * @see JavaClass.getFieldForInstance()
+     */
+    public JavaClass getClassForField(int i) {
+        if (superclass != null) {
+            JavaClass sc = (JavaClass) superclass;
+            if (i < sc.totalNumFields) {
+                return sc.getClassForField(i);
+            }
+        }
+        return this;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isArray() {
+        return name.indexOf('[') != -1;
+    }
+
+    public Enumeration<JavaHeapObject> getInstances(boolean includeSubclasses) {
+        if (includeSubclasses) {
+            Enumeration<JavaHeapObject> res = instances.elements();
+            for (int i = 0; i < subclasses.length; i++) {
+                res = new CompositeEnumeration(res,
+                              subclasses[i].getInstances(true));
+            }
+            return res;
+        } else {
+            return instances.elements();
+        }
+    }
+
+    /**
+     * @return a count of the instances of this class
+     */
+    public int getInstancesCount(boolean includeSubclasses) {
+        int result = instances.size();
+        if (includeSubclasses) {
+            for (int i = 0; i < subclasses.length; i++) {
+                result += subclasses[i].getInstancesCount(includeSubclasses);
+            }
+        }
+        return result;
+    }
+
+    public JavaClass[] getSubclasses() {
+        return subclasses;
+    }
+
+    /**
+     * This can only safely be called after resolve()
+     */
+    public JavaClass getSuperclass() {
+        return (JavaClass) superclass;
+    }
+
+    /**
+     * This can only safely be called after resolve()
+     */
+    public JavaThing getLoader() {
+        return loader;
+    }
+
+    /**
+     * This can only safely be called after resolve()
+     */
+    public boolean isBootstrap() {
+        return loader == mySnapshot.getNullThing();
+    }
+
+    /**
+     * This can only safely be called after resolve()
+     */
+    public JavaThing getSigners() {
+        return signers;
+    }
+
+    /**
+     * This can only safely be called after resolve()
+     */
+    public JavaThing getProtectionDomain() {
+        return protectionDomain;
+    }
+
+    public JavaField[] getFields() {
+        return fields;
+    }
+
+    /**
+     * Includes superclass fields
+     */
+    public JavaField[] getFieldsForInstance() {
+        Vector<JavaField> v = new Vector<JavaField>();
+        addFields(v);
+        JavaField[] result = new JavaField[v.size()];
+        for (int i = 0; i < v.size(); i++) {
+            result[i] =  v.elementAt(i);
+        }
+        return result;
+    }
+
+
+    public JavaStatic[] getStatics() {
+        return statics;
+    }
+
+    // returns value of static field of given name
+    public JavaThing getStaticField(String name) {
+        for (int i = 0; i < statics.length; i++) {
+            JavaStatic s = statics[i];
+            if (s.getField().getName().equals(name)) {
+                return s.getValue();
+            }
+        }
+        return null;
+    }
+
+    public String toString() {
+        return "class " + name;
+    }
+
+    public int compareTo(JavaThing other) {
+        if (other instanceof JavaClass) {
+            return name.compareTo(((JavaClass) other).name);
+        }
+        return super.compareTo(other);
+    }
+
+
+    /**
+     * @return true iff a variable of type this is assignable from an instance
+     *          of other
+     */
+    public boolean isAssignableFrom(JavaClass other) {
+        if (this == other) {
+            return true;
+        } else if (other == null) {
+            return false;
+        } else {
+            return isAssignableFrom((JavaClass) other.superclass);
+            // Trivial tail recursion:  I have faith in javac.
+        }
+    }
+
+    /**
+     * Describe the reference that this thing has to target.  This will only
+     * be called if target is in the array returned by getChildrenForRootset.
+     */
+     public String describeReferenceTo(JavaThing target, Snapshot ss) {
+        for (int i = 0; i < statics.length; i++) {
+            JavaField f = statics[i].getField();
+            if (f.hasId()) {
+                JavaThing other = statics[i].getValue();
+                if (other == target) {
+                    return "static field " + f.getName();
+                }
+            }
+        }
+        return super.describeReferenceTo(target, ss);
+    }
+
+    /**
+     * @return the size of an instance of this class.  Gives 0 for an array
+     *          type.
+     */
+    public int getInstanceSize() {
+        return instanceSize + mySnapshot.getMinimumObjectSize();
+    }
+
+
+    /**
+     * @return The size of all instances of this class.  Correctly handles
+     *          arrays.
+     */
+    public long getTotalInstanceSize() {
+        int count = instances.size();
+        if (count == 0 || !isArray()) {
+            return count * instanceSize;
+        }
+
+        // array class and non-zero count, we have to
+        // get the size of each instance and sum it
+        long result = 0;
+        for (int i = 0; i < count; i++) {
+            JavaThing t = (JavaThing) instances.elementAt(i);
+            result += t.getSize();
+        }
+        return result;
+    }
+
+    /**
+     * @return the size of this object
+     */
+    public int getSize() {
+        JavaClass cl = mySnapshot.getJavaLangClass();
+        if (cl == null) {
+            return 0;
+        } else {
+            return cl.getInstanceSize();
+        }
+    }
+
+    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
+        super.visitReferencedObjects(v);
+        JavaHeapObject sc = getSuperclass();
+        if (sc != null) v.visit(getSuperclass());
+
+        JavaThing other;
+        other = getLoader();
+        if (other instanceof JavaHeapObject) {
+            v.visit((JavaHeapObject)other);
+        }
+        other = getSigners();
+        if (other instanceof JavaHeapObject) {
+            v.visit((JavaHeapObject)other);
+        }
+        other = getProtectionDomain();
+        if (other instanceof JavaHeapObject) {
+            v.visit((JavaHeapObject)other);
+        }
+
+        for (int i = 0; i < statics.length; i++) {
+            JavaField f = statics[i].getField();
+            if (!v.exclude(this, f) && f.hasId()) {
+                other = statics[i].getValue();
+                if (other instanceof JavaHeapObject) {
+                    v.visit((JavaHeapObject) other);
+                }
+            }
+        }
+    }
+
+    // package-privates below this point
+    final ReadBuffer getReadBuffer() {
+        return mySnapshot.getReadBuffer();
+    }
+
+    final void setNew(JavaHeapObject obj, boolean flag) {
+        mySnapshot.setNew(obj, flag);
+    }
+
+    final boolean isNew(JavaHeapObject obj) {
+        return mySnapshot.isNew(obj);
+    }
+
+    final StackTrace getSiteTrace(JavaHeapObject obj) {
+        return mySnapshot.getSiteTrace(obj);
+    }
+
+    final void addReferenceFromRoot(Root root, JavaHeapObject obj) {
+        mySnapshot.addReferenceFromRoot(root, obj);
+    }
+
+    final Root getRoot(JavaHeapObject obj) {
+        return mySnapshot.getRoot(obj);
+    }
+
+    final Snapshot getSnapshot() {
+        return mySnapshot;
+    }
+
+    void addInstance(JavaHeapObject inst) {
+        instances.addElement(inst);
+    }
+
+    // Internals only below this point
+    private void addFields(Vector<JavaField> v) {
+        if (superclass != null) {
+            ((JavaClass) superclass).addFields(v);
+        }
+        for (int i = 0; i < fields.length; i++) {
+            v.addElement(fields[i]);
+        }
+    }
+
+    private void addSubclassInstances(Vector<JavaHeapObject> v) {
+        for (int i = 0; i < subclasses.length; i++) {
+            subclasses[i].addSubclassInstances(v);
+        }
+        for (int i = 0; i < instances.size(); i++) {
+            v.addElement(instances.elementAt(i));
+        }
+    }
+
+    private void addSubclass(JavaClass sub) {
+        JavaClass newValue[] = new JavaClass[subclasses.length + 1];
+        System.arraycopy(subclasses, 0, newValue, 0, subclasses.length);
+        newValue[subclasses.length] = sub;
+        subclasses = newValue;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaDouble.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a double (i.e. a double field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaDouble extends JavaValue {
+
+    double value;
+
+    public JavaDouble(double value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return Double.toString(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaField.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+public class JavaField {
+
+    private String name;
+    private String signature;
+
+    public JavaField(String name, String signature) {
+        this.name = name;
+        this.signature = signature;
+    }
+
+
+    /**
+     * @return true if the type of this field is something that has an ID.
+     *          int fields, for exampe, don't.
+     */
+    public boolean hasId() {
+        char ch = signature.charAt(0);
+        return (ch == '[' || ch == 'L');
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getSignature() {
+        return signature;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaFloat.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a float (i.e. a float field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaFloat extends JavaValue {
+
+    float value;
+
+    public JavaFloat(float value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return Float.toString(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaHeapObject.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import jdk.test.lib.hprof.util.Misc;
+
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+/**
+ * Represents an object that's allocated out of the Java heap.  It occupies
+ * memory in the VM, and is the sort of thing that in a JDK 1.1 VM had
+ * a handle.  It can be a
+ * JavaClass, a JavaObjectArray, a JavaValueArray or a JavaObject.
+ */
+
+public abstract class JavaHeapObject extends JavaThing {
+
+    //
+    // Who we refer to.  This is heavily optimized for space, because it's
+    // well worth trading a bit of speed for less swapping.
+    // referers and referersLen go through two phases:  Building and
+    // resolved.  When building, referers might have duplicates, but can
+    // be appended to.  When resolved, referers has no duplicates or
+    // empty slots.
+    //
+    private JavaThing[] referers = null;
+    private int referersLen = 0;        // -1 when resolved
+
+    public abstract JavaClass getClazz();
+    public abstract int getSize();
+    public abstract long getId();
+
+    /**
+     * Do any initialization this thing needs after its data is read in.
+     * Subclasses that override this should call super.resolve().
+     */
+    public void resolve(Snapshot snapshot) {
+        StackTrace trace = snapshot.getSiteTrace(this);
+        if (trace != null) {
+            trace.resolve(snapshot);
+        }
+    }
+
+    //
+    //  Eliminate duplicates from referers, and size the array exactly.
+    // This sets us up to answer queries.  See the comments around the
+    // referers data member for details.
+    //
+    void setupReferers() {
+        if (referersLen > 1) {
+            // Copy referers to map, screening out duplicates
+            Map<JavaThing, JavaThing> map = new HashMap<JavaThing, JavaThing>();
+            for (int i = 0; i < referersLen; i++) {
+                if (map.get(referers[i]) == null) {
+                    map.put(referers[i], referers[i]);
+                }
+            }
+
+            // Now copy into the array
+            referers = new JavaThing[map.size()];
+            map.keySet().toArray(referers);
+        }
+        referersLen = -1;
+    }
+
+
+    /**
+     * @return the id of this thing as hex string
+     */
+    public String getIdString() {
+        return Misc.toHex(getId());
+    }
+
+    public String toString() {
+        return getClazz().getName() + "@" + getIdString();
+    }
+
+    /**
+     * @return the StackTrace of the point of allocation of this object,
+     *          or null if unknown
+     */
+    public StackTrace getAllocatedFrom() {
+        return getClazz().getSiteTrace(this);
+    }
+
+    public boolean isNew() {
+        return getClazz().isNew(this);
+    }
+
+    void setNew(boolean flag) {
+        getClazz().setNew(this, flag);
+    }
+
+    /**
+     * Tell the visitor about all of the objects we refer to
+     */
+    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
+        v.visit(getClazz());
+    }
+
+    void addReferenceFrom(JavaHeapObject other) {
+        if (referersLen == 0) {
+            referers = new JavaThing[1];        // It was null
+        } else if (referersLen == referers.length) {
+            JavaThing[] copy = new JavaThing[(3 * (referersLen + 1)) / 2];
+            System.arraycopy(referers, 0, copy, 0, referersLen);
+            referers = copy;
+        }
+        referers[referersLen++] = other;
+        // We just append to referers here.  Measurements have shown that
+        // around 10% to 30% are duplicates, so it's better to just append
+        // blindly and screen out all the duplicates at once.
+    }
+
+    void addReferenceFromRoot(Root r) {
+        getClazz().addReferenceFromRoot(r, this);
+    }
+
+    /**
+     * If the rootset includes this object, return a Root describing one
+     * of the reasons why.
+     */
+    public Root getRoot() {
+        return getClazz().getRoot(this);
+    }
+
+    /**
+     * Tell who refers to us.
+     *
+     * @return an Enumeration of JavaHeapObject instances
+     */
+    public Enumeration<JavaThing> getReferers() {
+        if (referersLen != -1) {
+            throw new RuntimeException("not resolved: " + getIdString());
+        }
+        return new Enumeration<JavaThing>() {
+
+            private int num = 0;
+
+            public boolean hasMoreElements() {
+                return referers != null && num < referers.length;
+            }
+
+            public JavaThing nextElement() {
+                return referers[num++];
+            }
+        };
+    }
+
+    /**
+     * Given other, which the caller promises is in referers, determines if
+     * the reference is only a weak reference.
+     */
+    public boolean refersOnlyWeaklyTo(Snapshot ss, JavaThing other) {
+        return false;
+    }
+
+    /**
+     * Describe the reference that this thing has to target.  This will only
+     * be called if target is in the array returned by getChildrenForRootset.
+     */
+    public String describeReferenceTo(JavaThing target, Snapshot ss) {
+        return "??";
+    }
+
+    public boolean isHeapAllocated() {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaHeapObjectVisitor.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * A visitor for a JavaThing.  @see JavaObject#visitReferencedObjects()
+ *
+ * @author      Bill Foote
+ */
+
+
+public interface JavaHeapObjectVisitor {
+    public void visit(JavaHeapObject other);
+
+    /**
+     * Should the given field be excluded from the set of things visited?
+     * @return true if it should.
+     */
+    public boolean exclude(JavaClass clazz, JavaField f);
+
+    /**
+     * @return true iff exclude might ever return true
+     */
+    public boolean mightExclude();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaInt.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents an integer (i.e. an int field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaInt extends JavaValue {
+
+    int value;
+
+    public JavaInt(int value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return "" + value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaLazyReadObject.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.io.IOException;
+import jdk.test.lib.hprof.parser.ReadBuffer;
+
+/*
+ * Base class for lazily read Java heap objects.
+ */
+public abstract class JavaLazyReadObject extends JavaHeapObject {
+
+    // file offset from which this object data starts
+    private final long offset;
+
+    protected JavaLazyReadObject(long offset) {
+        this.offset = offset;
+    }
+
+    public final int getSize() {
+        return getValueLength() + getClazz().getMinimumObjectSize();
+    }
+
+    protected final long getOffset() {
+        return offset;
+    }
+
+    // return the length of the data for this object
+    protected final int getValueLength() {
+        try {
+            return readValueLength();
+        } catch (IOException exp) {
+            System.err.println("lazy read failed at offset " + offset);
+            exp.printStackTrace();
+            return 0;
+        }
+    }
+
+    // get this object's content as byte array
+    protected final byte[] getValue() {
+        try {
+            return readValue();
+        } catch (IOException exp) {
+            System.err.println("lazy read failed at offset " + offset);
+            exp.printStackTrace();
+            return Snapshot.EMPTY_BYTE_ARRAY;
+        }
+    }
+
+    // get ID of this object
+    public final long getId() {
+        try {
+            ReadBuffer buf = getClazz().getReadBuffer();
+            int idSize = getClazz().getIdentifierSize();
+            if (idSize == 4) {
+                return ((long)buf.getInt(offset)) & Snapshot.SMALL_ID_MASK;
+            } else {
+                return buf.getLong(offset);
+            }
+        } catch (IOException exp) {
+            System.err.println("lazy read failed at offset " + offset);
+            exp.printStackTrace();
+            return -1;
+        }
+    }
+
+    protected abstract int readValueLength() throws IOException;
+    protected abstract byte[] readValue() throws IOException;
+
+    // make Integer or Long for given object ID
+    protected static Number makeId(long id) {
+        if ((id & ~Snapshot.SMALL_ID_MASK) == 0) {
+            return (int)id;
+        } else {
+            return id;
+        }
+    }
+
+    // get ID as long value from Number
+    protected static long getIdValue(Number num) {
+        long id = num.longValue();
+        if (num instanceof Integer) {
+            id &= Snapshot.SMALL_ID_MASK;
+        }
+        return id;
+    }
+
+    // read object ID from given index from given byte array
+    protected final long objectIdAt(int index, byte[] data) {
+        int idSize = getClazz().getIdentifierSize();
+        if (idSize == 4) {
+            return ((long)intAt(index, data)) & Snapshot.SMALL_ID_MASK;
+        } else {
+            return longAt(index, data);
+        }
+    }
+
+    // utility methods to read primitive types from byte array
+    protected static byte byteAt(int index, byte[] value) {
+        return value[index];
+    }
+
+    protected static boolean booleanAt(int index, byte[] value) {
+        return (value[index] & 0xff) == 0? false: true;
+    }
+
+    protected static char charAt(int index, byte[] value) {
+        int b1 = ((int) value[index++] & 0xff);
+        int b2 = ((int) value[index++] & 0xff);
+        return (char) ((b1 << 8) + b2);
+    }
+
+    protected static short shortAt(int index, byte[] value) {
+        int b1 = ((int) value[index++] & 0xff);
+        int b2 = ((int) value[index++] & 0xff);
+        return (short) ((b1 << 8) + b2);
+    }
+
+    protected static int intAt(int index, byte[] value) {
+        int b1 = ((int) value[index++] & 0xff);
+        int b2 = ((int) value[index++] & 0xff);
+        int b3 = ((int) value[index++] & 0xff);
+        int b4 = ((int) value[index++] & 0xff);
+        return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
+    }
+
+    protected static long longAt(int index, byte[] value) {
+        long val = 0;
+        for (int j = 0; j < 8; j++) {
+            val = val << 8;
+            int b = ((int)value[index++]) & 0xff;
+            val |= b;
+        }
+        return val;
+    }
+
+    protected static float floatAt(int index, byte[] value) {
+        int val = intAt(index, value);
+        return Float.intBitsToFloat(val);
+    }
+
+    protected static double doubleAt(int index, byte[] value) {
+        long val = longAt(index, value);
+        return Double.longBitsToDouble(val);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaLong.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a long (i.e. a long field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaLong extends JavaValue {
+
+    long value;
+
+    public JavaLong(long value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return Long.toString(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObject.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.io.IOException;
+import jdk.test.lib.hprof.parser.ReadBuffer;
+
+/**
+ * Represents Java instance
+ *
+ * @author      Bill Foote
+ */
+public class JavaObject extends JavaLazyReadObject {
+
+    private Object clazz;       // Number before resolve
+                                // JavaClass after resolve
+    /**
+     * Construct a new JavaObject.
+     *
+     * @param classID id of the class object
+     * @param offset The offset of field data
+     */
+    public JavaObject(long classID, long offset) {
+        super(offset);
+        this.clazz = makeId(classID);
+    }
+
+    public void resolve(Snapshot snapshot) {
+        if (clazz instanceof JavaClass) {
+            return;
+        }
+        if (clazz instanceof Number) {
+            long classID = getIdValue((Number)clazz);
+            clazz = snapshot.findThing(classID);
+            if (! (clazz instanceof JavaClass)) {
+                warn("Class " + Long.toHexString(classID) + " not found, " +
+                     "adding fake class!");
+                int length;
+                ReadBuffer buf = snapshot.getReadBuffer();
+                int idSize = snapshot.getIdentifierSize();
+                long lenOffset = getOffset() + 2*idSize + 4;
+                try {
+                    length = buf.getInt(lenOffset);
+                } catch (IOException exp) {
+                    throw new RuntimeException(exp);
+                }
+                clazz = snapshot.addFakeInstanceClass(classID, length);
+            }
+        } else {
+            throw new InternalError("should not reach here");
+        }
+
+        JavaClass cl = (JavaClass) clazz;
+        cl.resolve(snapshot);
+
+        // while resolving, parse fields in verbose mode.
+        // but, getFields calls parseFields in non-verbose mode
+        // to avoid printing warnings repeatedly.
+        parseFields(getValue(), true);
+
+        cl.addInstance(this);
+        super.resolve(snapshot);
+    }
+
+    /**
+     * Are we the same type as other?  We are iff our clazz is the
+     * same type as other's.
+     */
+    public boolean isSameTypeAs(JavaThing other) {
+        if (!(other instanceof JavaObject)) {
+            return false;
+        }
+        JavaObject oo = (JavaObject) other;
+        return getClazz().equals(oo.getClazz());
+    }
+
+    /**
+     * Return our JavaClass object.  This may only be called after resolve.
+     */
+    public JavaClass getClazz() {
+        return (JavaClass) clazz;
+    }
+
+    public JavaThing[] getFields() {
+        // pass false to verbose mode so that dereference
+        // warnings are not printed.
+        return parseFields(getValue(), false);
+    }
+
+    // returns the value of field of given name
+    public JavaThing getField(String name) {
+        JavaThing[] flds = getFields();
+        JavaField[] instFields = getClazz().getFieldsForInstance();
+        for (int i = 0; i < instFields.length; i++) {
+            if (instFields[i].getName().equals(name)) {
+                return flds[i];
+            }
+        }
+        return null;
+    }
+
+    public int compareTo(JavaThing other) {
+        if (other instanceof JavaObject) {
+            JavaObject oo = (JavaObject) other;
+            return getClazz().getName().compareTo(oo.getClazz().getName());
+        }
+        return super.compareTo(other);
+    }
+
+    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
+        super.visitReferencedObjects(v);
+        JavaThing[] flds = getFields();
+        for (int i = 0; i < flds.length; i++) {
+            if (flds[i] != null) {
+                if (v.mightExclude()
+                    && v.exclude(getClazz().getClassForField(i),
+                                 getClazz().getFieldForInstance(i)))
+                {
+                    // skip it
+                } else if (flds[i] instanceof JavaHeapObject) {
+                    v.visit((JavaHeapObject) flds[i]);
+                }
+            }
+        }
+    }
+
+    public boolean refersOnlyWeaklyTo(Snapshot ss, JavaThing other) {
+        if (ss.getWeakReferenceClass() != null) {
+            final int referentFieldIndex = ss.getReferentFieldIndex();
+            if (ss.getWeakReferenceClass().isAssignableFrom(getClazz())) {
+                //
+                // REMIND:  This introduces a dependency on the JDK
+                //      implementation that is undesirable.
+                JavaThing[] flds = getFields();
+                for (int i = 0; i < flds.length; i++) {
+                    if (i != referentFieldIndex && flds[i] == other) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Describe the reference that this thing has to target.  This will only
+     * be called if target is in the array returned by getChildrenForRootset.
+     */
+    public String describeReferenceTo(JavaThing target, Snapshot ss) {
+        JavaThing[] flds = getFields();
+        for (int i = 0; i < flds.length; i++) {
+            if (flds[i] == target) {
+                JavaField f = getClazz().getFieldForInstance(i);
+                return "field " + f.getName();
+            }
+        }
+        return super.describeReferenceTo(target, ss);
+    }
+
+    public String toString() {
+        if (getClazz().isString()) {
+            JavaThing value = getField("value");
+            if (value instanceof JavaValueArray) {
+                return ((JavaValueArray)value).valueString();
+            } else {
+                return "null";
+            }
+        } else {
+            return super.toString();
+        }
+    }
+
+    // Internals only below this point
+
+    /*
+     * Java instance record (HPROF_GC_INSTANCE_DUMP) looks as below:
+     *
+     *     object ID
+     *     stack trace serial number (int)
+     *     class ID
+     *     data length (int)
+     *     byte[length]
+     */
+    protected final int readValueLength() throws IOException {
+        JavaClass cl = getClazz();
+        int idSize = cl.getIdentifierSize();
+        long lengthOffset = getOffset() + 2*idSize + 4;
+        return cl.getReadBuffer().getInt(lengthOffset);
+    }
+
+    protected final byte[] readValue() throws IOException {
+        JavaClass cl = getClazz();
+        int idSize = cl.getIdentifierSize();
+        ReadBuffer buf = cl.getReadBuffer();
+        long offset = getOffset() + 2*idSize + 4;
+        int length = buf.getInt(offset);
+        if (length == 0) {
+            return Snapshot.EMPTY_BYTE_ARRAY;
+        } else {
+            byte[] res = new byte[length];
+            buf.get(offset + 4, res);
+            return res;
+        }
+    }
+
+    private JavaThing[] parseFields(byte[] data, boolean verbose) {
+        JavaClass cl = getClazz();
+        int target = cl.getNumFieldsForInstance();
+        JavaField[] fields = cl.getFields();
+        JavaThing[] fieldValues = new JavaThing[target];
+        Snapshot snapshot = cl.getSnapshot();
+        int idSize = snapshot.getIdentifierSize();
+        int fieldNo = 0;
+        // In the dump file, the fields are stored in this order:
+        // fields of most derived class (immediate class) are stored
+        // first and then the super class and so on. In this object,
+        // fields are stored in the reverse ("natural") order. i.e.,
+        // fields of most super class are stored first.
+
+        // target variable is used to compensate for the fact that
+        // the dump file starts field values from the leaf working
+        // upwards in the inheritance hierarchy, whereas JavaObject
+        // starts with the top of the inheritance hierarchy and works down.
+        target -= fields.length;
+        JavaClass currClass = cl;
+        int index = 0;
+        for (int i = 0; i < fieldValues.length; i++, fieldNo++) {
+            while (fieldNo >= fields.length) {
+                currClass = currClass.getSuperclass();
+                fields = currClass.getFields();
+                fieldNo = 0;
+                target -= fields.length;
+            }
+            JavaField f = fields[fieldNo];
+            char sig = f.getSignature().charAt(0);
+            switch (sig) {
+                case 'L':
+                case '[': {
+                    long id = objectIdAt(index, data);
+                    index += idSize;
+                    JavaObjectRef ref = new JavaObjectRef(id);
+                    fieldValues[target+fieldNo] = ref.dereference(snapshot, f, verbose);
+                    break;
+                }
+                case 'Z': {
+                    byte value = byteAt(index, data);
+                    index++;
+                    fieldValues[target+fieldNo] = new JavaBoolean(value != 0);
+                    break;
+                }
+                case 'B': {
+                    byte value = byteAt(index, data);
+                    index++;
+                    fieldValues[target+fieldNo] = new JavaByte(value);
+                    break;
+                }
+                case 'S': {
+                    short value = shortAt(index, data);
+                    index += 2;
+                    fieldValues[target+fieldNo] = new JavaShort(value);
+                    break;
+                }
+                case 'C': {
+                    char value = charAt(index, data);
+                    index += 2;
+                    fieldValues[target+fieldNo] = new JavaChar(value);
+                    break;
+                }
+                case 'I': {
+                    int value = intAt(index, data);
+                    index += 4;
+                    fieldValues[target+fieldNo] = new JavaInt(value);
+                    break;
+                }
+                case 'J': {
+                    long value = longAt(index, data);
+                    index += 8;
+                    fieldValues[target+fieldNo] = new JavaLong(value);
+                    break;
+                }
+                case 'F': {
+                    float value = floatAt(index, data);
+                    index += 4;
+                    fieldValues[target+fieldNo] = new JavaFloat(value);
+                    break;
+                }
+                case 'D': {
+                    double value = doubleAt(index, data);
+                    index += 8;
+                    fieldValues[target+fieldNo] = new JavaDouble(value);
+                    break;
+                }
+                default:
+                    throw new RuntimeException("invalid signature: " + sig);
+            }
+        }
+        return fieldValues;
+    }
+
+    private void warn(String msg) {
+        System.out.println("WARNING: " + msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.io.IOException;
+import jdk.test.lib.hprof.parser.ReadBuffer;
+
+/**
+ * @author      Bill Foote
+ */
+public class JavaObjectArray extends JavaLazyReadObject {
+
+    private Object clazz;  // Long before resolve, the class after resolve
+
+    public JavaObjectArray(long classID, long offset) {
+        super(offset);
+        this.clazz = makeId(classID);
+    }
+
+    public JavaClass getClazz() {
+        return (JavaClass) clazz;
+    }
+
+    public void resolve(Snapshot snapshot) {
+        if (clazz instanceof JavaClass) {
+            return;
+        }
+        long classID = getIdValue((Number)clazz);
+        if (snapshot.isNewStyleArrayClass()) {
+            // Modern heap dumps do this
+            JavaThing t = snapshot.findThing(classID);
+            if (t instanceof JavaClass) {
+                clazz = (JavaClass) t;
+            }
+        }
+        if (!(clazz instanceof JavaClass)) {
+            JavaThing t = snapshot.findThing(classID);
+            if (t != null && t instanceof JavaClass) {
+                JavaClass el = (JavaClass) t;
+                String nm = el.getName();
+                if (!nm.startsWith("[")) {
+                    nm = "L" + el.getName() + ";";
+                }
+                clazz = snapshot.getArrayClass(nm);
+            }
+        }
+
+        if (!(clazz instanceof JavaClass)) {
+            clazz = snapshot.getOtherArrayType();
+        }
+        ((JavaClass)clazz).addInstance(this);
+        super.resolve(snapshot);
+    }
+
+    public JavaThing[] getValues() {
+        return getElements();
+    }
+
+    public JavaThing[] getElements() {
+        Snapshot snapshot = getClazz().getSnapshot();
+        byte[] data = getValue();
+        final int idSize = snapshot.getIdentifierSize();
+        final int numElements = data.length / idSize;
+        JavaThing[] elements = new JavaThing[numElements];
+        int index = 0;
+        for (int i = 0; i < elements.length; i++) {
+            long id = objectIdAt(index, data);
+            index += idSize;
+            elements[i] = snapshot.findThing(id);
+        }
+        return elements;
+    }
+
+    public int compareTo(JavaThing other) {
+        if (other instanceof JavaObjectArray) {
+            return 0;
+        }
+        return super.compareTo(other);
+    }
+
+    public int getLength() {
+        return getValueLength() / getClazz().getIdentifierSize();
+    }
+
+    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
+        super.visitReferencedObjects(v);
+        JavaThing[] elements = getElements();
+        for (int i = 0; i < elements.length; i++) {
+            if (elements[i] != null && elements[i] instanceof JavaHeapObject) {
+                v.visit((JavaHeapObject) elements[i]);
+            }
+        }
+    }
+
+    /**
+     * Describe the reference that this thing has to target.  This will only
+     * be called if target is in the array returned by getChildrenForRootset.
+     */
+    public String describeReferenceTo(JavaThing target, Snapshot ss) {
+        JavaThing[] elements = getElements();
+        for (int i = 0; i < elements.length; i++) {
+            if (elements[i] == target) {
+                return "Element " + i + " of " + this;
+            }
+        }
+        return super.describeReferenceTo(target, ss);
+    }
+
+    /*
+     * Java object array record (HPROF_GC_OBJ_ARRAY_DUMP)
+     * looks as below:
+     *
+     *     object ID
+     *     stack trace serial number (int)
+     *     array length (int)
+     *     array class ID
+     *     array element IDs
+     */
+    protected final int readValueLength() throws IOException {
+        JavaClass cl = getClazz();
+        ReadBuffer buf = cl.getReadBuffer();
+        int idSize = cl.getIdentifierSize();
+        long offset = getOffset() + idSize + 4;
+        int len = buf.getInt(offset);
+        return len * cl.getIdentifierSize();
+    }
+
+    protected final byte[] readValue() throws IOException {
+        JavaClass cl = getClazz();
+        ReadBuffer buf = cl.getReadBuffer();
+        int idSize = cl.getIdentifierSize();
+        long offset = getOffset() + idSize + 4;
+        int len = buf.getInt(offset);
+        if (len == 0) {
+            return Snapshot.EMPTY_BYTE_ARRAY;
+        } else {
+            byte[] res = new byte[len * idSize];
+            buf.get(offset + 4 + idSize, res);
+            return res;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObjectRef.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import jdk.test.lib.hprof.util.Misc;
+
+/**
+ * A forward reference to an object.  This is an intermediate representation
+ * for a JavaThing, when we have the thing's ID, but we might not have read
+ * the thing yet.
+ *
+ * @author      Bill Foote
+ */
+public class JavaObjectRef extends JavaThing {
+    private long id;
+
+    public JavaObjectRef(long id) {
+        this.id = id;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public boolean isHeapAllocated() {
+        return true;
+    }
+
+    public JavaThing dereference(Snapshot snapshot, JavaField field) {
+        return dereference(snapshot, field, true);
+    }
+
+    public JavaThing dereference(Snapshot snapshot, JavaField field, boolean verbose) {
+        if (field != null && !field.hasId()) {
+            // If this happens, we must be a field that represents an int.
+            // (This only happens with .bod-style files)
+            return new JavaLong(id);
+        }
+        if (id == 0) {
+            return snapshot.getNullThing();
+        }
+        JavaThing result = snapshot.findThing(id);
+        if (result == null) {
+            if (!snapshot.getUnresolvedObjectsOK() && verbose) {
+                String msg = "WARNING:  Failed to resolve object id "
+                                + Misc.toHex(id);
+                if (field != null) {
+                    msg += " for field " + field.getName()
+                            + " (signature " + field.getSignature() + ")";
+                }
+                System.out.println(msg);
+                // Thread.dumpStack();
+            }
+            result = new HackJavaValue("Unresolved object "
+                                        + Misc.toHex(id), 0);
+        }
+        return result;
+    }
+
+    public int getSize() {
+        return 0;
+    }
+
+    public String toString() {
+        return "Unresolved object " + Misc.toHex(id);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaShort.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a short (i.e. a short field in an instance).
+ *
+ * @author      Bill Foote
+ */
+
+
+public class JavaShort extends JavaValue {
+
+    short value;
+
+    public JavaShort(short value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return "" + value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaStatic.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+/**
+ * Represents the value of a static field of a JavaClass
+ */
+
+public class JavaStatic {
+
+    private JavaField field;
+    private JavaThing value;
+
+    public JavaStatic(JavaField field, JavaThing value) {
+        this.field = field;
+        this.value = value;
+    }
+
+    public void resolve(JavaClass clazz, Snapshot snapshot) {
+        long id = -1;
+        if (value instanceof JavaObjectRef) {
+            id = ((JavaObjectRef)value).getId();
+        }
+        value = value.dereference(snapshot, field);
+        if (value.isHeapAllocated() &&
+            clazz.getLoader() == snapshot.getNullThing()) {
+            // static fields are only roots if they are in classes
+            //    loaded by the root classloader.
+            JavaHeapObject ho = (JavaHeapObject) value;
+            String s = "Static reference from " + clazz.getName()
+                       + "." + field.getName();
+            snapshot.addRoot(new Root(id, clazz.getId(),
+                                      Root.JAVA_STATIC, s));
+        }
+    }
+
+    public JavaField getField() {
+        return field;
+    }
+
+    public JavaThing getValue() {
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaThing.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+
+/**
+ * Represents a java "Thing".  A thing is anything that can be the value of
+ * a field.  This includes JavaHeapObject, JavaObjectRef, and JavaValue.
+ */
+
+public abstract class JavaThing {
+
+    protected JavaThing() {
+    }
+
+    /**
+     * If this is a forward reference, figure out what it really
+     * refers to.
+     *
+     * @param snapshot  The snapshot this is for
+     * @param field     The field this thing represents.  If null, it is
+     *                  assumed this thing is an object (and never a value).
+     */
+    public JavaThing dereference(Snapshot shapshot, JavaField field) {
+        return this;
+    }
+
+
+    /**
+     * Are we the same type as other?
+     *
+     * @see JavaObject.isSameTypeAs()
+     */
+    public boolean isSameTypeAs(JavaThing other) {
+        return getClass() == other.getClass();
+    }
+    /**
+     * @return true iff this represents a heap-allocated object
+     */
+    abstract public boolean isHeapAllocated();
+
+    /**
+     * @return the size of this object, in bytes, including VM overhead
+     */
+    abstract public int getSize();
+
+    /**
+     * @return a human-readable string representation of this thing
+     */
+    abstract public String toString();
+
+    /**
+     * Compare our string representation to other's
+     * @see java.lang.String.compareTo()
+     */
+    public int compareTo(JavaThing other) {
+        return toString().compareTo(other.toString());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaValue.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Abstract base class for all value types (ints, longs, floats, etc.)
+ *
+ * @author      Bill Foote
+ */
+
+
+
+
+public abstract class JavaValue extends JavaThing {
+
+    protected JavaValue() {
+    }
+
+    public boolean isHeapAllocated() {
+        return false;
+    }
+
+    abstract public String toString();
+
+    public int getSize() {
+        // The size of a value is already accounted for in the class
+        // that has the data member.
+        return 0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import jdk.test.lib.hprof.parser.ReadBuffer;
+import java.io.IOException;
+
+/**
+ * An array of values, that is, an array of ints, boolean, floats or the like.
+ *
+ * @author      Bill Foote
+ */
+public class JavaValueArray extends JavaLazyReadObject
+                /*imports*/ implements ArrayTypeCodes {
+
+    private static String arrayTypeName(byte sig) {
+        switch (sig) {
+            case 'B':
+                return "byte[]";
+            case 'Z':
+                return "boolean[]";
+            case 'C':
+                return "char[]";
+            case 'S':
+                return "short[]";
+            case 'I':
+                return "int[]";
+            case 'F':
+                return "float[]";
+            case 'J':
+                return "long[]";
+            case 'D':
+                return "double[]";
+            default:
+                throw new RuntimeException("invalid array element sig: " + sig);
+        }
+    }
+
+    private static int elementSize(byte type) {
+        switch (type) {
+            case T_BYTE:
+            case T_BOOLEAN:
+                return 1;
+            case T_CHAR:
+            case T_SHORT:
+                return 2;
+            case T_INT:
+            case T_FLOAT:
+                return 4;
+            case T_LONG:
+            case T_DOUBLE:
+                return 8;
+            default:
+                throw new RuntimeException("invalid array element type: " + type);
+        }
+    }
+
+    /*
+     * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
+     * as below:
+     *
+     *    object ID
+     *    stack trace serial number (int)
+     *    length of the instance data (int)
+     *    element type (byte)
+     *    array data
+     */
+    protected final int readValueLength() throws IOException {
+        JavaClass cl = getClazz();
+        ReadBuffer buf = cl.getReadBuffer();
+        int idSize = cl.getIdentifierSize();
+        long offset = getOffset() + idSize + 4;
+        // length of the array
+        int len = buf.getInt(offset);
+        // typecode of array element type
+        byte type = buf.getByte(offset + 4);
+        return len * elementSize(type);
+    }
+
+    protected final byte[] readValue() throws IOException {
+        JavaClass cl = getClazz();
+        ReadBuffer buf = cl.getReadBuffer();
+        int idSize = cl.getIdentifierSize();
+        long offset = getOffset() + idSize + 4;
+        // length of the array
+        int length = buf.getInt(offset);
+        // typecode of array element type
+        byte type = buf.getByte(offset + 4);
+        if (length == 0) {
+            return Snapshot.EMPTY_BYTE_ARRAY;
+        } else {
+            length *= elementSize(type);
+            byte[] res = new byte[length];
+            buf.get(offset + 5, res);
+            return res;
+        }
+    }
+
+    // JavaClass set only after resolve.
+    private JavaClass clazz;
+
+    // This field contains elementSignature byte and
+    // divider to be used to calculate length. Note that
+    // length of content byte[] is not same as array length.
+    // Actual array length is (byte[].length / divider)
+    private int data;
+
+    // First 8 bits of data is used for element signature
+    private static final int SIGNATURE_MASK = 0x0FF;
+
+    // Next 8 bits of data is used for length divider
+    private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
+
+    // Number of bits to shift to get length divider
+    private static final int LENGTH_DIVIDER_SHIFT = 8;
+
+    public JavaValueArray(byte elementSignature, long offset) {
+        super(offset);
+        this.data = (elementSignature & SIGNATURE_MASK);
+    }
+
+    public JavaClass getClazz() {
+        return clazz;
+    }
+
+    public void visitReferencedObjects(JavaHeapObjectVisitor v) {
+        super.visitReferencedObjects(v);
+    }
+
+    public void resolve(Snapshot snapshot) {
+        if (clazz instanceof JavaClass) {
+            return;
+        }
+        byte elementSig = getElementType();
+        clazz = snapshot.findClass(arrayTypeName(elementSig));
+        if (clazz == null) {
+            clazz = snapshot.getArrayClass("" + ((char) elementSig));
+        }
+        getClazz().addInstance(this);
+        super.resolve(snapshot);
+    }
+
+    public int getLength() {
+        int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
+        if (divider == 0) {
+            byte elementSignature = getElementType();
+            switch (elementSignature) {
+            case 'B':
+            case 'Z':
+                divider = 1;
+                break;
+            case 'C':
+            case 'S':
+                divider = 2;
+                break;
+            case 'I':
+            case 'F':
+                divider = 4;
+                break;
+            case 'J':
+            case 'D':
+                divider = 8;
+                break;
+            default:
+                throw new RuntimeException("unknown primitive type: " +
+                                elementSignature);
+            }
+            data |= (divider << LENGTH_DIVIDER_SHIFT);
+        }
+        return (getValueLength() / divider);
+    }
+
+    public Object getElements() {
+        final int len = getLength();
+        final byte et = getElementType();
+        byte[] data = getValue();
+        int index = 0;
+        switch (et) {
+            case 'Z': {
+                boolean[] res = new boolean[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = booleanAt(index, data);
+                    index++;
+                }
+                return res;
+            }
+            case 'B': {
+                byte[] res = new byte[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = byteAt(index, data);
+                    index++;
+                }
+                return res;
+            }
+            case 'C': {
+                char[] res = new char[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = charAt(index, data);
+                    index += 2;
+                }
+                return res;
+            }
+            case 'S': {
+                short[] res = new short[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = shortAt(index, data);
+                    index += 2;
+                }
+                return res;
+            }
+            case 'I': {
+                int[] res = new int[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = intAt(index, data);
+                    index += 4;
+                }
+                return res;
+            }
+            case 'J': {
+                long[] res = new long[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = longAt(index, data);
+                    index += 8;
+                }
+                return res;
+            }
+            case 'F': {
+                float[] res = new float[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = floatAt(index, data);
+                    index += 4;
+                }
+                return res;
+            }
+            case 'D': {
+                double[] res = new double[len];
+                for (int i = 0; i < len; i++) {
+                    res[i] = doubleAt(index, data);
+                    index += 8;
+                }
+                return res;
+            }
+            default: {
+                throw new RuntimeException("unknown primitive type?");
+            }
+        }
+    }
+
+    public byte getElementType() {
+        return (byte) (data & SIGNATURE_MASK);
+    }
+
+    private void checkIndex(int index) {
+        if (index < 0 || index >= getLength()) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+    }
+
+    private void requireType(char type) {
+        if (getElementType() != type) {
+            throw new RuntimeException("not of type : " + type);
+        }
+    }
+
+    public boolean getBooleanAt(int index) {
+        checkIndex(index);
+        requireType('Z');
+        return booleanAt(index, getValue());
+    }
+
+    public byte getByteAt(int index) {
+        checkIndex(index);
+        requireType('B');
+        return byteAt(index, getValue());
+    }
+
+    public char getCharAt(int index) {
+        checkIndex(index);
+        requireType('C');
+        return charAt(index << 1, getValue());
+    }
+
+    public short getShortAt(int index) {
+        checkIndex(index);
+        requireType('S');
+        return shortAt(index << 1, getValue());
+    }
+
+    public int getIntAt(int index) {
+        checkIndex(index);
+        requireType('I');
+        return intAt(index << 2, getValue());
+    }
+
+    public long getLongAt(int index) {
+        checkIndex(index);
+        requireType('J');
+        return longAt(index << 3, getValue());
+    }
+
+    public float getFloatAt(int index) {
+        checkIndex(index);
+        requireType('F');
+        return floatAt(index << 2, getValue());
+    }
+
+    public double getDoubleAt(int index) {
+        checkIndex(index);
+        requireType('D');
+        return doubleAt(index << 3, getValue());
+    }
+
+    public String valueString() {
+        return valueString(true);
+    }
+
+    public String valueString(boolean bigLimit) {
+        // Char arrays deserve special treatment
+        StringBuilder result;
+        byte[] value = getValue();
+        int max = value.length;
+        byte elementSignature = getElementType();
+        if (elementSignature == 'C')  {
+            result = new StringBuilder();
+            for (int i = 0; i < value.length; ) {
+                char val = charAt(i, value);
+                result.append(val);
+                i += 2;
+            }
+        } else {
+            int limit = 8;
+            if (bigLimit) {
+                limit = 1000;
+            }
+            result = new StringBuilder("{");
+            int num = 0;
+            for (int i = 0; i < value.length; ) {
+                if (num > 0) {
+                    result.append(", ");
+                }
+                if (num >= limit) {
+                    result.append("... ");
+                    break;
+                }
+                num++;
+                switch (elementSignature) {
+                    case 'Z': {
+                        boolean val = booleanAt(i, value);
+                        if (val) {
+                            result.append("true");
+                        } else {
+                            result.append("false");
+                        }
+                        i++;
+                        break;
+                    }
+                    case 'B': {
+                        int val = 0xFF & byteAt(i, value);
+                        result.append("0x").append(Integer.toString(val, 16));
+                        i++;
+                        break;
+                    }
+                    case 'S': {
+                        short val = shortAt(i, value);
+                        i += 2;
+                        result.append(val);
+                        break;
+                    }
+                    case 'I': {
+                        int val = intAt(i, value);
+                        i += 4;
+                        result.append(val);
+                        break;
+                    }
+                    case 'J': {         // long
+                        long val = longAt(i, value);
+                        result.append(val);
+                        i += 8;
+                        break;
+                    }
+                    case 'F': {
+                        float val = floatAt(i, value);
+                        result.append(val);
+                        i += 4;
+                        break;
+                    }
+                    case 'D': {         // double
+                        double val = doubleAt(i, value);
+                        result.append(val);
+                        i += 8;
+                        break;
+                    }
+                    default: {
+                        throw new RuntimeException("unknown primitive type?");
+                    }
+                }
+            }
+            result.append('}');
+        }
+        return result.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/ReachableExcludes.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+
+/**
+ * This represents a set of data members that should be excluded from the
+ * reachable objects query. This is useful to exclude observers from the
+ * transitive closure of objects reachable from a given object, allowing
+ * some kind of real determination of the "size" of that object.
+ *
+ */
+
+public interface ReachableExcludes {
+    /**
+     * @return true iff the given field is on the hitlist of excluded
+     *          fields.
+     */
+    public boolean isExcluded(String fieldName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/ReachableExcludesImpl.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.IOException;
+
+import java.util.Hashtable;
+
+/**
+ * This represents a set of data members that should be excluded from the
+ * reachable objects query.
+ * This is useful to exclude observers from the
+ * transitive closure of objects reachable from a given object, allowing
+ * some kind of real determination of the "size" of that object.
+ *
+ * @author      Bill Foote
+ */
+public class ReachableExcludesImpl implements ReachableExcludes {
+
+    private File excludesFile;
+    private long lastModified;
+    private Hashtable<String, String> methods;  // Used as a bag
+
+    /**
+     * Create a new ReachableExcludesImpl over the given file.  The file will be
+     * re-read whenever the timestamp changes.
+     */
+    public ReachableExcludesImpl(File excludesFile) {
+        this.excludesFile = excludesFile;
+        readFile();
+    }
+
+    private void readFileIfNeeded() {
+        if (excludesFile.lastModified() != lastModified) {
+            synchronized(this) {
+                if (excludesFile.lastModified() != lastModified) {
+                    readFile();
+                }
+            }
+        }
+    }
+
+    private void readFile() {
+        long lm = excludesFile.lastModified();
+        Hashtable<String, String> m = new Hashtable<String, String>();
+
+        try (BufferedReader r = new BufferedReader(new InputStreamReader(
+                new FileInputStream(excludesFile)))) {
+            String method;
+            while ((method = r.readLine()) != null) {
+                m.put(method, method);
+            }
+            lastModified = lm;
+            methods = m;        // We want this to be atomic
+        } catch (IOException ex) {
+            System.out.println("Error reading " + excludesFile + ":  " + ex);
+        }
+    }
+
+    /**
+     * @return true iff the given field is on the histlist of excluded
+     *          fields.
+     */
+    public boolean isExcluded(String fieldName) {
+        readFileIfNeeded();
+        return methods.get(fieldName) != null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import jdk.test.lib.hprof.util.ArraySorter;
+import jdk.test.lib.hprof.util.Comparer;
+
+/**
+ * @author      A. Sundararajan
+ */
+
+public class ReachableObjects {
+    public ReachableObjects(JavaHeapObject root,
+                            final ReachableExcludes excludes) {
+        this.root = root;
+
+        final Hashtable<JavaHeapObject, JavaHeapObject> bag = new Hashtable<JavaHeapObject, JavaHeapObject>();
+        final Hashtable<String, String> fieldsExcluded = new Hashtable<String, String>();  //Bag<String>
+        final Hashtable<String, String> fieldsUsed = new Hashtable<String, String>();   // Bag<String>
+        JavaHeapObjectVisitor visitor = new AbstractJavaHeapObjectVisitor() {
+            public void visit(JavaHeapObject t) {
+                // Size is zero for things like integer fields
+                if (t != null && t.getSize() > 0 && bag.get(t) == null) {
+                    bag.put(t, t);
+                    t.visitReferencedObjects(this);
+                }
+            }
+
+            public boolean mightExclude() {
+                return excludes != null;
+            }
+
+            public boolean exclude(JavaClass clazz, JavaField f) {
+                if (excludes == null) {
+                    return false;
+                }
+                String nm = clazz.getName() + "." + f.getName();
+                if (excludes.isExcluded(nm)) {
+                    fieldsExcluded.put(nm, nm);
+                    return true;
+                } else {
+                    fieldsUsed.put(nm, nm);
+                    return false;
+                }
+            }
+        };
+        // Put the closure of root and all objects reachable from root into
+        // bag (depth first), but don't include root:
+        visitor.visit(root);
+        bag.remove(root);
+
+        // Now grab the elements into a vector, and sort it in decreasing size
+        JavaThing[] things = new JavaThing[bag.size()];
+        int i = 0;
+        for (Enumeration<JavaHeapObject> e = bag.elements(); e.hasMoreElements(); ) {
+            things[i++] = (JavaThing) e.nextElement();
+        }
+        ArraySorter.sort(things, new Comparer() {
+            public int compare(Object lhs, Object rhs) {
+                JavaThing left = (JavaThing) lhs;
+                JavaThing right = (JavaThing) rhs;
+                int diff = right.getSize() - left.getSize();
+                if (diff != 0) {
+                    return diff;
+                }
+                return left.compareTo(right);
+            }
+        });
+        this.reachables = things;
+
+        this.totalSize = root.getSize();
+        for (i = 0; i < things.length; i++) {
+            this.totalSize += things[i].getSize();
+        }
+
+        excludedFields = getElements(fieldsExcluded);
+        usedFields = getElements(fieldsUsed);
+    }
+
+    public JavaHeapObject getRoot() {
+        return root;
+    }
+
+    public JavaThing[] getReachables() {
+        return reachables;
+    }
+
+    public long getTotalSize() {
+        return totalSize;
+    }
+
+    public String[] getExcludedFields() {
+        return excludedFields;
+    }
+
+    public String[] getUsedFields() {
+        return usedFields;
+    }
+
+    private String[] getElements(Hashtable<?, ?> ht) {
+        Object[] keys = ht.keySet().toArray();
+        int len = keys.length;
+        String[] res = new String[len];
+        System.arraycopy(keys, 0, res, 0, len);
+        ArraySorter.sortArrayOfStrings(res);
+        return res;
+    }
+
+    private JavaHeapObject root;
+    private JavaThing[] reachables;
+    private String[]  excludedFields;
+    private String[]  usedFields;
+    private long totalSize;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/ReferenceChain.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ * Represents a chain of references to some target object
+ *
+ * @author      Bill Foote
+ */
+
+public class ReferenceChain {
+
+    JavaHeapObject      obj;    // Object referred to
+    ReferenceChain      next;   // Next in chain
+
+    public ReferenceChain(JavaHeapObject obj, ReferenceChain next) {
+        this.obj = obj;
+        this.next = next;
+    }
+
+    public JavaHeapObject getObj() {
+        return obj;
+    }
+
+    public ReferenceChain getNext() {
+        return next;
+    }
+
+    public int getDepth() {
+        int count = 1;
+        ReferenceChain tmp = next;
+        while (tmp != null) {
+            count++;
+            tmp = tmp.next;
+        }
+        return count;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/Root.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import jdk.test.lib.hprof.util.Misc;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+
+/**
+ * Represents a member of the rootset, that is, one of the objects that
+ * the GC starts from when marking reachable objects.
+ */
+
+public class Root {
+
+    private long id;            // ID of the JavaThing we refer to
+    private long refererId;     // Thread or Class responsible for this, or 0
+    private int index = -1;             // Index in Snapshot.roots
+    private int type;
+    private String description;
+    private JavaHeapObject referer = null;
+    private StackTrace stackTrace = null;
+
+    // Values for type.  Higher values are more interesting -- see getType().
+    // See also getTypeName()
+    public final static int INVALID_TYPE = 0;
+    public final static int UNKNOWN = 1;
+    public final static int SYSTEM_CLASS = 2;
+
+    public final static int NATIVE_LOCAL = 3;
+    public final static int NATIVE_STATIC = 4;
+    public final static int THREAD_BLOCK = 5;
+    public final static int BUSY_MONITOR = 6;
+    public final static int JAVA_LOCAL = 7;
+    public final static int NATIVE_STACK = 8;
+    public final static int JAVA_STATIC = 9;
+
+
+    public Root(long id, long refererId, int type, String description) {
+        this(id, refererId, type, description, null);
+    }
+
+
+    public Root(long id, long refererId, int type, String description,
+                StackTrace stackTrace) {
+        this.id = id;
+        this.refererId = refererId;
+        this.type = type;
+        this.description = description;
+        this.stackTrace = stackTrace;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getIdString() {
+        return Misc.toHex(id);
+    }
+
+    public String getDescription() {
+        if ("".equals(description)) {
+            return getTypeName() + " Reference";
+        } else {
+            return description;
+        }
+    }
+
+    /**
+     * Return type.  We guarantee that more interesting roots will have
+     * a type that is numerically higher.
+     */
+    public int getType() {
+        return type;
+    }
+
+    public String getTypeName() {
+        switch(type) {
+            case INVALID_TYPE:          return "Invalid (?!?)";
+            case UNKNOWN:               return "Unknown";
+            case SYSTEM_CLASS:          return "System Class";
+            case NATIVE_LOCAL:          return "JNI Local";
+            case NATIVE_STATIC:         return "JNI Global";
+            case THREAD_BLOCK:          return "Thread Block";
+            case BUSY_MONITOR:          return "Busy Monitor";
+            case JAVA_LOCAL:            return "Java Local";
+            case NATIVE_STACK:          return "Native Stack (possibly Java local)";
+            case JAVA_STATIC:           return "Java Static";
+            default:                    return "??";
+        }
+    }
+
+    /**
+     * Given two Root instances, return the one that is most interesting.
+     */
+    public Root mostInteresting(Root other) {
+        if (other.type > this.type) {
+            return other;
+        } else {
+            return this;
+        }
+    }
+
+    /**
+     * Get the object that's responsible for this root, if there is one.
+     * This will be null, a Thread object, or a Class object.
+     */
+    public JavaHeapObject getReferer() {
+        return referer;
+    }
+
+    /**
+     * @return the stack trace responsible for this root, or null if there
+     * is none.
+     */
+    public StackTrace getStackTrace() {
+        return stackTrace;
+    }
+
+    /**
+     * @return The index of this root in Snapshot.roots
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    void resolve(Snapshot ss) {
+        if (refererId != 0) {
+            referer = ss.findThing(refererId);
+        }
+        if (stackTrace != null) {
+            stackTrace.resolve(ss);
+        }
+    }
+
+    void setIndex(int i) {
+        index = i;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/Snapshot.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+import java.lang.ref.SoftReference;
+import java.util.*;
+
+import jdk.test.lib.hprof.parser.ReadBuffer;
+import jdk.test.lib.hprof.util.Misc;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+/**
+ * Represents a snapshot of the Java objects in the VM at one instant.
+ * This is the top-level "model" object read out of a single .hprof or .bod
+ * file.
+ */
+
+public class Snapshot implements AutoCloseable {
+
+    public static final long SMALL_ID_MASK = 0x0FFFFFFFFL;
+    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+    private static final JavaField[] EMPTY_FIELD_ARRAY = new JavaField[0];
+    private static final JavaStatic[] EMPTY_STATIC_ARRAY = new JavaStatic[0];
+
+    // all heap objects
+    private Hashtable<Number, JavaHeapObject> heapObjects =
+                 new Hashtable<Number, JavaHeapObject>();
+
+    private Hashtable<Number, JavaClass> fakeClasses =
+                 new Hashtable<Number, JavaClass>();
+
+    // all Roots in this Snapshot
+    private Vector<Root> roots = new Vector<Root>();
+
+    // name-to-class map
+    private Map<String, JavaClass> classes =
+                 new TreeMap<String, JavaClass>();
+
+    // new objects relative to a baseline - lazily initialized
+    private volatile Map<JavaHeapObject, Boolean> newObjects;
+
+    // allocation site traces for all objects - lazily initialized
+    private volatile Map<JavaHeapObject, StackTrace> siteTraces;
+
+    // object-to-Root map for all objects
+    private Map<JavaHeapObject, Root> rootsMap =
+                 new HashMap<JavaHeapObject, Root>();
+
+    // soft cache of finalizeable objects - lazily initialized
+    private SoftReference<Vector<?>> finalizablesCache;
+
+    // represents null reference
+    private JavaThing nullThing;
+
+    // java.lang.ref.Reference class
+    private JavaClass weakReferenceClass;
+    // index of 'referent' field in java.lang.ref.Reference class
+    private int referentFieldIndex;
+
+    // java.lang.Class class
+    private JavaClass javaLangClass;
+    // java.lang.String class
+    private JavaClass javaLangString;
+    // java.lang.ClassLoader class
+    private JavaClass javaLangClassLoader;
+
+    // unknown "other" array class
+    private volatile JavaClass otherArrayType;
+    // Stuff to exclude from reachable query
+    private ReachableExcludes reachableExcludes;
+    // the underlying heap dump buffer
+    private ReadBuffer readBuf;
+
+    // True iff some heap objects have isNew set
+    private boolean hasNewSet;
+    private boolean unresolvedObjectsOK;
+
+    // whether object array instances have new style class or
+    // old style (element) class.
+    private boolean newStyleArrayClass;
+
+    // object id size in the heap dump
+    private int identifierSize = 4;
+
+    // minimum object size - accounts for object header in
+    // most Java virtual machines - we assume 2 identifierSize
+    // (which is true for Sun's hotspot JVM).
+    private int minimumObjectSize;
+
+    public Snapshot(ReadBuffer buf) {
+        nullThing = new HackJavaValue("<null>", 0);
+        readBuf = buf;
+    }
+
+    public void setSiteTrace(JavaHeapObject obj, StackTrace trace) {
+        if (trace != null && trace.getFrames().length != 0) {
+            initSiteTraces();
+            siteTraces.put(obj, trace);
+        }
+    }
+
+    public StackTrace getSiteTrace(JavaHeapObject obj) {
+        if (siteTraces != null) {
+            return siteTraces.get(obj);
+        } else {
+            return null;
+        }
+    }
+
+    public void setNewStyleArrayClass(boolean value) {
+        newStyleArrayClass = value;
+    }
+
+    public boolean isNewStyleArrayClass() {
+        return newStyleArrayClass;
+    }
+
+    public void setIdentifierSize(int size) {
+        identifierSize = size;
+        minimumObjectSize = 2 * size;
+    }
+
+    public int getIdentifierSize() {
+        return identifierSize;
+    }
+
+    public int getMinimumObjectSize() {
+        return minimumObjectSize;
+    }
+
+    public void addHeapObject(long id, JavaHeapObject ho) {
+        heapObjects.put(makeId(id), ho);
+    }
+
+    public void addRoot(Root r) {
+        r.setIndex(roots.size());
+        roots.addElement(r);
+    }
+
+    public void addClass(long id, JavaClass c) {
+        addHeapObject(id, c);
+        putInClassesMap(c);
+    }
+
+    JavaClass addFakeInstanceClass(long classID, int instSize) {
+        // Create a fake class name based on ID.
+        String name = "unknown-class<@" + Misc.toHex(classID) + ">";
+
+        // Create fake fields convering the given instance size.
+        // Create as many as int type fields and for the left over
+        // size create byte type fields.
+        int numInts = instSize / 4;
+        int numBytes = instSize % 4;
+        JavaField[] fields = new JavaField[numInts + numBytes];
+        int i;
+        for (i = 0; i < numInts; i++) {
+            fields[i] = new JavaField("unknown-field-" + i, "I");
+        }
+        for (i = 0; i < numBytes; i++) {
+            fields[i + numInts] = new JavaField("unknown-field-" +
+                                                i + numInts, "B");
+        }
+
+        // Create fake instance class
+        JavaClass c = new JavaClass(name, 0, 0, 0, 0, fields,
+                                 EMPTY_STATIC_ARRAY, instSize);
+        // Add the class
+        addFakeClass(makeId(classID), c);
+        return c;
+    }
+
+
+    /**
+     * @return true iff it's possible that some JavaThing instances might
+     *          isNew set
+     *
+     * @see JavaThing.isNew()
+     */
+    public boolean getHasNewSet() {
+        return hasNewSet;
+    }
+
+    //
+    // Used in the body of resolve()
+    //
+    private static class MyVisitor extends AbstractJavaHeapObjectVisitor {
+        JavaHeapObject t;
+        public void visit(JavaHeapObject other) {
+            other.addReferenceFrom(t);
+        }
+    }
+
+    // To show heap parsing progress, we print a '.' after this limit
+    private static final int DOT_LIMIT = 5000;
+
+    /**
+     * Called after reading complete, to initialize the structure
+     */
+    public void resolve(boolean calculateRefs) {
+        System.out.println("Resolving " + heapObjects.size() + " objects...");
+
+        // First, resolve the classes.  All classes must be resolved before
+        // we try any objects, because the objects use classes in their
+        // resolution.
+        javaLangClass = findClass("java.lang.Class");
+        if (javaLangClass == null) {
+            System.out.println("WARNING:  hprof file does not include java.lang.Class!");
+            javaLangClass = new JavaClass("java.lang.Class", 0, 0, 0, 0,
+                                 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
+            addFakeClass(javaLangClass);
+        }
+        javaLangString = findClass("java.lang.String");
+        if (javaLangString == null) {
+            System.out.println("WARNING:  hprof file does not include java.lang.String!");
+            javaLangString = new JavaClass("java.lang.String", 0, 0, 0, 0,
+                                 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
+            addFakeClass(javaLangString);
+        }
+        javaLangClassLoader = findClass("java.lang.ClassLoader");
+        if (javaLangClassLoader == null) {
+            System.out.println("WARNING:  hprof file does not include java.lang.ClassLoader!");
+            javaLangClassLoader = new JavaClass("java.lang.ClassLoader", 0, 0, 0, 0,
+                                 EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
+            addFakeClass(javaLangClassLoader);
+        }
+
+        for (JavaHeapObject t : heapObjects.values()) {
+            if (t instanceof JavaClass) {
+                t.resolve(this);
+            }
+        }
+
+        // Now, resolve everything else.
+        for (JavaHeapObject t : heapObjects.values()) {
+            if (!(t instanceof JavaClass)) {
+                t.resolve(this);
+            }
+        }
+
+        heapObjects.putAll(fakeClasses);
+        fakeClasses.clear();
+
+        weakReferenceClass = findClass("java.lang.ref.Reference");
+        referentFieldIndex = 0;
+        if (weakReferenceClass != null)  {
+            JavaField[] fields = weakReferenceClass.getFieldsForInstance();
+            for (int i = 0; i < fields.length; i++) {
+                if ("referent".equals(fields[i].getName())) {
+                    referentFieldIndex = i;
+                    break;
+                }
+            }
+        }
+
+        if (calculateRefs) {
+            calculateReferencesToObjects();
+            System.out.print("Eliminating duplicate references");
+            System.out.flush();
+            // This println refers to the *next* step
+        }
+        int count = 0;
+        for (JavaHeapObject t : heapObjects.values()) {
+            t.setupReferers();
+            ++count;
+            if (calculateRefs && count % DOT_LIMIT == 0) {
+                System.out.print(".");
+                System.out.flush();
+            }
+        }
+        if (calculateRefs) {
+            System.out.println("");
+        }
+
+        // to ensure that Iterator.remove() on getClasses()
+        // result will throw exception..
+        classes = Collections.unmodifiableMap(classes);
+    }
+
+    private void calculateReferencesToObjects() {
+        System.out.print("Chasing references, expect "
+                         + (heapObjects.size() / DOT_LIMIT) + " dots");
+        System.out.flush();
+        int count = 0;
+        MyVisitor visitor = new MyVisitor();
+        for (JavaHeapObject t : heapObjects.values()) {
+            visitor.t = t;
+            // call addReferenceFrom(t) on all objects t references:
+            t.visitReferencedObjects(visitor);
+            ++count;
+            if (count % DOT_LIMIT == 0) {
+                System.out.print(".");
+                System.out.flush();
+            }
+        }
+        System.out.println();
+        for (Root r : roots) {
+            r.resolve(this);
+            JavaHeapObject t = findThing(r.getId());
+            if (t != null) {
+                t.addReferenceFromRoot(r);
+            }
+        }
+    }
+
+    public void markNewRelativeTo(Snapshot baseline) {
+        hasNewSet = true;
+        for (JavaHeapObject t : heapObjects.values()) {
+            boolean isNew;
+            long thingID = t.getId();
+            if (thingID == 0L || thingID == -1L) {
+                isNew = false;
+            } else {
+                JavaThing other = baseline.findThing(t.getId());
+                if (other == null) {
+                    isNew = true;
+                } else {
+                    isNew = !t.isSameTypeAs(other);
+                }
+            }
+            t.setNew(isNew);
+        }
+    }
+
+    public Enumeration<JavaHeapObject> getThings() {
+        return heapObjects.elements();
+    }
+
+
+    public JavaHeapObject findThing(long id) {
+        Number idObj = makeId(id);
+        JavaHeapObject jho = heapObjects.get(idObj);
+        return jho != null? jho : fakeClasses.get(idObj);
+    }
+
+    public JavaHeapObject findThing(String id) {
+        return findThing(Misc.parseHex(id));
+    }
+
+    public JavaClass findClass(String name) {
+        if (name.startsWith("0x")) {
+            return (JavaClass) findThing(name);
+        } else {
+            return classes.get(name);
+        }
+    }
+
+    /**
+     * Return an Iterator of all of the classes in this snapshot.
+     **/
+    public Iterator<JavaClass> getClasses() {
+        // note that because classes is a TreeMap
+        // classes are already sorted by name
+        return classes.values().iterator();
+    }
+
+    public JavaClass[] getClassesArray() {
+        JavaClass[] res = new JavaClass[classes.size()];
+        classes.values().toArray(res);
+        return res;
+    }
+
+    public synchronized Enumeration<?> getFinalizerObjects() {
+        Vector<?> obj;
+        if (finalizablesCache != null &&
+            (obj = finalizablesCache.get()) != null) {
+            return obj.elements();
+        }
+
+        JavaClass clazz = findClass("java.lang.ref.Finalizer");
+        JavaObject queue = (JavaObject) clazz.getStaticField("queue");
+        JavaThing tmp = queue.getField("head");
+        Vector<JavaHeapObject> finalizables = new Vector<JavaHeapObject>();
+        if (tmp != getNullThing()) {
+            JavaObject head = (JavaObject) tmp;
+            while (true) {
+                JavaHeapObject referent = (JavaHeapObject) head.getField("referent");
+                JavaThing next = head.getField("next");
+                if (next == getNullThing() || next.equals(head)) {
+                    break;
+                }
+                head = (JavaObject) next;
+                finalizables.add(referent);
+            }
+        }
+        finalizablesCache = new SoftReference<Vector<?>>(finalizables);
+        return finalizables.elements();
+    }
+
+    public Enumeration<Root> getRoots() {
+        return roots.elements();
+    }
+
+    public Root[] getRootsArray() {
+        Root[] res = new Root[roots.size()];
+        roots.toArray(res);
+        return res;
+    }
+
+    public Root getRootAt(int i) {
+        return roots.elementAt(i);
+    }
+
+    public ReferenceChain[]
+    rootsetReferencesTo(JavaHeapObject target, boolean includeWeak) {
+        Vector<ReferenceChain> fifo = new Vector<ReferenceChain>();  // This is slow... A real fifo would help
+            // Must be a fifo to go breadth-first
+        Hashtable<JavaHeapObject, JavaHeapObject> visited = new Hashtable<JavaHeapObject, JavaHeapObject>();
+        // Objects are added here right after being added to fifo.
+        Vector<ReferenceChain> result = new Vector<ReferenceChain>();
+        visited.put(target, target);
+        fifo.addElement(new ReferenceChain(target, null));
+
+        while (fifo.size() > 0) {
+            ReferenceChain chain = fifo.elementAt(0);
+            fifo.removeElementAt(0);
+            JavaHeapObject curr = chain.getObj();
+            if (curr.getRoot() != null) {
+                result.addElement(chain);
+                // Even though curr is in the rootset, we want to explore its
+                // referers, because they might be more interesting.
+            }
+            Enumeration<JavaThing> referers = curr.getReferers();
+            while (referers.hasMoreElements()) {
+                JavaHeapObject t = (JavaHeapObject) referers.nextElement();
+                if (t != null && !visited.containsKey(t)) {
+                    if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) {
+                        visited.put(t, t);
+                        fifo.addElement(new ReferenceChain(t, chain));
+                    }
+                }
+            }
+        }
+
+        ReferenceChain[] realResult = new ReferenceChain[result.size()];
+        for (int i = 0; i < result.size(); i++) {
+            realResult[i] =  result.elementAt(i);
+        }
+        return realResult;
+    }
+
+    public boolean getUnresolvedObjectsOK() {
+        return unresolvedObjectsOK;
+    }
+
+    public void setUnresolvedObjectsOK(boolean v) {
+        unresolvedObjectsOK = v;
+    }
+
+    public JavaClass getWeakReferenceClass() {
+        return weakReferenceClass;
+    }
+
+    public int getReferentFieldIndex() {
+        return referentFieldIndex;
+    }
+
+    public JavaThing getNullThing() {
+        return nullThing;
+    }
+
+    public void setReachableExcludes(ReachableExcludes e) {
+        reachableExcludes = e;
+    }
+
+    public ReachableExcludes getReachableExcludes() {
+        return reachableExcludes;
+    }
+
+    // package privates
+    void addReferenceFromRoot(Root r, JavaHeapObject obj) {
+        Root root = rootsMap.get(obj);
+        if (root == null) {
+            rootsMap.put(obj, r);
+        } else {
+            rootsMap.put(obj, root.mostInteresting(r));
+        }
+    }
+
+    Root getRoot(JavaHeapObject obj) {
+        return rootsMap.get(obj);
+    }
+
+    JavaClass getJavaLangClass() {
+        return javaLangClass;
+    }
+
+    JavaClass getJavaLangString() {
+        return javaLangString;
+    }
+
+    JavaClass getJavaLangClassLoader() {
+        return javaLangClassLoader;
+    }
+
+    JavaClass getOtherArrayType() {
+        if (otherArrayType == null) {
+            synchronized(this) {
+                if (otherArrayType == null) {
+                    addFakeClass(new JavaClass("[<other>", 0, 0, 0, 0,
+                                     EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY,
+                                     0));
+                    otherArrayType = findClass("[<other>");
+                }
+            }
+        }
+        return otherArrayType;
+    }
+
+    JavaClass getArrayClass(String elementSignature) {
+        JavaClass clazz;
+        synchronized(classes) {
+            clazz = findClass("[" + elementSignature);
+            if (clazz == null) {
+                clazz = new JavaClass("[" + elementSignature, 0, 0, 0, 0,
+                                   EMPTY_FIELD_ARRAY, EMPTY_STATIC_ARRAY, 0);
+                addFakeClass(clazz);
+                // This is needed because the JDK only creates Class structures
+                // for array element types, not the arrays themselves.  For
+                // analysis, though, we need to pretend that there's a
+                // JavaClass for the array type, too.
+            }
+        }
+        return clazz;
+    }
+
+    ReadBuffer getReadBuffer() {
+        return readBuf;
+    }
+
+    void setNew(JavaHeapObject obj, boolean isNew) {
+        initNewObjects();
+        if (isNew) {
+            newObjects.put(obj, Boolean.TRUE);
+        }
+    }
+
+    boolean isNew(JavaHeapObject obj) {
+        if (newObjects != null) {
+            return newObjects.get(obj) != null;
+        } else {
+            return false;
+        }
+    }
+
+    // Internals only below this point
+    private Number makeId(long id) {
+        if (identifierSize == 4) {
+            return (int)id;
+        } else {
+            return id;
+        }
+    }
+
+    private void putInClassesMap(JavaClass c) {
+        String name = c.getName();
+        if (classes.containsKey(name)) {
+            // more than one class can have the same name
+            // if so, create a unique name by appending
+            // - and id string to it.
+            name += "-" + c.getIdString();
+        }
+        classes.put(c.getName(), c);
+    }
+
+    private void addFakeClass(JavaClass c) {
+        putInClassesMap(c);
+        c.resolve(this);
+    }
+
+    private void addFakeClass(Number id, JavaClass c) {
+        fakeClasses.put(id, c);
+        addFakeClass(c);
+    }
+
+    private synchronized void initNewObjects() {
+        if (newObjects == null) {
+            synchronized (this) {
+                if (newObjects == null) {
+                    newObjects = new HashMap<JavaHeapObject, Boolean>();
+                }
+            }
+        }
+    }
+
+    private synchronized void initSiteTraces() {
+        if (siteTraces == null) {
+            synchronized (this) {
+                if (siteTraces == null) {
+                    siteTraces = new HashMap<JavaHeapObject, StackTrace>();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        readBuf.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/StackFrame.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+
+/**
+ * Represents a stack frame.
+ */
+
+public class StackFrame {
+
+    //
+    // Values for the lineNumber data member.  These are the same
+    // as the values used in the JDK 1.2 heap dump file.
+    //
+    public final static int LINE_NUMBER_UNKNOWN = -1;
+    public final static int LINE_NUMBER_COMPILED = -2;
+    public final static int LINE_NUMBER_NATIVE = -3;
+
+    private String methodName;
+    private String methodSignature;
+    private String className;
+    private String sourceFileName;
+    private int lineNumber;
+
+    public StackFrame(String methodName, String methodSignature,
+                      String className, String sourceFileName, int lineNumber) {
+        this.methodName = methodName;
+        this.methodSignature = methodSignature;
+        this.className = className;
+        this.sourceFileName = sourceFileName;
+        this.lineNumber = lineNumber;
+    }
+
+    public void resolve(Snapshot snapshot) {
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public String getMethodSignature() {
+        return methodSignature;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public String getSourceFileName() {
+        return sourceFileName;
+    }
+
+    public String getLineNumber() {
+        switch(lineNumber) {
+            case LINE_NUMBER_UNKNOWN:
+                return "(unknown)";
+            case LINE_NUMBER_COMPILED:
+                return "(compiled method)";
+            case LINE_NUMBER_NATIVE:
+                return "(native method)";
+            default:
+                return Integer.toString(lineNumber, 10);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/model/StackTrace.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.model;
+
+/**
+ *
+ * @author      Bill Foote
+ */
+
+
+/**
+ * Represents a stack trace, that is, an ordered collection of stack frames.
+ */
+
+public class StackTrace {
+
+    private StackFrame[] frames;
+
+    public StackTrace(StackFrame[] frames) {
+        this.frames = frames;
+    }
+
+    /**
+     * @param depth.  The minimum reasonable depth is 1.
+     *
+     * @return a (possibly new) StackTrace that is limited to depth.
+     */
+    public StackTrace traceForDepth(int depth) {
+        if (depth >= frames.length) {
+            return this;
+        } else {
+            StackFrame[] f = new StackFrame[depth];
+            System.arraycopy(frames, 0, f, 0, depth);
+            return new StackTrace(f);
+        }
+    }
+
+    public void resolve(Snapshot snapshot) {
+        for (int i = 0; i < frames.length; i++) {
+            frames[i].resolve(snapshot);
+        }
+    }
+
+    public StackFrame[] getFrames() {
+        return frames;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/parser/FileReadBuffer.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.parser;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Implementation of ReadBuffer using a RandomAccessFile
+ *
+ * @author A. Sundararajan
+ */
+class FileReadBuffer implements ReadBuffer {
+    // underlying file to read
+    private RandomAccessFile file;
+
+    FileReadBuffer(RandomAccessFile file) {
+        this.file = file;
+    }
+
+    private void seek(long pos) throws IOException {
+        file.getChannel().position(pos);
+    }
+
+    public synchronized void get(long pos, byte[] buf) throws IOException {
+        seek(pos);
+        file.read(buf);
+    }
+
+    public synchronized char getChar(long pos) throws IOException {
+        seek(pos);
+        return file.readChar();
+    }
+
+    public synchronized byte getByte(long pos) throws IOException {
+        seek(pos);
+        return (byte) file.read();
+    }
+
+    public synchronized short getShort(long pos) throws IOException {
+        seek(pos);
+        return file.readShort();
+    }
+
+    public synchronized int getInt(long pos) throws IOException {
+        seek(pos);
+        return file.readInt();
+    }
+
+    public synchronized long getLong(long pos) throws IOException {
+        seek(pos);
+        return file.readLong();
+    }
+
+    @Override
+    public void close() throws Exception {
+        file.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/hprof/parser/HprofReader.java	Fri Sep 02 02:40:58 2016 +0000
@@ -0,0 +1,899 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * The Original Code is HAT. The Initial Developer of the
+ * Original Code is Bill Foote, with contributions from others
+ * at JavaSoft/Sun.
+ */
+
+package jdk.test.lib.hprof.parser;
+
+import java.io.*;
+import java.util.Date;
+import java.util.Hashtable;
+import jdk.test.lib.hprof.model.ArrayTypeCodes;
+import jdk.test.lib.hprof.model.*;
+
+/**
+ * Object that's used to read a hprof file.
+ *
+ * @author      Bill Foote
+ */
+
+public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes {
+
+    final static int MAGIC_NUMBER = 0x4a415641;
+    // That's "JAVA", the first part of "JAVA PROFILE ..."
+    private final static String[] VERSIONS = {
+            " PROFILE 1.0\0",
+            " PROFILE 1.0.1\0",
+            " PROFILE 1.0.2\0",
+    };
+
+    private final static int VERSION_JDK12BETA3 = 0;
+    private final static int VERSION_JDK12BETA4 = 1;
+    private final static int VERSION_JDK6       = 2;
+    // These version numbers are indices into VERSIONS.  The instance data
+    // member version is set to one of these, and it drives decisions when
+    // reading the file.
+    //
+    // Version 1.0.1 added HPROF_GC_PRIM_ARRAY_DUMP, which requires no
+    // version-sensitive parsing.
+    //
+    // Version 1.0.1 changed the type of a constant pool entry from a signature
+    // to a typecode.
+    //
+    // Version 1.0.2 added HPROF_HEAP_DUMP_SEGMENT and HPROF_HEAP_DUMP_END
+    // to allow a large heap to be dumped as a sequence of heap dump segments.
+    //
+    // The HPROF agent in J2SE 1.2 through to 5.0 generate a version 1.0.1
+    // file. In Java SE 6.0 the version is either 1.0.1 or 1.0.2 depending on
+    // the size of the heap (normally it will be 1.0.1 but for multi-GB
+    // heaps the heap dump will not fit in a HPROF_HEAP_DUMP record so the
+    // dump is generated as version 1.0.2).
+
+    //
+    // Record types:
+    //
+    static final int HPROF_UTF8          = 0x01;
+    static final int HPROF_LOAD_CLASS    = 0x02;
+    static final int HPROF_UNLOAD_CLASS  = 0x03;
+    static final int HPROF_FRAME         = 0x04;
+    static final int HPROF_TRACE         = 0x05;
+    static final int HPROF_ALLOC_SITES   = 0x06;
+    static final int HPROF_HEAP_SUMMARY  = 0x07;
+
+    static final int HPROF_START_THREAD  = 0x0a;
+    static final int HPROF_END_THREAD    = 0x0b;
+
+    static final int HPROF_HEAP_DUMP     = 0x0c;
+
+    static final int HPROF_CPU_SAMPLES   = 0x0d;
+    static final int HPROF_CONTROL_SETTINGS = 0x0e;
+    static final int HPROF_LOCKSTATS_WAIT_TIME = 0x10;
+    static final int HPROF_LOCKSTATS_HOLD_TIME = 0x11;
+
+    static final int HPROF_GC_ROOT_UNKNOWN       = 0xff;
+    static final int HPROF_GC_ROOT_JNI_GLOBAL    = 0x01;
+    static final int HPROF_GC_ROOT_JNI_LOCAL     = 0x02;
+    static final int HPROF_GC_ROOT_JAVA_FRAME    = 0x03;
+    static final int HPROF_GC_ROOT_NATIVE_STACK  = 0x04;
+    static final int HPROF_GC_ROOT_STICKY_CLASS  = 0x05;
+    static final int HPROF_GC_ROOT_THREAD_BLOCK  = 0x06;
+    static final int HPROF_GC_ROOT_MONITOR_USED  = 0x07;
+    static final int HPROF_GC_ROOT_THREAD_OBJ    = 0x08;
+
+    static final int HPROF_GC_CLASS_DUMP         = 0x20;
+    static final int HPROF_GC_INSTANCE_DUMP      = 0x21;
+    static final int HPROF_GC_OBJ_ARRAY_DUMP         = 0x22;
+    static final int HPROF_GC_PRIM_ARRAY_DUMP         = 0x23;
+
+    static final int HPROF_HEAP_DUMP_SEGMENT     = 0x1c;
+    static final int HPROF_HEAP_DUMP_END         = 0x2c;
+
+    private final static int T_CLASS = 2;
+
+    private int version;        // The version of .hprof being read
+
+    private int debugLevel;
+    private long currPos;        // Current position in the file
+
+    private int dumpsToSkip;
+    private boolean callStack;  // If true, read the call stack of objects
+
+    private int identifierSize;         // Size, in bytes, of identifiers.
+    private Hashtable<Long, String> names;
+
+    // Hashtable<Integer, ThreadObject>, used to map the thread sequence number
+    // (aka "serial number") to the thread object ID for
+    // HPROF_GC_ROOT_THREAD_OBJ.  ThreadObject is a trivial inner class,
+    // at the end of this file.
+    private Hashtable<Integer, ThreadObject> threadObjects;
+
+    // Hashtable<Long, String>, maps class object ID to class name
+    // (with / converted to .)
+    private Hashtable<Long, String> classNameFromObjectID;
+
+    // Hashtable<Integer, Integer>, maps class serial # to class object ID
+    private Hashtable<Integer, String> classNameFromSerialNo;
+
+    // Hashtable<Long, StackFrame> maps stack frame ID to StackFrame.
+    // Null if we're not tracking them.
+    private Hashtable<Long, StackFrame> stackFrames;
+
+    // Hashtable<Integer, StackTrace> maps stack frame ID to StackTrace
+    // Null if we're not tracking them.
+    private Hashtable<Integer, StackTrace> stackTraces;
+
+    private Snapshot snapshot;
+
+    public HprofReader(String fileName, PositionDataInputStream in,
+                       int dumpNumber, boolean callStack, int debugLevel)
+                       throws IOException {
+        super(in);
+        RandomAccessFile file = new RandomAccessFile(fileName, "r");
+        this.snapshot = new Snapshot(MappedReadBuffer.create(file));
+        this.dumpsToSkip = dumpNumber - 1;
+        this.callStack = callStack;
+        this.debugLevel = debugLevel;
+        names = new Hashtable<Long, String>();
+        threadObjects = new Hashtable<Integer, ThreadObject>(43);
+        classNameFromObjectID = new Hashtable<Long, String>();
+        if (callStack) {
+            stackFrames = new Hashtable<Long, StackFrame>(43);
+            stackTraces = new Hashtable<Integer, StackTrace>(43);
+            classNameFromSerialNo = new Hashtable<Integer, String>();
+        }
+    }
+
+    public Snapshot read() throws IOException {
+        currPos = 4;    // 4 because of the magic number
+        version = readVersionHeader();
+        identifierSize = in.readInt();
+        snapshot.setIdentifierSize(identifierSize);
+        if (version >= VERSION_JDK12BETA4) {
+            snapshot.setNewStyleArrayClass(true);
+        } else {
+            snapshot.setNewStyleArrayClass(false);
+        }
+
+        currPos += 4;
+        if (identifierSize != 4 && identifierSize != 8) {
+            throw new IOException("I'm sorry, but I can't deal with an identifier size of " + identifierSize + ".  I can only deal with 4 or 8.");
+        }
+        System.out.println("Dump file created " + (new Date(in.readLong())));
+        currPos += 8;
+
+        for (;;) {
+            int type;
+            try {
+                type = in.readUnsignedByte();
+            } catch (EOFException ignored) {
+                break;
+            }
+            in.readInt();       // Timestamp of this record
+            // Length of record: readInt() will return negative value for record
+            // length >2GB.  so store 32bit value in long to keep it unsigned.
+            long length = in.readInt() & 0xffffffffL;
+            if (debugLevel > 0) {
+                System.out.println("Read record type " + type
+                                   + ", length " + length
+                                   + " at position " + toHex(currPos));
+            }
+            if (length < 0) {
+                throw new IOException("Bad record length of " + length
+                                      + " at byte " + toHex(currPos+5)
+                                      + " of file.");
+            }
+            currPos += 9 + length;
+            switch (type) {
+                case HPROF_UTF8: {
+                    long id = readID();
+                    byte[] chars = new byte[(int)length - identifierSize];
+                    in.readFully(chars);
+                    names.put(id, new String(chars));
+                    break;
+                }
+                case HPROF_LOAD_CLASS: {
+                    int serialNo = in.readInt();        // Not used
+                    long classID = readID();
+                    int stackTraceSerialNo = in.readInt();
+                    long classNameID = readID();
+                    Long classIdI = classID;
+                    String nm = getNameFromID(classNameID).replace('/', '.');
+                    classNameFromObjectID.put(classIdI, nm);
+                    if (classNameFromSerialNo != null) {
+                        classNameFromSerialNo.put(serialNo, nm);
+                    }
+                    break;
+                }
+
+                case HPROF_HEAP_DUMP: {
+                    if (dumpsToSkip <= 0) {
+                        try {
+                            readHeapDump(length, currPos);
+                        } catch (EOFException exp) {
+                            handleEOF(exp, snapshot);
+                        }
+                        if (debugLevel > 0) {
+                            System.out.println("    Finished processing instances in heap dump.");
+                        }
+                        return snapshot;
+                    } else {
+                        dumpsToSkip--;
+                        skipBytes(length);
+                    }
+                    break;
+                }
+
+                case HPROF_HEAP_DUMP_END: {
+                    if (version >= VERSION_JDK6) {
+                        if (dumpsToSkip <= 0) {
+                            skipBytes(length);  // should be no-op
+                            return snapshot;
+                        } else {
+                            // skip this dump (of the end record for a sequence of dump segments)
+                            dumpsToSkip--;
+                        }
+                    } else {
+                        // HPROF_HEAP_DUMP_END only recognized in >= 1.0.2
+                        warn("Ignoring unrecognized record type " + type);
+                    }
+                    skipBytes(length);  // should be no-op
+                    break;
+                }
+
+                case HPROF_HEAP_DUMP_SEGMENT: {
+                    if (version >= VERSION_JDK6) {
+                        if (dumpsToSkip <= 0) {
+                            try {
+                                // read the dump segment
+                                readHeapDump(length, currPos);
+                            } catch (EOFException exp) {
+                                handleEOF(exp, snapshot);
+                            }
+                        } else {
+                            // all segments comprising the heap dump will be skipped
+                            skipBytes(length);
+                        }
+                    } else {
+                        // HPROF_HEAP_DUMP_SEGMENT only recognized in >= 1.0.2
+                        warn("Ignoring unrecognized record type " + type);
+                        skipBytes(length);
+                    }
+                    break;
+                }
+
+                case HPROF_FRAME: {
+                    if (stackFrames == null) {
+                        skipBytes(length);
+                    } else {
+                        long id = readID();
+                        String methodName = getNameFromID(readID());
+                        String methodSig = getNameFromID(readID());
+                        String sourceFile = getNameFromID(readID());
+                        int classSer = in.readInt();
+                        String className = classNameFromSerialNo.get(classSer);
+                        int lineNumber = in.readInt();
+                        if (lineNumber < StackFrame.LINE_NUMBER_NATIVE) {
+                            warn("Weird stack frame line number:  " + lineNumber);
+                            lineNumber = StackFrame.LINE_NUMBER_UNKNOWN;
+                        }
+                        stackFrames.put(id,
+                                        new StackFrame(methodName, methodSig,
+                                                       className, sourceFile,
+                                                       lineNumber));
+                    }
+                    break;
+                }
+                case HPROF_TRACE: {
+                    if (stackTraces == null) {
+                        skipBytes(length);
+                    } else {
+                        int serialNo = in.readInt();
+                        int threadSeq = in.readInt();   // Not used
+                        StackFrame[] frames = new StackFrame[in.readInt()];
+                        for (int i = 0; i < frames.length; i++) {
+                            long fid = readID();
+                            frames[i] = stackFrames.get(fid);
+                            if (frames[i] == null) {
+                                throw new IOException("Stack frame " + toHex(fid) + " not found");
+                            }
+                        }
+                        stackTraces.put(serialNo,
+                                        new StackTrace(frames));
+                    }
+                    break;
+                }
+                case HPROF_UNLOAD_CLASS:
+                case HPROF_ALLOC_SITES:
+                case HPROF_START_THREAD:
+                case HPROF_END_THREAD:
+                case HPROF_HEAP_SUMMARY:
+                case HPROF_CPU_SAMPLES:
+                case HPROF_CONTROL_SETTINGS:
+                case HPROF_LOCKSTATS_WAIT_TIME:
+                case HPROF_LOCKSTATS_HOLD_TIME:
+                {
+                    // Ignore these record types
+                    skipBytes(length);
+                    break;
+                }
+                default: {
+                    skipBytes(length);
+                    warn("Ignoring unrecognized record type " + type);
+                }
+            }
+        }
+
+        return snapshot;
+    }
+
+    private void skipBytes(long length) throws IOException {
+        while (length > 0) {
+            long skipped = in.skip(length);
+            if (skipped == 0) {
+                // EOF or other problem, throw exception
+                throw new EOFException("Couldn't skip enough bytes");
+            }
+            length -= skipped;
+        }