Merge
authorduke
Wed, 05 Jul 2017 20:34:33 +0200
changeset 30638 3709a72237d2
parent 30637 725914ee5f0c (current diff)
parent 30550 a3ea54d69bd0 (diff)
child 30693 d52dccf017c0
Merge
--- a/.hgtags-top-repo	Thu May 21 16:19:49 2015 -0700
+++ b/.hgtags-top-repo	Wed Jul 05 20:34:33 2017 +0200
@@ -307,3 +307,4 @@
 105d045a69174d870b69bfe471b3f2d05a9f8ecc jdk9-b62
 0b32ed628fa60e4ab99fb0b5866d648e16231f17 jdk9-b63
 82cf9aab9a83e41c8194ba01af9666afdb856cbe jdk9-b64
+7c31f9d7b932f7924f1258d52885b1c7c3e078c2 jdk9-b65
--- a/common/bin/compare_exceptions.sh.incl	Thu May 21 16:19:49 2015 -0700
+++ b/common/bin/compare_exceptions.sh.incl	Wed Jul 05 20:34:33 2017 +0200
@@ -83,7 +83,6 @@
 ./bin/jcmd
 ./bin/jconsole
 ./bin/jdb
-./bin/jhat
 ./bin/jimage
 ./bin/jinfo
 ./bin/jjs
@@ -163,7 +162,6 @@
 ./bin/jcmd
 ./bin/jconsole
 ./bin/jdb
-./bin/jhat
 ./bin/jimage
 ./bin/jinfo
 ./bin/jjs
@@ -284,7 +282,6 @@
 ./bin/jcmd
 ./bin/jconsole
 ./bin/jdb
-./bin/jhat
 ./bin/jimage
 ./bin/jinfo
 ./bin/jjs
@@ -420,7 +417,6 @@
 ./bin/jcmd
 ./bin/jconsole
 ./bin/jdb
-./bin/jhat
 ./bin/jimage
 ./bin/jinfo
 ./bin/jjs
@@ -499,7 +495,6 @@
 ./bin/jcmd.exe
 ./bin/jconsole.exe
 ./bin/jdb.exe
-./bin/jhat.exe
 ./bin/jimage.exe
 ./bin/jinfo.exe
 ./bin/jjs.exe
@@ -579,7 +574,6 @@
 ./bin/jcmd
 ./bin/jconsole
 ./bin/jdb
-./bin/jhat
 ./bin/jimage
 ./bin/jinfo
 ./bin/jjs
--- a/make/Images.gmk	Thu May 21 16:19:49 2015 -0700
+++ b/make/Images.gmk	Wed Jul 05 20:34:33 2017 +0200
@@ -213,7 +213,6 @@
       jcmd.1 \
       jdb.1 \
       jdeps.1 \
-      jhat.1 \
       jinfo.1 \
       jmap.1 \
       jps.1 \
--- a/make/JrtfsJar.gmk	Thu May 21 16:19:49 2015 -0700
+++ b/make/JrtfsJar.gmk	Wed Jul 05 20:34:33 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,20 @@
 include $(SPEC)
 include MakeBase.gmk
 include JavaCompilation.gmk
+include TextFileProcessing.gmk
+
+# This rule will be depended on due to the MANIFEST line
+$(eval $(call SetupTextFileProcessing, BUILD_JAVA_MANIFEST, \
+  SOURCE_FILES := $(JDK_TOPDIR)/make/data/mainmanifest/manifest.mf, \
+  OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf, \
+  REPLACEMENTS := \
+      @@RELEASE@@ => $(RELEASE) ; \
+      @@COMPANY_NAME@@ => $(COMPANY_NAME) , \
+))
 
 $(eval $(call SetupArchive,JRTFS_JAR, , \
     SRCS := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes, \
     JAR := $(SUPPORT_OUTPUTDIR)/jrt-fs.jar, \
-    MANIFEST := $(JDK_TOPDIR)/make/data/mainmanifest/manifest.mf))
+    MANIFEST := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf))
 
 all: $(JRTFS_JAR)
--- a/make/common/JavaCompilation.gmk	Thu May 21 16:19:49 2015 -0700
+++ b/make/common/JavaCompilation.gmk	Wed Jul 05 20:34:33 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -265,7 +265,7 @@
   endif
 
   # Include all variables of significance in the vardeps file
-  $1_VARDEPS := $(JAR) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) $(RELEASE) $(COMPANY_NAME) \
+  $1_VARDEPS := $(JAR) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) \
       $$($1_JARMAIN) $$($1_EXTRA_MANIFEST_ATTR)
   $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$(dir $$($1_JAR))_the.$$($1_JARNAME).vardeps)
 
@@ -280,8 +280,7 @@
         # potential changes.
 	$$(if $$(filter $$($1_VARDEPS_FILE) $$($1_MANIFEST), $$?), \
 	  $$(if $$($1_MANIFEST), \
-	    $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \
-	        -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" $$($1_MANIFEST) > $$($1_MANIFEST_FILE) $$(NEWLINE) \
+	    $(CP) $$($1_MANIFEST) $$($1_MANIFEST_FILE) $$(NEWLINE) \
 	  , \
 	    $(RM) $$($1_MANIFEST_FILE) && $(TOUCH) $$($1_MANIFEST_FILE) $$(NEWLINE)) \
 	  $$(if $$($1_JARMAIN), \
--- a/make/jprt.properties	Thu May 21 16:19:49 2015 -0700
+++ b/make/jprt.properties	Wed Jul 05 20:34:33 2017 +0200
@@ -428,15 +428,6 @@
   windows_i586_6.2-*-default-hotspot_basicvmtest,                       \
   windows_x64_6.2-*-default-hotspot_basicvmtest
   
-my.make.rule.test.targets.hotspot.internalvmtests=			\
-  solaris_sparcv9_5.11-fastdebug-c2-hotspot_internalvmtests,		\
-  solaris_x64_5.11-fastdebug-c2-hotspot_internalvmtests,		\
-  linux_i586_2.6-fastdebug-c2-hotspot_internalvmtests,			\
-  linux_x64_2.6-fastdebug-c2-hotspot_internalvmtests,			\
-  macosx_x64_10.9-fastdebug-c2-hotspot_internalvmtests,			\
-  windows_i586_6.2-fastdebug-c2-hotspot_internalvmtests,		\
-  windows_x64_6.2-fastdebug-c2-hotspot_internalvmtests
-
 my.make.rule.test.targets.hotspot.reg.group=				\
   solaris_sparcv9_5.11-fastdebug-c2-GROUP,				\
   solaris_x64_5.11-fastdebug-c2-GROUP,					\
@@ -450,7 +441,6 @@
 
 # Hotspot jtreg tests
 my.make.rule.test.targets.hotspot.reg=						\
-  ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_wbapitest},	\
   ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_1},	\
   ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_2},	\
   ${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_compiler_3},	\
@@ -466,7 +456,6 @@
 # Other Makefile based Hotspot tests
 my.make.rule.test.targets.hotspot.other=                                \
   ${my.make.rule.test.targets.hotspot.basicvmtests},                    \
-  ${my.make.rule.test.targets.hotspot.internalvmtests},                 \
   ${my.additional.make.rule.test.targets.hotspot.other}
 
 # All the makefile based tests to run
--- a/modules.xml	Thu May 21 16:19:49 2015 -0700
+++ b/modules.xml	Wed Jul 05 20:34:33 2017 +0200
@@ -2,7 +2,7 @@
 
 <!--
 
-   Copyright (c) 2014, 2015 Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
    This code is free software; you can redistribute it and/or modify it
@@ -216,19 +216,19 @@
     </export>
     <export>
       <name>jdk.internal.jimage</name>
-      <to>jdk.dev</to> 
+      <to>jdk.dev</to>
     </export>
     <export>
       <name>jdk.internal.org.objectweb.asm</name>
+      <to>java.instrument</to>
       <to>jdk.jfr</to>
       <to>jdk.scripting.nashorn</to>
-      <to>java.instrument</to>
     </export>
     <export>
       <name>jdk.internal.org.objectweb.asm.commons</name>
+      <to>java.instrument</to>
       <to>jdk.jfr</to>
       <to>jdk.scripting.nashorn</to>
-      <to>java.instrument</to>
     </export>
     <export>
       <name>jdk.internal.org.objectweb.asm.signature</name>
@@ -236,19 +236,20 @@
     </export>
     <export>
       <name>jdk.internal.org.objectweb.asm.tree</name>
+      <to>java.instrument</to>
       <to>jdk.jfr</to>
-      <to>java.instrument</to>
     </export>
     <export>
       <name>jdk.internal.org.objectweb.asm.util</name>
+      <to>java.instrument</to>
       <to>jdk.jfr</to>
       <to>jdk.scripting.nashorn</to>
-      <to>java.instrument</to>
     </export>
     <export>
       <name>sun.misc</name>
       <to>java.corba</to>
       <to>java.desktop</to>
+      <to>java.instrument</to>
       <to>java.logging</to>
       <to>java.management</to>
       <to>java.naming</to>
@@ -266,6 +267,7 @@
       <to>jdk.jartool</to>
       <to>jdk.jconsole</to>
       <to>jdk.jvmstat</to>
+      <to>jdk.management.resource</to>
       <to>jdk.pack200</to>
       <to>jdk.security.auth</to>
       <to>jdk.security.jgss</to>
@@ -301,6 +303,7 @@
       <to>java.management</to>
       <to>jdk.crypto.pkcs11</to>
       <to>jdk.crypto.ucrypto</to>
+      <to>jdk.management.resource</to>
       <to>jdk.sctp</to>
     </export>
     <export>
@@ -311,11 +314,11 @@
     <export>
       <name>sun.reflect</name>
       <to>java.corba</to>
+      <to>java.instrument</to>
       <to>java.logging</to>
       <to>java.sql</to>
       <to>java.sql.rowset</to>
       <to>jdk.scripting.nashorn</to>
-      <to>java.instrument</to>
     </export>
     <export>
       <name>sun.reflect.annotation</name>
@@ -774,6 +777,7 @@
     <export>
       <name>jdk.internal.instrumentation</name>
       <to>jdk.jfr</to>
+      <to>jdk.management.resource</to>
     </export>
   </module>
   <module>
--- a/test/lib/Makefile	Thu May 21 16:19:49 2015 -0700
+++ b/test/lib/Makefile	Wed Jul 05 20:34:33 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -41,25 +41,38 @@
 JAVAC = $(JDK_HOME)/bin/javac
 JAR = $(JDK_HOME)/bin/jar
 
-SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+WB_SRC_FILES = $(shell find $(SRC_DIR)/sun/hotspot -name '*.java')
+SHARE_SRC_FILES = $(shell find $(SRC_DIR)/share/classes -name '*.java')
 
-.PHONY: filelist clean cleantmp
+.PHONY: wb.filelist share.filelist clean cleantmp
 
-all: wb.jar cleantmp
+all: wb.jar test-lib.jar cleantmp
 
-wb.jar: filelist
+wb.jar: wb.filelist
 	@mkdir -p $(OUTPUT_DIR)
-	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @filelist
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @wb.filelist
 	$(JAR) cf wb.jar -C $(OUTPUT_DIR) .
 	@rm -rf $(OUTPUT_DIR)
 
-filelist: $(SRC_FILES)
+wb.filelist: $(WB_SRC_FILES)
 	@rm -f $@
-	@echo $(SRC_FILES) > $@
+	@echo $(WB_SRC_FILES) > $@
+
+test-lib.jar: share.filelist
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @share.filelist
+	$(JAR) cf test-lib.jar -C $(OUTPUT_DIR) .
+	@rm -rf $(OUTPUT_DIR)
+
+share.filelist: $(SHARE_SRC_FILES)
+	@rm -f $@
+	@echo $(SHARE_SRC_FILES) > $@
 
 clean: cleantmp
 	@rm -rf wb.jar
+	@rm -rf test-list.jar
 
 cleantmp:
-	@rm -rf filelist
+	@rm -rf wb.filelist
+	@rm -rf share.filelist
 	@rm -rf $(BUILD_DIR)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/HprofParser.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact 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/share/classes/jdk/test/lib/hprof/README	Wed Jul 05 20:34:33 2017 +0200
@@ -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/share/classes/jdk/test/lib/hprof/model/AbstractJavaHeapObjectVisitor.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/ArrayTypeCodes.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/HackJavaValue.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaBoolean.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaByte.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaChar.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaClass.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaDouble.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaField.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaFloat.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaHeapObject.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaHeapObjectVisitor.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaInt.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaLazyReadObject.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaLong.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaObject.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaObjectArray.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaObjectRef.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaShort.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaStatic.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaThing.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaValue.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/JavaValueArray.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/ReachableExcludes.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/ReachableExcludesImpl.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/ReachableObjects.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/ReferenceChain.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/Root.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/Snapshot.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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");
+        if (weakReferenceClass == null)  {      // JDK 1.1.x
+            weakReferenceClass = findClass("sun.misc.Ref");
+            referentFieldIndex = 0;
+        } else {
+            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/share/classes/jdk/test/lib/hprof/model/StackFrame.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/model/StackTrace.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/parser/FileReadBuffer.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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/share/classes/jdk/test/lib/hprof/parser/HprofReader.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 {
+        in.skipBytes((int)length);
+    }
+
+    private int readVersionHeader() throws IOException {
+        int candidatesLeft = VERSIONS.length;
+        boolean[] matched = new boolean[VERSIONS.length];
+        for (int i = 0; i < candidatesLeft; i++) {
+            matched[i] = true;
+        }
+
+        int pos = 0;
+        while (candidatesLeft > 0) {
+            char c = (char) in.readByte();
+            currPos++;
+            for (int i = 0; i < VERSIONS.length; i++) {
+                if (matched[i]) {
+                    if (c != VERSIONS[i].charAt(pos)) {   // Not matched
+                        matched[i] = false;
+                        --candidatesLeft;
+                    } else if (pos == VERSIONS[i].length() - 1) {  // Full match
+                        return i;
+                    }
+                }
+            }
+            ++pos;
+        }
+        throw new IOException("Version string not recognized at byte " + (pos+3));
+    }
+
+    private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException {
+        while (bytesLeft > 0) {
+            int type = in.readUnsignedByte();
+            if (debugLevel > 0) {
+                System.out.println("    Read heap sub-record type " + type
+                                   + " at position "
+                                   + toHex(posAtEnd - bytesLeft));
+            }
+            bytesLeft--;
+            switch(type) {
+                case HPROF_GC_ROOT_UNKNOWN: {
+                    long id = readID();
+                    bytesLeft -= identifierSize;
+                    snapshot.addRoot(new Root(id, 0, Root.UNKNOWN, ""));
+                    break;
+                }
+                case HPROF_GC_ROOT_THREAD_OBJ: {
+                    long id = readID();
+                    int threadSeq = in.readInt();
+                    int stackSeq = in.readInt();
+                    bytesLeft -= identifierSize + 8;
+                    threadObjects.put(threadSeq,
+                                      new ThreadObject(id, stackSeq));
+                    break;
+                }
+                case HPROF_GC_ROOT_JNI_GLOBAL: {
+                    long id = readID();
+                    long globalRefId = readID();        // Ignored, for now
+                    bytesLeft -= 2*identifierSize;
+                    snapshot.addRoot(new Root(id, 0, Root.NATIVE_STATIC, ""));
+                    break;
+                }
+                case HPROF_GC_ROOT_JNI_LOCAL: {
+                    long id = readID();
+                    int threadSeq = in.readInt();
+                    int depth = in.readInt();
+                    bytesLeft -= identifierSize + 8;
+                    ThreadObject to = getThreadObjectFromSequence(threadSeq);
+                    StackTrace st = getStackTraceFromSerial(to.stackSeq);
+                    if (st != null) {
+                        st = st.traceForDepth(depth+1);
+                    }
+                    snapshot.addRoot(new Root(id, to.threadId,
+                                              Root.NATIVE_LOCAL, "", st));
+                    break;
+                }
+                case HPROF_GC_ROOT_JAVA_FRAME: {
+                    long id = readID();
+                    int threadSeq = in.readInt();
+                    int depth = in.readInt();
+                    bytesLeft -= identifierSize + 8;
+                    ThreadObject to = getThreadObjectFromSequence(threadSeq);
+                    StackTrace st = getStackTraceFromSerial(to.stackSeq);
+                    if (st != null) {
+                        st = st.traceForDepth(depth+1);
+                    }
+                    snapshot.addRoot(new Root(id, to.threadId,
+                                              Root.JAVA_LOCAL, "", st));
+                    break;
+                }
+                case HPROF_GC_ROOT_NATIVE_STACK: {
+                    long id = readID();
+                    int threadSeq = in.readInt();
+                    bytesLeft -= identifierSize + 4;
+                    ThreadObject to = getThreadObjectFromSequence(threadSeq);
+                    StackTrace st = getStackTraceFromSerial(to.stackSeq);
+                    snapshot.addRoot(new Root(id, to.threadId,
+                                              Root.NATIVE_STACK, "", st));
+                    break;
+                }
+                case HPROF_GC_ROOT_STICKY_CLASS: {
+                    long id = readID();
+                    bytesLeft -= identifierSize;
+                    snapshot.addRoot(new Root(id, 0, Root.SYSTEM_CLASS, ""));
+                    break;
+                }
+                case HPROF_GC_ROOT_THREAD_BLOCK: {
+                    long id = readID();
+                    int threadSeq = in.readInt();
+                    bytesLeft -= identifierSize + 4;
+                    ThreadObject to = getThreadObjectFromSequence(threadSeq);
+                    StackTrace st = getStackTraceFromSerial(to.stackSeq);
+                    snapshot.addRoot(new Root(id, to.threadId,
+                                     Root.THREAD_BLOCK, "", st));
+                    break;
+                }
+                case HPROF_GC_ROOT_MONITOR_USED: {
+                    long id = readID();
+                    bytesLeft -= identifierSize;
+                    snapshot.addRoot(new Root(id, 0, Root.BUSY_MONITOR, ""));
+                    break;
+                }
+                case HPROF_GC_CLASS_DUMP: {
+                    int bytesRead = readClass();
+                    bytesLeft -= bytesRead;
+                    break;
+                }
+                case HPROF_GC_INSTANCE_DUMP: {
+                    int bytesRead = readInstance();
+                    bytesLeft -= bytesRead;
+                    break;
+                }
+                case HPROF_GC_OBJ_ARRAY_DUMP: {
+                    int bytesRead = readArray(false);
+                    bytesLeft -= bytesRead;
+                    break;
+                }
+                case HPROF_GC_PRIM_ARRAY_DUMP: {
+                    int bytesRead = readArray(true);
+                    bytesLeft -= bytesRead;
+                    break;
+                }
+                default: {
+                    throw new IOException("Unrecognized heap dump sub-record type:  " + type);
+                }
+            }
+        }
+        if (bytesLeft != 0) {
+            warn("Error reading heap dump or heap dump segment:  Byte count is " + bytesLeft + " instead of 0");
+            skipBytes(bytesLeft);
+        }
+        if (debugLevel > 0) {
+            System.out.println("    Finished heap sub-records.");
+        }
+    }
+
+    private long readID() throws IOException {
+        return (identifierSize == 4)?
+            (Snapshot.SMALL_ID_MASK & (long)in.readInt()) : in.readLong();
+    }
+
+    //
+    // Read a java value.  If result is non-null, it's expected to be an
+    // array of one element.  We use it to fake multiple return values.
+    // @returns the number of bytes read
+    //
+    private int readValue(JavaThing[] resultArr) throws IOException {
+        byte type = in.readByte();
+        return 1 + readValueForType(type, resultArr);
+    }
+
+    private int readValueForType(byte type, JavaThing[] resultArr)
+            throws IOException {
+        if (version >= VERSION_JDK12BETA4) {
+            type = signatureFromTypeId(type);
+        }
+        return readValueForTypeSignature(type, resultArr);
+    }
+
+    private int readValueForTypeSignature(byte type, JavaThing[] resultArr)
+            throws IOException {
+        switch (type) {
+            case '[':
+            case 'L': {
+                long id = readID();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaObjectRef(id);
+                }
+                return identifierSize;
+            }
+            case 'Z': {
+                int b = in.readByte();
+                if (b != 0 && b != 1) {
+                    warn("Illegal boolean value read");
+                }
+                if (resultArr != null) {
+                    resultArr[0] = new JavaBoolean(b != 0);
+                }
+                return 1;
+            }
+            case 'B': {
+                byte b = in.readByte();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaByte(b);
+                }
+                return 1;
+            }
+            case 'S': {
+                short s = in.readShort();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaShort(s);
+                }
+                return 2;
+            }
+            case 'C': {
+                char ch = in.readChar();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaChar(ch);
+                }
+                return 2;
+            }
+            case 'I': {
+                int val = in.readInt();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaInt(val);
+                }
+                return 4;
+            }
+            case 'J': {
+                long val = in.readLong();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaLong(val);
+                }
+                return 8;
+            }
+            case 'F': {
+                float val = in.readFloat();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaFloat(val);
+                }
+                return 4;
+            }
+            case 'D': {
+                double val = in.readDouble();
+                if (resultArr != null) {
+                    resultArr[0] = new JavaDouble(val);
+                }
+                return 8;
+            }
+            default: {
+                throw new IOException("Bad value signature:  " + type);
+            }
+        }
+    }
+
+    private ThreadObject getThreadObjectFromSequence(int threadSeq)
+            throws IOException {
+        ThreadObject to = threadObjects.get(threadSeq);
+        if (to == null) {
+            throw new IOException("Thread " + threadSeq +
+                                  " not found for JNI local ref");
+        }
+        return to;
+    }
+
+    private String getNameFromID(long id) throws IOException {
+        return getNameFromID(Long.valueOf(id));
+    }
+
+    private String getNameFromID(Long id) throws IOException {
+        if (id.longValue() == 0L) {
+            return "";
+        }
+        String result = names.get(id);
+        if (result == null) {
+            warn("Name not found at " + toHex(id.longValue()));
+            return "unresolved name " + toHex(id.longValue());
+        }
+        return result;
+    }
+
+    private StackTrace getStackTraceFromSerial(int ser) throws IOException {
+        if (stackTraces == null) {
+            return null;
+        }
+        StackTrace result = stackTraces.get(ser);
+        if (result == null) {
+            warn("Stack trace not found for serial # " + ser);
+        }
+        return result;
+    }
+
+    //
+    // Handle a HPROF_GC_CLASS_DUMP
+    // Return number of bytes read
+    //
+    private int readClass() throws IOException {
+        long id = readID();
+        StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
+        long superId = readID();
+        long classLoaderId = readID();
+        long signersId = readID();
+        long protDomainId = readID();
+        long reserved1 = readID();
+        long reserved2 = readID();
+        int instanceSize = in.readInt();
+        int bytesRead = 7 * identifierSize + 8;
+
+        int numConstPoolEntries = in.readUnsignedShort();
+        bytesRead += 2;
+        for (int i = 0; i < numConstPoolEntries; i++) {
+            int index = in.readUnsignedShort(); // unused
+            bytesRead += 2;
+            bytesRead += readValue(null);       // We ignore the values
+        }
+
+        int numStatics = in.readUnsignedShort();
+        bytesRead += 2;
+        JavaThing[] valueBin = new JavaThing[1];
+        JavaStatic[] statics = new JavaStatic[numStatics];
+        for (int i = 0; i < numStatics; i++) {
+            long nameId = readID();
+            bytesRead += identifierSize;
+            byte type = in.readByte();
+            bytesRead++;
+            bytesRead += readValueForType(type, valueBin);
+            String fieldName = getNameFromID(nameId);
+            if (version >= VERSION_JDK12BETA4) {
+                type = signatureFromTypeId(type);
+            }
+            String signature = "" + ((char) type);
+            JavaField f = new JavaField(fieldName, signature);
+            statics[i] = new JavaStatic(f, valueBin[0]);
+        }
+
+        int numFields = in.readUnsignedShort();
+        bytesRead += 2;
+        JavaField[] fields = new JavaField[numFields];
+        for (int i = 0; i < numFields; i++) {
+            long nameId = readID();
+            bytesRead += identifierSize;
+            byte type = in.readByte();
+            bytesRead++;
+            String fieldName = getNameFromID(nameId);
+            if (version >= VERSION_JDK12BETA4) {
+                type = signatureFromTypeId(type);
+            }
+            String signature = "" + ((char) type);
+            fields[i] = new JavaField(fieldName, signature);
+        }
+        String name = classNameFromObjectID.get(id);
+        if (name == null) {
+            warn("Class name not found for " + toHex(id));
+            name = "unknown-name@" + toHex(id);
+        }
+        JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId,
+                                    protDomainId, fields, statics,
+                                    instanceSize);
+        snapshot.addClass(id, c);
+        snapshot.setSiteTrace(c, stackTrace);
+
+        return bytesRead;
+    }
+
+    private String toHex(long addr) {
+        return jdk.test.lib.hprof.util.Misc.toHex(addr);
+    }
+
+    //
+    // Handle a HPROF_GC_INSTANCE_DUMP
+    // Return number of bytes read
+    //
+    private int readInstance() throws IOException {
+        long start = in.position();
+        long id = readID();
+        StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
+        long classID = readID();
+        int bytesFollowing = in.readInt();
+        int bytesRead = (2 * identifierSize) + 8 + bytesFollowing;
+        JavaObject jobj = new JavaObject(classID, start);
+        skipBytes(bytesFollowing);
+        snapshot.addHeapObject(id, jobj);
+        snapshot.setSiteTrace(jobj, stackTrace);
+        return bytesRead;
+    }
+
+    //
+    // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP
+    // Return number of bytes read
+    //
+    private int readArray(boolean isPrimitive) throws IOException {
+        long start = in.position();
+        long id = readID();
+        StackTrace stackTrace = getStackTraceFromSerial(in.readInt());
+        int num = in.readInt();
+        int bytesRead = identifierSize + 8;
+        long elementClassID;
+        if (isPrimitive) {
+            elementClassID = in.readByte();
+            bytesRead++;
+        } else {
+            elementClassID = readID();
+            bytesRead += identifierSize;
+        }
+
+        // Check for primitive arrays:
+        byte primitiveSignature = 0x00;
+        int elSize = 0;
+        if (isPrimitive || version < VERSION_JDK12BETA4) {
+            switch ((int)elementClassID) {
+                case T_BOOLEAN: {
+                    primitiveSignature = (byte) 'Z';
+                    elSize = 1;
+                    break;
+                }
+                case T_CHAR: {
+                    primitiveSignature = (byte) 'C';
+                    elSize = 2;
+                    break;
+                }
+                case T_FLOAT: {
+                    primitiveSignature = (byte) 'F';
+                    elSize = 4;
+                    break;
+                }
+                case T_DOUBLE: {
+                    primitiveSignature = (byte) 'D';
+                    elSize = 8;
+                    break;
+                }
+                case T_BYTE: {
+                    primitiveSignature = (byte) 'B';
+                    elSize = 1;
+                    break;
+                }
+                case T_SHORT: {
+                    primitiveSignature = (byte) 'S';
+                    elSize = 2;
+                    break;
+                }
+                case T_INT: {
+                    primitiveSignature = (byte) 'I';
+                    elSize = 4;
+                    break;
+                }
+                case T_LONG: {
+                    primitiveSignature = (byte) 'J';
+                    elSize = 8;
+                    break;
+                }
+            }
+            if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) {
+                throw new IOException("Unrecognized typecode:  "
+                                        + elementClassID);
+            }
+        }
+        if (primitiveSignature != 0x00) {
+            int size = elSize * num;
+            bytesRead += size;
+            JavaValueArray va = new JavaValueArray(primitiveSignature, start);
+            skipBytes(size);
+            snapshot.addHeapObject(id, va);
+            snapshot.setSiteTrace(va, stackTrace);
+        } else {
+            int sz = num * identifierSize;
+            bytesRead += sz;
+            JavaObjectArray arr = new JavaObjectArray(elementClassID, start);
+            skipBytes(sz);
+            snapshot.addHeapObject(id, arr);
+            snapshot.setSiteTrace(arr, stackTrace);
+        }
+        return bytesRead;
+    }
+
+    private byte signatureFromTypeId(byte typeId) throws IOException {
+        switch (typeId) {
+            case T_CLASS: {
+                return (byte) 'L';
+            }
+            case T_BOOLEAN: {
+                return (byte) 'Z';
+            }
+            case T_CHAR: {
+                return (byte) 'C';
+            }
+            case T_FLOAT: {
+                return (byte) 'F';
+            }
+            case T_DOUBLE: {
+                return (byte) 'D';
+            }
+            case T_BYTE: {
+                return (byte) 'B';
+            }
+            case T_SHORT: {
+                return (byte) 'S';
+            }
+            case T_INT: {
+                return (byte) 'I';
+            }
+            case T_LONG: {
+                return (byte) 'J';
+            }
+            default: {
+                throw new IOException("Invalid type id of " + typeId);
+            }
+        }
+    }
+
+    private void handleEOF(EOFException exp, Snapshot snapshot) {
+        if (debugLevel > 0) {
+            exp.printStackTrace();
+        }
+        warn("Unexpected EOF. Will miss information...");
+        // we have EOF, we have to tolerate missing references
+        snapshot.setUnresolvedObjectsOK(true);
+    }
+
+    private void warn(String msg) {
+        System.out.println("WARNING: " + msg);
+    }
+
+    //
+    // A trivial data-holder class for HPROF_GC_ROOT_THREAD_OBJ.
+    //
+    private class ThreadObject {
+
+        long threadId;
+        int stackSeq;
+
+        ThreadObject(long threadId, int stackSeq) {
+            this.threadId = threadId;
+            this.stackSeq = stackSeq;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/parser/MappedReadBuffer.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+/**
+ * Implementation of ReadBuffer using mapped file buffer
+ *
+ * @author A. Sundararajan
+ */
+class MappedReadBuffer implements ReadBuffer {
+    private MappedByteBuffer buf;
+    private RandomAccessFile file;
+
+    MappedReadBuffer(RandomAccessFile file, MappedByteBuffer buf) {
+        this.file = file;
+        this.buf = buf;
+    }
+
+    /**
+     * Factory method to create correct ReadBuffer for a given file.
+     *
+     * The initial purpose of this method was to choose how to read hprof file for parsing
+     * depending on the size of the file and the system property 'jhat.disableFileMap':
+     * "If file size is more than 2 GB and when file mapping is configured (default),
+     * use mapped file reader".
+     *
+     * However, it has been discovered a problem with this approach.
+     * Creating java.nio.MappedByteBuffer from inside the test leads to hprof file
+     * is locked on Windows until test process dies since there is no good way to
+     * release this resource.
+     *
+     * java.nio.MappedByteBuffer will be used only if 'jhat.enableFileMap' is set to true.
+     * Per default 'jhat.enableFileMap' is not set.
+     */
+    static ReadBuffer create(RandomAccessFile file) throws IOException {
+        if (canUseFileMap()) {
+            MappedByteBuffer buf;
+            try {
+                FileChannel ch = file.getChannel();
+                long size = ch.size();
+                buf = ch.map(FileChannel.MapMode.READ_ONLY, 0, size);
+                ch.close();
+                return new MappedReadBuffer(file, buf);
+            } catch (IOException exp) {
+                exp.printStackTrace();
+                System.err.println("File mapping failed, will use direct read");
+                // fall through
+            }
+        } // else fall through
+        return new FileReadBuffer(file);
+    }
+
+    /**
+     * Set system property 'jhat.enableFileMap' to 'true' to enable file mapping.
+     */
+    private static boolean canUseFileMap() {
+        String prop = System.getProperty("jhat.enableFileMap");
+        return prop != null && prop.equals("true");
+    }
+
+    private void seek(long pos) throws IOException {
+        assert pos <= Integer.MAX_VALUE :  "position overflow";
+        buf.position((int)pos);
+    }
+
+    public synchronized void get(long pos, byte[] res) throws IOException {
+        seek(pos);
+        buf.get(res);
+    }
+
+    public synchronized char getChar(long pos) throws IOException {
+        seek(pos);
+        return buf.getChar();
+    }
+
+    public synchronized byte getByte(long pos) throws IOException {
+        seek(pos);
+        return buf.get();
+    }
+
+    public synchronized short getShort(long pos) throws IOException {
+        seek(pos);
+        return buf.getShort();
+    }
+
+    public synchronized int getInt(long pos) throws IOException {
+        seek(pos);
+        return buf.getInt();
+    }
+
+    public synchronized long getLong(long pos) throws IOException {
+        seek(pos);
+        return buf.getLong();
+    }
+
+    @Override
+    public void close() throws Exception {
+        file.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/parser/PositionDataInputStream.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.DataInputStream;
+import java.io.InputStream;
+
+/**
+ * A DataInputStream that keeps track of total bytes read
+ * (in effect 'position' in stream) so far.
+ *
+ */
+public class PositionDataInputStream extends DataInputStream {
+    public PositionDataInputStream(InputStream in) {
+        super(in instanceof PositionInputStream?
+              in : new PositionInputStream(in));
+    }
+
+    public boolean markSupported() {
+        return false;
+    }
+
+    public void mark(int readLimit) {
+        throw new UnsupportedOperationException("mark");
+    }
+
+    public void reset() {
+        throw new UnsupportedOperationException("reset");
+    }
+
+    public long position() {
+        return ((PositionInputStream)in).position();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/parser/PositionInputStream.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * InputStream that keeps track of total bytes read (in effect
+ * 'position' in stream) from the input stream.
+ *
+ */
+public class PositionInputStream extends FilterInputStream {
+    private long position = 0L;
+
+    public PositionInputStream(InputStream in) {
+        super(in);
+    }
+
+    public int read() throws IOException {
+        int res = super.read();
+        if (res != -1) position++;
+        return res;
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        int res = super.read(b, off, len);
+        if (res != -1) position += res;
+        return res;
+    }
+
+    public long skip(long n) throws IOException {
+        long res = super.skip(n);
+        position += res;
+        return res;
+    }
+
+    public boolean markSupported() {
+        return false;
+    }
+
+    public void mark(int readLimit) {
+        throw new UnsupportedOperationException("mark");
+    }
+
+    public void reset() {
+        throw new UnsupportedOperationException("reset");
+    }
+
+    public long position() {
+        return position;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/parser/ReadBuffer.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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;
+
+/**
+ * Positionable read only buffer
+ *
+ * @author A. Sundararajan
+ */
+public interface ReadBuffer extends AutoCloseable {
+    // read methods - only byte array and int primitive types.
+    // read position has to be specified always.
+    public void  get(long pos, byte[] buf) throws IOException;
+    public char  getChar(long pos) throws IOException;
+    public byte  getByte(long pos) throws IOException;
+    public short getShort(long pos) throws IOException;
+    public int   getInt(long pos) throws IOException;
+    public long  getLong(long pos) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/parser/Reader.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 jdk.test.lib.hprof.model.*;
+
+/**
+ * Abstract base class for reading object dump files.  A reader need not be
+ * thread-safe.
+ *
+ * @author      Bill Foote
+ */
+
+
+public abstract class Reader {
+    protected PositionDataInputStream in;
+
+    protected Reader(PositionDataInputStream in) {
+        this.in = in;
+    }
+
+    /**
+     * Read a snapshot from a data input stream.  It is assumed that the magic
+     * number has already been read.
+     */
+    abstract public Snapshot read() throws IOException;
+
+    /**
+     * Read a snapshot from a file.
+     *
+     * @param heapFile The name of a file containing a heap dump
+     * @param callStack If true, read the call stack of allocaation sites
+     */
+    public static Snapshot readFile(String heapFile, boolean callStack,
+                                    int debugLevel)
+            throws IOException {
+        int dumpNumber = 1;
+        int pos = heapFile.lastIndexOf('#');
+        if (pos > -1) {
+            String num = heapFile.substring(pos+1, heapFile.length());
+            try {
+                dumpNumber = Integer.parseInt(num, 10);
+            } catch (java.lang.NumberFormatException ex) {
+                String msg = "In file name \"" + heapFile
+                             + "\", a dump number was "
+                             + "expected after the :, but \""
+                             + num + "\" was found instead.";
+                System.err.println(msg);
+                throw new IOException(msg);
+            }
+            heapFile = heapFile.substring(0, pos);
+        }
+        try (PositionDataInputStream in = new PositionDataInputStream(
+                new BufferedInputStream(new FileInputStream(heapFile)))) {
+            int i = in.readInt();
+            if (i == HprofReader.MAGIC_NUMBER) {
+                Reader r
+                    = new HprofReader(heapFile, in, dumpNumber,
+                                      callStack, debugLevel);
+                return r.read();
+            } else {
+                throw new IOException("Unrecognized magic number: " + i);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/util/ArraySorter.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.util;
+import java.util.*;
+
+/**
+ * A singleton utility class that sorts an array of objects.
+ * <p>
+ * Use:
+ * <pre>
+ *
+ *  Stuff[] arr = ...;
+ *  ArraySorter.sort(arr, new Comparer() {
+ *      public int compare(Object lhs, Object rhs) {
+ *          return ((String) lhs).compareTo((String) rhs);
+ *      }
+ *  });
+ * </pre>
+ *
+ * @author      Bill Foote
+ */
+
+public class ArraySorter {
+
+    /**
+     * Sort the given array, using c for comparison
+    **/
+    static public void sort(Object[] arr, Comparer c)  {
+        quickSort(arr, c, 0, arr.length-1);
+    }
+
+
+    /**
+     * Sort an array of strings, using String.compareTo()
+    **/
+    static public void sortArrayOfStrings(Object[] arr) {
+        sort(arr, new Comparer() {
+            public int compare(Object lhs, Object rhs) {
+                return ((String) lhs).compareTo((String) rhs);
+            }
+        });
+    }
+
+
+    static private void swap(Object[] arr, int a, int b) {
+        Object tmp = arr[a];
+        arr[a] = arr[b];
+        arr[b] = tmp;
+    }
+
+    //
+    // Sorts arr between from and to, inclusive.  This is a quick, off-the-top-
+    // of-my-head quicksort:  I haven't put any thought into optimizing it.
+    // I _did_ put thought into making sure it's safe (it will always
+    // terminate).  Worst-case it's O(n^2), but it will usually run in
+    // in O(n log n).  It's well-behaved if the list is already sorted,
+    // or nearly so.
+    //
+    static private void quickSort(Object[] arr, Comparer c, int from, int to) {
+        if (to <= from)
+            return;
+        int mid = (from + to) / 2;
+        if (mid != from)
+            swap(arr, mid, from);
+        Object pivot = arr[from];   // Simple-minded, but reasonable
+        int highestBelowPivot = from - 1;
+        int low = from+1;
+        int high = to;
+            // We now move low and high toward each other, maintaining the
+            // invariants:
+            //      arr[i] <= pivot    for all i < low
+            //      arr[i] > pivot     for all i > high
+            // As long as these invariants hold, and every iteration makes
+            // progress, we are safe.
+        while (low <= high) {
+            int cmp = c.compare(arr[low], pivot);
+            if (cmp <= 0) {   // arr[low] <= pivot
+                if (cmp < 0) {
+                    highestBelowPivot = low;
+                }
+                low++;
+            } else {
+                int c2;
+                for (;;) {
+                        // arr[high] > pivot:
+                    c2 = c.compare(arr[high], pivot);
+                    if (c2 > 0) {
+                        high--;
+                        if (low > high) {
+                            break;
+                        }
+                    } else {
+                        break;
+                    }
+                }
+                // At this point, low is never == high, BTW
+                if (low <= high) {
+                    swap(arr, low, high);
+                    if (c2 < 0) {
+                        highestBelowPivot = low;
+                    }
+                    low++;
+                    high--;
+                }
+            }
+        }
+        // At this point, low == high+1
+        // Now we just need to sort from from..highestBelowPivot
+        // and from high+1..to
+        if (highestBelowPivot > from) {
+            // pivot == pivot, so ensure algorithm terminates
+            swap(arr, from, highestBelowPivot);
+            quickSort(arr, c, from, highestBelowPivot-1);
+        }
+        quickSort(arr, c, high+1, to);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/util/Comparer.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.util;
+
+/**
+ * Base class for comparison of two objects.
+ * @see VectorSorter
+ *
+ * @author      Bill Foote
+ */
+
+abstract public class Comparer {
+
+    /**
+     * @return a number <, == or > 0 depending on lhs compared to rhs
+     * @see java.lang.String.compareTo
+    **/
+    abstract public int compare(Object lhs, Object rhs);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/util/CompositeEnumeration.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.util;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+import jdk.test.lib.hprof.model.JavaHeapObject;
+
+public class CompositeEnumeration implements Enumeration<JavaHeapObject> {
+    Enumeration<JavaHeapObject> e1;
+    Enumeration<JavaHeapObject> e2;
+
+    public CompositeEnumeration(Enumeration<JavaHeapObject> e1, Enumeration<JavaHeapObject> e2) {
+        this.e1 = e1;
+        this.e2 = e2;
+    }
+
+    public boolean hasMoreElements() {
+        return e1.hasMoreElements() || e2.hasMoreElements();
+    }
+
+    public JavaHeapObject nextElement() {
+        if (e1.hasMoreElements()) {
+            return e1.nextElement();
+        }
+
+        if (e2.hasMoreElements()) {
+            return e2.nextElement();
+        }
+
+        throw new NoSuchElementException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/util/Misc.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.util;
+import java.util.*;
+
+/**
+ * Miscellaneous functions I couldn't think of a good place to put.
+ *
+ * @author      Bill Foote
+ */
+
+
+public class Misc {
+
+    private static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    public final static String toHex(int addr) {
+        char[] buf = new char[8];
+        int i = 0;
+        for (int s = 28; s >= 0; s -= 4) {
+            buf[i++] = digits[(addr >> s) & 0xf];
+        }
+        return "0x" + new String(buf);
+    }
+
+    public final static String toHex(long addr) {
+        return "0x" + Long.toHexString(addr);
+    }
+
+    public final static long parseHex(String value) {
+        long result = 0;
+        if (value.length() < 2 || value.charAt(0) != '0' ||
+            value.charAt(1) != 'x') {
+            return -1L;
+        }
+        for(int i = 2; i < value.length(); i++) {
+            result *= 16;
+            char ch = value.charAt(i);
+            if (ch >= '0' && ch <= '9') {
+                result += (ch - '0');
+            } else if (ch >= 'a' && ch <= 'f') {
+                result += (ch - 'a') + 10;
+            } else if (ch >= 'A' && ch <= 'F') {
+                result += (ch - 'A') + 10;
+            } else {
+                throw new NumberFormatException("" + ch
+                                        + " is not a valid hex digit");
+            }
+        }
+        return result;
+    }
+
+    public static String encodeHtml(String str) {
+        final int len = str.length();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            char ch = str.charAt(i);
+            if (ch == '<') {
+                sb.append("&lt;");
+            } else if (ch == '>') {
+                sb.append("&gt;");
+            } else if (ch == '"') {
+                sb.append("&quot;");
+            } else if (ch == '\'') {
+                sb.append("&#039;");
+            } else if (ch == '&') {
+                sb.append("&amp;");
+            } else if (ch < ' ') {
+                sb.append("&#").append((int)ch).append(';');
+            } else {
+                int c = (ch & 0xFFFF);
+                if (c > 127) {
+                    sb.append("&#").append(c).append(';');
+                } else {
+                    sb.append(ch);
+                }
+            }
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/share/classes/jdk/test/lib/hprof/util/VectorSorter.java	Wed Jul 05 20:34:33 2017 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.util;
+import java.util.*;
+
+/**
+ * A singleton utility class that sorts a vector.
+ * <p>
+ * Use:
+ * <pre>
+ *
+ *  Vector v =   <a vector of, say, String objects>;
+ *  VectorSorter.sort(v, new Comparer() {
+ *      public int compare(Object lhs, Object rhs) {
+ *          return ((String) lhs).compareTo((String) rhs);
+ *      }
+ *  });
+ * </pre>
+ *
+ * @author      Bill Foote
+ */
+
+
+public class VectorSorter {
+
+    /**
+     * Sort the given vector, using c for comparison
+    **/
+    static public void sort(Vector<Object> v, Comparer c)  {
+        quickSort(v, c, 0, v.size()-1);
+    }
+
+
+    /**
+     * Sort a vector of strings, using String.compareTo()
+    **/
+    static public void sortVectorOfStrings(Vector<Object> v) {
+        sort(v, new Comparer() {
+            public int compare(Object lhs, Object rhs) {
+                return ((String) lhs).compareTo((String) rhs);
+            }
+        });
+    }
+
+
+    static private void swap(Vector<Object> v, int a, int b) {
+        Object tmp = v.elementAt(a);
+        v.setElementAt(v.elementAt(b), a);
+        v.setElementAt(tmp, b);
+    }
+
+    //
+    // Sorts v between from and to, inclusive.  This is a quick, off-the-top-
+    // of-my-head quicksort:  I haven't put any thought into optimizing it.
+    // I _did_ put thought into making sure it's safe (it will always
+    // terminate).  Worst-case it's O(n^2), but it will usually run in
+    // in O(n log n).  It's well-behaved if the list is already sorted,
+    // or nearly so.
+    //
+    static private void quickSort(Vector<Object> v, Comparer c, int from, int to) {
+        if (to <= from)
+            return;
+        int mid = (from + to) / 2;
+        if (mid != from)
+            swap(v, mid, from);
+        Object pivot = v.elementAt(from);
+                        // Simple-minded, but reasonable
+        int highestBelowPivot = from - 1;
+        int low = from+1;
+        int high = to;
+            // We now move low and high toward eachother, maintaining the
+            // invariants:
+            //      v[i] <= pivot    for all i < low
+            //      v[i] > pivot     for all i > high
+            // As long as these invariants hold, and every iteration makes
+            // progress, we are safe.
+        while (low <= high) {
+            int cmp = c.compare(v.elementAt(low), pivot);
+            if (cmp <= 0) {    // v[low] <= pivot
+                if (cmp < 0) {
+                    highestBelowPivot = low;
+                }
+                low++;
+            } else {
+                int c2;
+                for (;;) {
+                    c2 = c.compare(v.elementAt(high), pivot);
+                        // v[high] > pivot:
+                    if (c2 > 0) {
+                        high--;
+                        if (low > high) {
+                            break;
+                        }
+                    } else {
+                        break;
+                    }
+                }
+                // At this point, low is never == high
+                if (low <= high) {
+                    swap(v, low, high);
+                    if (c2 < 0) {
+                        highestBelowPivot = low;
+                    }
+                    low++;
+                    high--;
+                }
+            }
+        }
+        // Now we just need to sort from from..highestBelowPivot
+        // and from high+1..to
+        if (highestBelowPivot > from) {
+            // pivot == pivot, so ensure algorithm terminates
+            swap(v, from, highestBelowPivot);
+            quickSort(v, c, from, highestBelowPivot-1);
+        }
+        quickSort(v, c, high+1, to);
+    }
+}