8071908: Port internal Diagnostic Command tests and test framework to jtreg
authormiauno
Fri, 30 Jan 2015 20:00:57 +0100
changeset 28821 f7820f311663
parent 28820 1837a69c2a22
child 28823 9c678eaab37e
child 28824 ad5e6cd229c0
8071908: Port internal Diagnostic Command tests and test framework to jtreg Reviewed-by: jbachorik, egahlin, ykantser, mtobiass
hotspot/test/TEST.groups
hotspot/test/serviceability/dcmd/ClassLoaderStatsTest.java
hotspot/test/serviceability/dcmd/DcmdUtil.java
hotspot/test/serviceability/dcmd/DynLibDcmdTest.java
hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java
hotspot/test/serviceability/dcmd/compiler/CodelistTest.java
hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
hotspot/test/serviceability/dcmd/compiler/MethodIdentifierParser.java
hotspot/test/serviceability/dcmd/framework/HelpTest.java
hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java
hotspot/test/serviceability/dcmd/framework/VMVersionTest.java
hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java
hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java
hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java
hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java
hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java
hotspot/test/serviceability/dcmd/gc/RunGCTest.java
hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java
hotspot/test/serviceability/dcmd/thread/PrintTest.java
hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java
hotspot/test/serviceability/dcmd/vm/CommandLineTest.java
hotspot/test/serviceability/dcmd/vm/DynLibsTest.java
hotspot/test/serviceability/dcmd/vm/FlagsTest.java
hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java
hotspot/test/serviceability/dcmd/vm/UptimeTest.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutor.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutorException.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/FileJcmdExecutor.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/JMXExecutor.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/JcmdExecutor.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/MainClassJcmdExecutor.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/PidJcmdExecutor.java
--- a/hotspot/test/TEST.groups	Fri Jan 30 20:20:11 2015 +0100
+++ b/hotspot/test/TEST.groups	Fri Jan 30 20:00:57 2015 +0100
@@ -97,7 +97,7 @@
   runtime/XCheckJniJsig/XCheckJSig.java \
   serviceability/attach/AttachWithStalePidFile.java \
   serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \
-  serviceability/dcmd/DynLibDcmdTest.java
+  serviceability/dcmd/vm/DynLibsTest.java
 
 
 # JRE adds further tests to compact3
--- a/hotspot/test/serviceability/dcmd/ClassLoaderStatsTest.java	Fri Jan 30 20:20:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- *
- * @build ClassLoaderStatsTest DcmdUtil
- * @run main ClassLoaderStatsTest
- */
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.StringReader;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class ClassLoaderStatsTest {
-
-    // ClassLoader         Parent              CLD*               Classes   ChunkSz   BlockSz  Type
-    // 0x00000007c0215928  0x0000000000000000  0x0000000000000000       0         0         0  org.eclipse.osgi.baseadaptor.BaseAdaptor$1
-    // 0x00000007c0009868  0x0000000000000000  0x00007fc52aebcc80       1      6144      3768  sun.reflect.DelegatingClassLoader
-    // 0x00000007c0009868  0x0000000000000000  0x00007fc52b8916d0       1      6144      3688  sun.reflect.DelegatingClassLoader
-    // 0x00000007c0009868  0x00000007c0038ba8  0x00007fc52afb8760       1      6144      3688  sun.reflect.DelegatingClassLoader
-    // 0x00000007c0009868  0x0000000000000000  0x00007fc52afbb1a0       1      6144      3688  sun.reflect.DelegatingClassLoader
-    // 0x0000000000000000  0x0000000000000000  0x00007fc523416070    5019  30060544  29956216  <boot classloader>
-    //                                                                455   1210368    672848   + unsafe anonymous classes
-    // 0x00000007c016b5c8  0x00000007c0038ba8  0x00007fc52a995000       5      8192      5864  org.netbeans.StandardModule$OneModuleClassLoader
-    // 0x00000007c0009868  0x00000007c016b5c8  0x00007fc52ac13640       1      6144      3896  sun.reflect.DelegatingClassLoader
-    // ...
-
-    static Pattern clLine = Pattern.compile("0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*(.*)");
-    static Pattern anonLine = Pattern.compile("\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*.*");
-
-    public static DummyClassLoader dummyloader;
-
-    public static void main(String arg[]) throws Exception {
-
-        // create a classloader and load our special class
-        dummyloader = new DummyClassLoader();
-        Class<?> c = Class.forName("TestClass", true, dummyloader);
-        if (c.getClassLoader() != dummyloader) {
-            throw new RuntimeException("TestClass defined by wrong classloader: " + c.getClassLoader());
-        }
-
-        String result = DcmdUtil.executeDcmd("VM.classloader_stats");
-        BufferedReader r = new BufferedReader(new StringReader(result));
-        String line;
-        while((line = r.readLine()) != null) {
-            Matcher m = clLine.matcher(line);
-            if (m.matches()) {
-                // verify that DummyClassLoader has loaded 1 class and 1 anonymous class
-                if (m.group(4).equals("ClassLoaderStatsTest$DummyClassLoader")) {
-                    System.out.println("line: " + line);
-                    if (!m.group(1).equals("1")) {
-                        throw new Exception("Should have loaded 1 class: " + line);
-                    }
-                    checkPositiveInt(m.group(2));
-                    checkPositiveInt(m.group(3));
-
-                    String next = r.readLine();
-                    System.out.println("next: " + next);
-                    Matcher m1 = anonLine.matcher(next);
-                    m1.matches();
-                    if (!m1.group(1).equals("1")) {
-                        throw new Exception("Should have loaded 1 anonymous class, but found : " + m1.group(1));
-                    }
-                    checkPositiveInt(m1.group(2));
-                    checkPositiveInt(m1.group(3));
-                }
-            }
-        }
-    }
-
-    private static void checkPositiveInt(String s) throws Exception {
-        if (Integer.parseInt(s) <= 0) {
-            throw new Exception("Value should have been > 0: " + s);
-        }
-    }
-
-    public static class DummyClassLoader extends ClassLoader {
-
-        public static final String CLASS_NAME = "TestClass";
-
-        static ByteBuffer readClassFile(String name)
-        {
-            File f = new File(System.getProperty("test.classes", "."),
-                              name);
-            try (FileInputStream fin = new FileInputStream(f);
-                 FileChannel fc = fin.getChannel())
-            {
-                return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
-            } catch (IOException e) {
-                throw new RuntimeException("Can't open file: " + name, e);
-            }
-        }
-
-        protected Class<?> loadClass(String name, boolean resolve)
-            throws ClassNotFoundException
-        {
-            Class<?> c;
-            if (!"TestClass".equals(name)) {
-                c = super.loadClass(name, resolve);
-            } else {
-                // should not delegate to the system class loader
-                c = findClass(name);
-                if (resolve) {
-                    resolveClass(c);
-                }
-            }
-            return c;
-        }
-
-        protected Class<?> findClass(String name)
-            throws ClassNotFoundException
-        {
-            if (!"TestClass".equals(name)) {
-                throw new ClassNotFoundException("Unexpected class: " + name);
-            }
-            return defineClass(name, readClassFile(name + ".class"), null);
-        }
-    } /* DummyClassLoader */
-
-}
-
-class TestClass {
-    static {
-        // force creation of anonymous class (for the lambdaform)
-        Runnable r = () -> System.out.println("Hello");
-        r.run();
-    }
-}
--- a/hotspot/test/serviceability/dcmd/DcmdUtil.java	Fri Jan 30 20:20:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import sun.management.ManagementFactoryHelper;
-
-import com.sun.management.DiagnosticCommandMBean;
-
-public class DcmdUtil
-{
-    public static String executeDcmd(String cmd, String ... args) {
-        DiagnosticCommandMBean dcmd = ManagementFactoryHelper.getDiagnosticCommandMBean();
-        Object[] dcmdArgs = {args};
-        String[] signature = {String[].class.getName()};
-
-        try {
-            System.out.print("> " + cmd + " ");
-            for (String s : args) {
-                System.out.print(s + " ");
-            }
-            System.out.println(":");
-            String result = (String) dcmd.invoke(transform(cmd), dcmdArgs, signature);
-            System.out.println(result);
-            return result;
-        } catch(Exception ex) {
-            ex.printStackTrace();
-        }
-        return null;
-    }
-
-    private static String transform(String name) {
-        StringBuilder sb = new StringBuilder();
-        boolean toLower = true;
-        boolean toUpper = false;
-        for (int i = 0; i < name.length(); i++) {
-            char c = name.charAt(i);
-            if (c == '.' || c == '_') {
-                toLower = false;
-                toUpper = true;
-            } else {
-                if (toUpper) {
-                    toUpper = false;
-                    sb.append(Character.toUpperCase(c));
-                } else if(toLower) {
-                    sb.append(Character.toLowerCase(c));
-                } else {
-                    sb.append(c);
-                }
-            }
-        }
-        return sb.toString();
-    }
-
-}
--- a/hotspot/test/serviceability/dcmd/DynLibDcmdTest.java	Fri Jan 30 20:20:11 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-import java.util.HashSet;
-import java.util.Set;
-import com.oracle.java.testlibrary.Platform;
-
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @summary Test of VM.dynlib diagnostic command via MBean
- * @library /testlibrary
- * @build com.oracle.java.testlibrary.* DcmdUtil
- * @run main DynLibDcmdTest
- */
-
-public class DynLibDcmdTest {
-
-    public static void main(String[] args) throws Exception {
-        String result = DcmdUtil.executeDcmd("VM.dynlibs");
-
-        String osDependentBaseString = null;
-        if (Platform.isAix()) {
-            osDependentBaseString = "lib%s.so";
-        } else if (Platform.isLinux()) {
-            osDependentBaseString = "lib%s.so";
-        } else if (Platform.isOSX()) {
-            osDependentBaseString = "lib%s.dylib";
-        } else if (Platform.isSolaris()) {
-            osDependentBaseString = "lib%s.so";
-        } else if (Platform.isWindows()) {
-            osDependentBaseString = "%s.dll";
-        }
-
-        if (osDependentBaseString == null) {
-            throw new Exception("Unsupported OS");
-        }
-
-        Set<String> expectedContent = new HashSet<>();
-        expectedContent.add(String.format(osDependentBaseString, "jvm"));
-        expectedContent.add(String.format(osDependentBaseString, "java"));
-        expectedContent.add(String.format(osDependentBaseString, "management"));
-
-        for(String expected : expectedContent) {
-            if (!result.contains(expected)) {
-                throw new Exception("Dynamic library list output did not contain the expected string: '" + expected + "'");
-            }
-        }
-    }
-}
--- a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java	Fri Jan 30 20:20:11 2015 +0100
+++ b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -24,17 +24,23 @@
 /*
  * @test CodeCacheTest
  * @bug 8054889
- * @library ..
- * @build DcmdUtil CodeCacheTest
- * @run main/othervm -XX:+SegmentedCodeCache CodeCacheTest
- * @run main/othervm -XX:-SegmentedCodeCache CodeCacheTest
- * @run main/othervm -Xint -XX:+SegmentedCodeCache CodeCacheTest
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng/othervm -XX:+SegmentedCodeCache CodeCacheTest
+ * @run testng/othervm -XX:-SegmentedCodeCache CodeCacheTest
+ * @run testng/othervm -Xint -XX:+SegmentedCodeCache CodeCacheTest
  * @summary Test of diagnostic command Compiler.codecache
  */
 
-import java.io.BufferedReader;
-import java.io.StringReader;
-import java.lang.reflect.Method;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+import java.util.Iterator;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -72,7 +78,7 @@
     private static boolean getFlagBool(String flag, String where) {
       Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where);
       if (!m.find()) {
-        throw new RuntimeException("Could not find value for flag " + flag + " in output string");
+        Assert.fail("Could not find value for flag " + flag + " in output string");
       }
       return m.group(1).equals("true");
     }
@@ -80,16 +86,16 @@
     private static int getFlagInt(String flag, String where) {
       Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where);
       if (!m.find()) {
-        throw new RuntimeException("Could not find value for flag " + flag + " in output string");
+        Assert.fail("Could not find value for flag " + flag + " in output string");
       }
       String match = m.group();
       return Integer.parseInt(match.substring(match.lastIndexOf(" ") + 1, match.length()));
     }
 
-    public static void main(String arg[]) throws Exception {
+    public void run(CommandExecutor executor) {
         // Get number of code cache segments
         int segmentsCount = 0;
-        String flags = DcmdUtil.executeDcmd("VM.flags", "-all");
+        String flags = executor.execute("VM.flags -all").getOutput();
         if (!getFlagBool("SegmentedCodeCache", flags) || !getFlagBool("UseCompiler", flags)) {
           // No segmentation
           segmentsCount = 1;
@@ -102,29 +108,29 @@
         }
 
         // Get output from dcmd (diagnostic command)
-        String result = DcmdUtil.executeDcmd("Compiler.codecache");
-        BufferedReader r = new BufferedReader(new StringReader(result));
+        OutputAnalyzer output = executor.execute("Compiler.codecache");
+        Iterator<String> lines = output.asLines().iterator();
 
         // Validate code cache segments
         String line;
         Matcher m;
         for (int s = 0; s < segmentsCount; ++s) {
           // Validate first line
-          line = r.readLine();
+          line = lines.next();
           m = line1.matcher(line);
           if (m.matches()) {
               for (int i = 2; i <= 5; i++) {
                   int val = Integer.parseInt(m.group(i));
                   if (val < 0) {
-                      throw new Exception("Failed parsing dcmd codecache output");
+                      Assert.fail("Failed parsing dcmd codecache output");
                   }
               }
           } else {
-              throw new Exception("Regexp 1 failed");
+              Assert.fail("Regexp 1 failed to match line: " + line);
           }
 
           // Validate second line
-          line = r.readLine();
+          line = lines.next();
           m = line2.matcher(line);
           if (m.matches()) {
               String start = m.group(1);
@@ -133,44 +139,49 @@
 
               // Lexical compare of hex numbers to check that they look sane.
               if (start.compareTo(mark) > 1) {
-                  throw new Exception("Failed parsing dcmd codecache output");
+                  Assert.fail("Failed parsing dcmd codecache output");
               }
               if (mark.compareTo(top) > 1) {
-                  throw new Exception("Failed parsing dcmd codecache output");
+                  Assert.fail("Failed parsing dcmd codecache output");
               }
           } else {
-              throw new Exception("Regexp 2 failed line: " + line);
+              Assert.fail("Regexp 2 failed to match line: " + line);
           }
         }
 
         // Validate third line
-        line = r.readLine();
+        line = lines.next();
         m = line3.matcher(line);
         if (m.matches()) {
             int blobs = Integer.parseInt(m.group(1));
             if (blobs <= 0) {
-                throw new Exception("Failed parsing dcmd codecache output");
+                Assert.fail("Failed parsing dcmd codecache output");
             }
             int nmethods = Integer.parseInt(m.group(2));
             if (nmethods < 0) {
-                throw new Exception("Failed parsing dcmd codecache output");
+                Assert.fail("Failed parsing dcmd codecache output");
             }
             int adapters = Integer.parseInt(m.group(3));
             if (adapters <= 0) {
-                throw new Exception("Failed parsing dcmd codecache output");
+                Assert.fail("Failed parsing dcmd codecache output");
             }
             if (blobs < (nmethods + adapters)) {
-                throw new Exception("Failed parsing dcmd codecache output");
+                Assert.fail("Failed parsing dcmd codecache output");
             }
         } else {
-            throw new Exception("Regexp 3 failed");
+            Assert.fail("Regexp 3 failed to match line: " + line);
         }
 
         // Validate fourth line
-        line = r.readLine();
+        line = lines.next();
         m = line4.matcher(line);
         if (!m.matches()) {
-            throw new Exception("Regexp 4 failed");
+            Assert.fail("Regexp 4 failed to match line: " + line);
         }
     }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
 }
--- a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java	Fri Jan 30 20:20:11 2015 +0100
+++ b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -24,14 +24,21 @@
 /*
  * @test CodelistTest
  * @bug 8054889
- * @library ..
- * @build DcmdUtil MethodIdentifierParser CodelistTest
- * @run main CodelistTest
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @build MethodIdentifierParser
+ * @run testng CodelistTest
  * @summary Test of diagnostic command Compiler.codelist
  */
 
-import java.io.BufferedReader;
-import java.io.StringReader;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
 import java.lang.reflect.Method;
 
 public class CodelistTest {
@@ -51,19 +58,17 @@
      *
      */
 
-    public static void main(String arg[]) throws Exception {
+    public void run(CommandExecutor executor) {
         int ok   = 0;
         int fail = 0;
 
         // Get output from dcmd (diagnostic command)
-        String result = DcmdUtil.executeDcmd("Compiler.codelist");
-        BufferedReader r = new BufferedReader(new StringReader(result));
+        OutputAnalyzer output = executor.execute("Compiler.codelist");
 
         // Grab a method name from the output
-        String line;
         int count = 0;
 
-        while((line = r.readLine()) != null) {
+        for (String line : output.asLines()) {
             count++;
 
             String[] parts = line.split(" ");
@@ -83,14 +88,16 @@
             }
 
             MethodIdentifierParser mf = new MethodIdentifierParser(methodPrintedInLogFormat);
-            Method m;
+            Method m = null;
             try {
                 m = mf.getMethod();
             } catch (NoSuchMethodException e) {
                 m = null;
+            } catch (ClassNotFoundException e) {
+                Assert.fail("Test error: Caught unexpected exception", e);
             }
             if (m == null) {
-                throw new Exception("Test failed on: " + methodPrintedInLogFormat);
+                Assert.fail("Test failed on: " + methodPrintedInLogFormat);
             }
             if (count > 10) {
                 // Testing 10 entries is enough. Lets not waste time.
@@ -98,4 +105,9 @@
             }
         }
     }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
 }
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java	Fri Jan 30 20:20:11 2015 +0100
+++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -24,17 +24,22 @@
 /*
  * @test CompilerQueueTest
  * @bug 8054889
- * @library ..
+ * @library /testlibrary
  * @ignore 8069160
- * @build DcmdUtil CompilerQueueTest
- * @run main CompilerQueueTest
- * @run main/othervm -XX:-TieredCompilation CompilerQueueTest
- * @run main/othervm -Xint CompilerQueueTest
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng CompilerQueueTest
+ * @run testng/othervm -XX:-TieredCompilation CompilerQueueTest
+ * @run testng/othervm -Xint CompilerQueueTest
  * @summary Test of diagnostic command Compiler.queue
  */
 
-import java.io.BufferedReader;
-import java.io.StringReader;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+import org.testng.annotations.Test;
+
+import java.util.Iterator;
 
 public class CompilerQueueTest {
 
@@ -60,52 +65,55 @@
      *
      **/
 
-    public static void main(String arg[]) throws Exception {
+    public void run(CommandExecutor executor) {
 
         // Get output from dcmd (diagnostic command)
-        String result = DcmdUtil.executeDcmd("Compiler.queue");
-        BufferedReader r = new BufferedReader(new StringReader(result));
-
-        String str = r.readLine();
+        OutputAnalyzer output = executor.execute("Compiler.queue");
+        Iterator<String> lines = output.asLines().iterator();
 
-        while (str != null) {
+        while (lines.hasNext()) {
+            String str = lines.next();
             if (str.startsWith("Contents of C")) {
-                match(r.readLine(), "----------------------------");
-                str = r.readLine();
+                match(lines.next(), "----------------------------");
+                str = lines.next();
                 if (!str.equals("Empty")) {
                     while (str.charAt(0) != '-') {
                         validateMethodLine(str);
-                        str = r.readLine();
+                        str = lines.next();
                     }
                 } else {
-                    str = r.readLine();
+                    str = lines.next();
                 }
                 match(str,"----------------------------");
-                str = r.readLine();
             } else {
-                throw new Exception("Failed parsing dcmd queue, line: " + str);
+                Assert.fail("Failed parsing dcmd queue, line: " + str);
             }
         }
     }
 
-    private static void validateMethodLine(String str)  throws Exception {
+    private static void validateMethodLine(String str) {
         // Skip until package/class name begins. Trim to remove whitespace that
         // may differ.
         String name = str.substring(14).trim();
         int sep = name.indexOf("::");
         if (sep == -1) {
-            throw new Exception("Failed dcmd queue, didn't find separator :: in: " + name);
+            Assert.fail("Failed dcmd queue, didn't find separator :: in: " + name);
         }
         try {
             Class.forName(name.substring(0, sep));
         } catch (ClassNotFoundException e) {
-            throw new Exception("Failed dcmd queue, Class for name: " + str);
+            Assert.fail("Failed dcmd queue, Class for name: " + str);
         }
     }
 
-    public static void match(String line, String str) throws Exception {
+    public static void match(String line, String str) {
         if (!line.equals(str)) {
-            throw new Exception("String equals: " + line + ", " + str);
+            Assert.fail("String equals: " + line + ", " + str);
         }
     }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
 }
--- a/hotspot/test/serviceability/dcmd/compiler/MethodIdentifierParser.java	Fri Jan 30 20:20:11 2015 +0100
+++ b/hotspot/test/serviceability/dcmd/compiler/MethodIdentifierParser.java	Fri Jan 30 20:00:57 2015 +0100
@@ -51,11 +51,11 @@
         // Add sanity check for extracted fields
     }
 
-    public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException, Exception {
+    public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
         try {
             return Class.forName(className).getDeclaredMethod(methodName, getParamenterDescriptorArray());
         } catch (UnexpectedTokenException e) {
-            throw new Exception("Parse failed");
+            throw new RuntimeException("Parse failed");
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/framework/HelpTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.PidJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.MainClassJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.FileJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @summary Test of diagnostic command help (tests all DCMD executors)
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng HelpTest
+ */
+public class HelpTest {
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("help");
+
+        output.shouldContain("The following commands are available");
+        output.shouldContain("help");
+        output.shouldContain("VM.version");
+    }
+
+    @Test
+    public void pid() {
+        run(new PidJcmdExecutor());
+    }
+
+    @Test
+    public void mainClass() {
+        run(new MainClassJcmdExecutor());
+    }
+
+    @Test
+    public void file() {
+        run(new FileJcmdExecutor());
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.PidJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.MainClassJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.FileJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @summary Test of invalid diagnostic command (tests all DCMD executors)
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng InvalidCommandTest
+ */
+public class InvalidCommandTest {
+
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("asdf");
+        output.shouldContain("Unknown diagnostic command");
+    }
+
+    @Test
+    public void pid() {
+        run(new PidJcmdExecutor());
+    }
+
+    @Test
+    public void mainClass() {
+        run(new MainClassJcmdExecutor());
+    }
+
+    @Test
+    public void file() {
+        run(new FileJcmdExecutor());
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.PidJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.MainClassJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.FileJcmdExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.version (tests all DCMD executors)
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng VMVersionTest
+ */
+public class VMVersionTest {
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("VM.version");
+        output.shouldMatch(".*(?:HotSpot|OpenJDK).*VM.*");
+    }
+
+    @Test
+    public void pid() {
+        run(new PidJcmdExecutor());
+    }
+
+    @Test
+    public void mainClass() {
+        run(new MainClassJcmdExecutor());
+    }
+
+    @Test
+    public void file() {
+        run(new FileJcmdExecutor());
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.class_histogram -all=true
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @build ClassHistogramTest
+ * @run testng ClassHistogramAllTest
+ */
+public class ClassHistogramAllTest extends ClassHistogramTest {
+    public ClassHistogramAllTest() {
+        super();
+        classHistogramArgs = "-all=true";
+    }
+
+    /* See ClassHistogramTest for test cases */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+
+import java.util.regex.Pattern;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.class_histogram
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng ClassHistogramTest
+ */
+public class ClassHistogramTest {
+    public static class TestClass {}
+    public static TestClass[] instances = new TestClass[1024];
+    protected String classHistogramArgs = "";
+
+    static {
+        for (int i = 0; i < instances.length; ++i) {
+            instances[i] = new TestClass();
+        }
+    }
+
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("GC.class_histogram " + classHistogramArgs);
+
+        /*
+         * example output:
+         *   num     #instances         #bytes  class name
+         *  ----------------------------------------------
+         *     1:          1647        1133752  [B
+         *     2:          6198         383168  [C
+         *     3:          1464         165744  java.lang.Class
+         *     4:          6151         147624  java.lang.String
+         *     5:          2304          73728  java.util.concurrent.ConcurrentHashMap$Node
+         *     6:          1199          64280  [Ljava.lang.Object;
+         * ...
+         */
+
+        /* Require at least one java.lang.Class */
+        output.shouldMatch("^\\s+\\d+:\\s+\\d+\\s+\\d+\\s+java.lang.Class\\s*$");
+
+        /* Require at least one java.lang.String */
+        output.shouldMatch("^\\s+\\d+:\\s+\\d+\\s+\\d+\\s+java.lang.String\\s*$");
+
+        /* Require at least one java.lang.Object */
+        output.shouldMatch("^\\s+\\d+:\\s+\\d+\\s+\\d+\\s+java.lang.Object\\s*$");
+
+        /* Require at exactly one TestClass[] */
+        output.shouldMatch("^\\s+\\d+:\\s+1\\s+\\d+\\s+" +
+                Pattern.quote(TestClass[].class.getName()) + "\\s*$");
+
+        /* Require at exactly 1024 TestClass */
+        output.shouldMatch("^\\s+\\d+:\\s+1024\\s+\\d+\\s+" +
+                Pattern.quote(TestClass.class.getName()) + "\\s*$");
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.heap_dump -all=true
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @build HeapDumpTest
+ * @run testng HeapDumpAllTest
+ */
+public class HeapDumpAllTest extends HeapDumpTest {
+    public HeapDumpAllTest() {
+        super();
+        heapDumpArgs = "-all=true";
+    }
+
+    /* See HeapDumpTest for test cases */
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.IOException;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.PidJcmdExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.heap_dump
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng HeapDumpTest
+ */
+public class HeapDumpTest {
+    protected String heapDumpArgs = "";
+
+    public void run(CommandExecutor executor) {
+        String fileName = "jcmd.gc.heap_dump." + System.currentTimeMillis() + ".hprof";
+        String cmd = "GC.heap_dump " + heapDumpArgs + " " + fileName;
+        executor.execute(cmd);
+
+        verifyHeapDump(fileName);
+    }
+
+    private void verifyHeapDump(String fileName) {
+        String jhat = JDKToolFinder.getTestJDKTool("jhat");
+        String[] cmd = { jhat, "-parseonly", "true", fileName };
+
+        ProcessBuilder pb = new ProcessBuilder(cmd);
+        pb.redirectErrorStream(true);
+        Process p = null;
+        OutputAnalyzer output = null;
+
+        try {
+            p = pb.start();
+            output = new OutputAnalyzer(p);
+
+            /*
+             * Some hprof dumps of all objects contain constantPoolOop references that cannot be resolved, so we ignore
+             * failures about resolving constantPoolOop fields using a negative lookahead
+             */
+            output.shouldNotMatch(".*WARNING(?!.*Failed to resolve object.*constantPoolOop.*).*");
+        } catch (IOException e) {
+            Assert.fail("Test error: Caught exception while reading stdout/err of jhat", e);
+        } finally {
+            if (p != null) {
+                p.destroy();
+            }
+        }
+
+        if (output.getExitValue() != 0) {
+            Assert.fail("Test error: jhat exit code was nonzero");
+        }
+    }
+
+    /* GC.heap_dump is not available over JMX, running jcmd pid executor instead */
+    @Test
+    public void pid() {
+        run(new PidJcmdExecutor());
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.run_finalization
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng RunFinalizationTest
+ */
+public class RunFinalizationTest {
+    static ReentrantLock lock = new ReentrantLock();
+    static Condition cond = lock.newCondition();
+    static volatile boolean wasFinalized = false;
+    static volatile boolean wasInitialized = false;
+
+    class MyObject {
+        public MyObject() {
+            /* Make sure object allocation/deallocation is not optimized out */
+            wasInitialized = true;
+        }
+
+        protected void finalize() {
+            lock.lock();
+            wasFinalized = true;
+            cond.signalAll();
+            lock.unlock();
+        }
+    }
+
+    public static MyObject o;
+
+    public void run(CommandExecutor executor) {
+        lock.lock();
+        o = new MyObject();
+        o = null;
+        System.gc();
+        executor.execute("GC.run_finalization");
+
+        int waited = 0;
+        int waitTime = 15;
+
+        try {
+            System.out.println("Waiting for signal from finalizer");
+
+            while (!cond.await(waitTime, TimeUnit.SECONDS)) {
+                waited += waitTime;
+                System.out.println(String.format("Waited %d seconds", waited));
+            }
+
+            System.out.println("Received signal");
+        } catch (InterruptedException e) {
+            Assert.fail("Test error: Interrupted while waiting for signal from finalizer", e);
+        } finally {
+            lock.unlock();
+        }
+
+        if (!wasFinalized) {
+            Assert.fail("Test failure: Object was not finalized");
+        }
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.run
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng/othervm -XX:+PrintGCDetails -Xloggc:RunGC.gclog RunGCTest
+ */
+public class RunGCTest {
+    public void run(CommandExecutor executor) {
+        executor.execute("GC.run");
+
+        Path gcLogPath = Paths.get("RunGC.gclog").toAbsolutePath();
+        String gcLog = null;
+
+        try {
+            gcLog = new String(Files.readAllBytes(gcLogPath));
+        } catch (IOException e) {
+            Assert.fail("Test error: Could not read GC log file: " + gcLogPath, e);
+        }
+
+        OutputAnalyzer output = new OutputAnalyzer(gcLog, "");
+        output.shouldMatch(".*\\[Full GC \\(System(\\.gc\\(\\))?.*");
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Test of diagnostic command Thread.print -l=true
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @build PrintTest
+ * @run testng PrintConcurrentLocksTest
+ */
+public class PrintConcurrentLocksTest extends PrintTest {
+    public PrintConcurrentLocksTest() {
+        jucLocks = true;
+    }
+
+    /* See PrintTest for test cases */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/thread/PrintTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Pattern;
+
+/*
+ * @test
+ * @summary Test of diagnostic command Thread.print
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng PrintTest
+ */
+public class PrintTest {
+    protected boolean jucLocks = false;
+
+    CyclicBarrier readyBarrier = new CyclicBarrier(3);
+    CyclicBarrier doneBarrier = new CyclicBarrier(3);
+
+    private void waitForBarrier(CyclicBarrier b) {
+        try {
+            b.await();
+        } catch (InterruptedException | BrokenBarrierException e) {
+            Assert.fail("Test error: Caught unexpected exception:", e);
+        }
+    }
+
+    class MonitorThread extends Thread {
+        Object lock = new Object();
+
+        public void run() {
+            /* Hold lock on "lock" to show up in thread dump */
+            synchronized (lock) {
+                /* Signal that we're ready for thread dump */
+                waitForBarrier(readyBarrier);
+
+                /* Released when the thread dump has been taken */
+                waitForBarrier(doneBarrier);
+            }
+        }
+    }
+
+    class LockThread extends Thread {
+        ReentrantLock lock = new ReentrantLock();
+
+        public void run() {
+            /* Hold lock "lock" to show up in thread dump */
+            lock.lock();
+
+            /* Signal that we're ready for thread dump */
+            waitForBarrier(readyBarrier);
+
+            /* Released when the thread dump has been taken */
+            waitForBarrier(doneBarrier);
+
+            lock.unlock();
+        }
+    }
+
+    public void run(CommandExecutor executor) {
+        MonitorThread mThread = new MonitorThread();
+        mThread.start();
+        LockThread lThread = new LockThread();
+        lThread.start();
+
+        /* Wait for threads to get ready */
+        waitForBarrier(readyBarrier);
+
+        /* Execute */
+        OutputAnalyzer output = executor.execute("Thread.print" + (jucLocks ? " -l=true" : ""));
+
+        /* Signal that we've got the thread dump */
+        waitForBarrier(doneBarrier);
+
+        /*
+         * Example output (trimmed) with arrows indicating the rows we are looking for:
+         *
+         *     ...
+         *     "Thread-2" #24 prio=5 os_prio=0 tid=0x00007f913411f800 nid=0x4fc9 waiting on condition [0x00007f91fbffe000]
+         *        java.lang.Thread.State: WAITING (parking)
+         *       at sun.misc.Unsafe.park(Native Method)
+         *       - parking to wait for  <0x000000071a0868a8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
+         *       at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
+         *       at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
+         *       at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:234)
+         *       at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
+         *       at Print.waitForBarrier(Print.java:26)
+         *       at Print.access$000(Print.java:18)
+         *       at Print$LockThread.run(Print.java:58)
+         *
+         * -->    Locked ownable synchronizers:
+         * -->    - <0x000000071a294930> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
+         *
+         *     "Thread-1" #23 prio=5 os_prio=0 tid=0x00007f913411e800 nid=0x4fc8 waiting on condition [0x00007f9200113000]
+         *        java.lang.Thread.State: WAITING (parking)
+         *       at sun.misc.Unsafe.park(Native Method)
+         *       - parking to wait for  <0x000000071a0868a8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
+         *       at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
+         *       at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
+         *       at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:234)
+         *       at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
+         *       at Print.waitForBarrier(Print.java:26)
+         *       at Print.access$000(Print.java:18)
+         *       at Print$MonitorThread.run(Print.java:42)
+         * -->   - locked <0x000000071a294390> (a java.lang.Object)
+         *
+         *        Locked ownable synchronizers:
+         *       - None
+         *
+         *     "MainThread" #22 prio=5 os_prio=0 tid=0x00007f923015b000 nid=0x4fc7 in Object.wait() [0x00007f9200840000]
+         *        java.lang.Thread.State: WAITING (on object monitor)
+         *       at java.lang.Object.wait(Native Method)
+         *       - waiting on <0x000000071a70ad98> (a java.lang.UNIXProcess)
+         *       at java.lang.Object.wait(Object.java:502)
+         *        at java.lang.UNIXProcess.waitFor(UNIXProcess.java:397)
+         *        - locked <0x000000071a70ad98> (a java.lang.UNIXProcess)
+         *        at com.oracle.java.testlibrary.dcmd.JcmdExecutor.executeImpl(JcmdExecutor.java:32)
+         *       at com.oracle.java.testlibrary.dcmd.CommandExecutor.execute(CommandExecutor.java:24)
+         * -->   at Print.run(Print.java:74)
+         *       at Print.file(Print.java:112)
+         *     ...
+
+         */
+        output.shouldMatch(".*at " + Pattern.quote(PrintTest.class.getName()) + "\\.run.*");
+        output.shouldMatch(".*- locked <0x\\p{XDigit}+> \\(a " + Pattern.quote(mThread.lock.getClass().getName()) + "\\).*");
+
+        String jucLockPattern1 = ".*Locked ownable synchronizers:.*";
+        String jucLockPattern2 = ".*- <0x\\p{XDigit}+> \\(a " + Pattern.quote(lThread.lock.getClass().getName()) + ".*";
+
+        if (jucLocks) {
+            output.shouldMatch(jucLockPattern1);
+            output.shouldMatch(jucLockPattern2);
+        } else {
+            output.shouldNotMatch(jucLockPattern1);
+            output.shouldNotMatch(jucLockPattern2);
+        }
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.classloader_stats
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng ClassLoaderStatsTest
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ClassLoaderStatsTest {
+
+    // ClassLoader         Parent              CLD*               Classes   ChunkSz   BlockSz  Type
+    // 0x00000007c0215928  0x0000000000000000  0x0000000000000000       0         0         0  org.eclipse.osgi.baseadaptor.BaseAdaptor$1
+    // 0x00000007c0009868  0x0000000000000000  0x00007fc52aebcc80       1      6144      3768  sun.reflect.DelegatingClassLoader
+    // 0x00000007c0009868  0x0000000000000000  0x00007fc52b8916d0       1      6144      3688  sun.reflect.DelegatingClassLoader
+    // 0x00000007c0009868  0x00000007c0038ba8  0x00007fc52afb8760       1      6144      3688  sun.reflect.DelegatingClassLoader
+    // 0x00000007c0009868  0x0000000000000000  0x00007fc52afbb1a0       1      6144      3688  sun.reflect.DelegatingClassLoader
+    // 0x0000000000000000  0x0000000000000000  0x00007fc523416070    5019  30060544  29956216  <boot classloader>
+    //                                                                455   1210368    672848   + unsafe anonymous classes
+    // 0x00000007c016b5c8  0x00000007c0038ba8  0x00007fc52a995000       5      8192      5864  org.netbeans.StandardModule$OneModuleClassLoader
+    // 0x00000007c0009868  0x00000007c016b5c8  0x00007fc52ac13640       1      6144      3896  sun.reflect.DelegatingClassLoader
+    // ...
+
+    static Pattern clLine = Pattern.compile("0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*(.*)");
+    static Pattern anonLine = Pattern.compile("\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*.*");
+
+    public static DummyClassLoader dummyloader;
+
+    public void run(CommandExecutor executor) throws ClassNotFoundException {
+
+        // create a classloader and load our special class
+        dummyloader = new DummyClassLoader();
+        Class<?> c = Class.forName("TestClass", true, dummyloader);
+        if (c.getClassLoader() != dummyloader) {
+            Assert.fail("TestClass defined by wrong classloader: " + c.getClassLoader());
+        }
+
+        OutputAnalyzer output = executor.execute("VM.classloader_stats");
+        Iterator<String> lines = output.asLines().iterator();
+        while (lines.hasNext()) {
+            String line = lines.next();
+            Matcher m = clLine.matcher(line);
+            if (m.matches()) {
+                // verify that DummyClassLoader has loaded 1 class and 1 anonymous class
+                if (m.group(4).equals("ClassLoaderStatsTest$DummyClassLoader")) {
+                    System.out.println("line: " + line);
+                    if (!m.group(1).equals("1")) {
+                        Assert.fail("Should have loaded 1 class: " + line);
+                    }
+                    checkPositiveInt(m.group(2));
+                    checkPositiveInt(m.group(3));
+
+                    String next = lines.next();
+                    System.out.println("next: " + next);
+                    Matcher m1 = anonLine.matcher(next);
+                    m1.matches();
+                    if (!m1.group(1).equals("1")) {
+                        Assert.fail("Should have loaded 1 anonymous class, but found : " + m1.group(1));
+                    }
+                    checkPositiveInt(m1.group(2));
+                    checkPositiveInt(m1.group(3));
+                }
+            }
+        }
+    }
+
+    private static void checkPositiveInt(String s) {
+        if (Integer.parseInt(s) <= 0) {
+            Assert.fail("Value should have been > 0: " + s);
+        }
+    }
+
+    public static class DummyClassLoader extends ClassLoader {
+
+        public static final String CLASS_NAME = "TestClass";
+
+        static ByteBuffer readClassFile(String name)
+        {
+            File f = new File(System.getProperty("test.classes", "."),
+                              name);
+            try (FileInputStream fin = new FileInputStream(f);
+                 FileChannel fc = fin.getChannel())
+            {
+                return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+            } catch (IOException e) {
+                Assert.fail("Can't open file: " + name, e);
+            }
+
+            /* Will not reach here as Assert.fail() throws exception */
+            return null;
+        }
+
+        protected Class<?> loadClass(String name, boolean resolve)
+            throws ClassNotFoundException
+        {
+            Class<?> c;
+            if (!"TestClass".equals(name)) {
+                c = super.loadClass(name, resolve);
+            } else {
+                // should not delegate to the system class loader
+                c = findClass(name);
+                if (resolve) {
+                    resolveClass(c);
+                }
+            }
+            return c;
+        }
+
+        protected Class<?> findClass(String name)
+            throws ClassNotFoundException
+        {
+            if (!"TestClass".equals(name)) {
+                throw new ClassNotFoundException("Unexpected class: " + name);
+            }
+            return defineClass(name, readClassFile(name + ".class"), null);
+        }
+    } /* DummyClassLoader */
+
+    @Test
+    public void jmx() throws ClassNotFoundException {
+        run(new JMXExecutor());
+    }
+}
+
+class TestClass {
+    static {
+        // force creation of anonymous class (for the lambdaform)
+        Runnable r = () -> System.out.println("Hello");
+        r.run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import org.testng.annotations.Test;
+
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.command_line
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis CommandLineTest
+ */
+public class CommandLineTest {
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("VM.command_line");
+        output.shouldContain("-XX:+IgnoreUnrecognizedVMOptions");
+        output.shouldContain("-XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis");
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,72 @@
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.Platform;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test of VM.dynlib diagnostic command via MBean
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng DynLibsTest
+ */
+
+public class DynLibsTest {
+
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("VM.dynlibs");
+
+        String osDependentBaseString = null;
+        if (Platform.isAix()) {
+            osDependentBaseString = "lib%s.so";
+        } else if (Platform.isLinux()) {
+            osDependentBaseString = "lib%s.so";
+        } else if (Platform.isOSX()) {
+            osDependentBaseString = "lib%s.dylib";
+        } else if (Platform.isSolaris()) {
+            osDependentBaseString = "lib%s.so";
+        } else if (Platform.isWindows()) {
+            osDependentBaseString = "%s.dll";
+        }
+
+        if (osDependentBaseString == null) {
+            Assert.fail("Unsupported OS");
+        }
+
+        output.shouldContain(String.format(osDependentBaseString, "jvm"));
+        output.shouldContain(String.format(osDependentBaseString, "java"));
+        output.shouldContain(String.format(osDependentBaseString, "management"));
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.flags
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng/othervm -Xmx129m -XX:+PrintGC -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest
+ */
+public class FlagsTest {
+    public void run(CommandExecutor executor) {
+        OutputAnalyzer output = executor.execute("VM.flags");
+
+        /* The following are interpreted by the JVM as actual "flags" */
+        output.shouldContain("-XX:+PrintGC");
+        output.shouldContain("-XX:+UnlockDiagnosticVMOptions");
+        output.shouldContain("-XX:+IgnoreUnrecognizedVMOptions");
+        output.shouldContain("-XX:-TieredCompilation");
+
+        /* The following are not */
+        output.shouldNotContain("-Xmx129m");
+        output.shouldNotContain("-XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right");
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.system_properties
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng SystemPropertiesTest
+ */
+public class SystemPropertiesTest {
+    private final static String PROPERTY_NAME  = "SystemPropertiesTestPropertyName";
+    private final static String PROPERTY_VALUE = "SystemPropertiesTestPropertyValue";
+
+    public void run(CommandExecutor executor) {
+        System.setProperty(PROPERTY_NAME, PROPERTY_VALUE);
+
+        OutputAnalyzer output = executor.execute("VM.system_properties");
+        output.shouldContain(PROPERTY_NAME + "=" + PROPERTY_VALUE);
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.dcmd.CommandExecutor;
+import com.oracle.java.testlibrary.dcmd.JMXExecutor;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+/*
+ * @test
+ * @summary Test of diagnostic command VM.uptime
+ * @library /testlibrary
+ * @build com.oracle.java.testlibrary.*
+ * @build com.oracle.java.testlibrary.dcmd.*
+ * @run testng UptimeTest
+ */
+public class UptimeTest {
+    public void run(CommandExecutor executor) {
+        double someUptime = 1.0;
+        long startTime = System.currentTimeMillis();
+        try {
+            synchronized (this) {
+                /* Loop to guard against spurious wake ups */
+                while (System.currentTimeMillis() < (startTime + someUptime * 1000)) {
+                    wait((int) someUptime * 1000);
+                }
+            }
+        } catch (InterruptedException e) {
+            Assert.fail("Test error: Exception caught when sleeping:", e);
+        }
+
+        OutputAnalyzer output = executor.execute("VM.uptime");
+
+        output.stderrShouldBeEmpty();
+
+        /*
+         * Output should be:
+         * [pid]:
+         * xx.yyy s
+         *
+         * If there is only one line in output there is no "[pid]:" printout;
+         * skip first line, split on whitespace and grab first half
+         */
+        int index = output.asLines().size() == 1 ? 0 : 1;
+        String uptimeString = output.asLines().get(index).split("\\s+")[0];
+
+        try {
+            double uptime = NumberFormat.getNumberInstance().parse(uptimeString).doubleValue();
+            if (uptime < someUptime) {
+                Assert.fail(String.format(
+                        "Test failure: Uptime was less than intended sleep time: %.3f s < %.3f s",
+                        uptime, someUptime));
+            }
+        } catch (ParseException e) {
+            Assert.fail("Test failure: Could not parse uptime string: " +
+                    uptimeString, e);
+        }
+    }
+
+    @Test
+    public void jmx() {
+        run(new JMXExecutor());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+/**
+ * Abstract base class for Diagnostic Command executors
+ */
+public abstract class CommandExecutor {
+
+    /**
+     * Execute a diagnostic command
+     *
+     * @param cmd The diagnostic command to execute
+     * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command
+     * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the
+     *          Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in
+     *          stderr, regardless of the specific executor used.
+     */
+    public final OutputAnalyzer execute(String cmd) throws CommandExecutorException {
+        System.out.printf("Running DCMD '%s' through '%s'%n", cmd, this.getClass().getSimpleName());
+        OutputAnalyzer oa = executeImpl(cmd);
+
+        System.out.println("---------------- stdout ----------------");
+        System.out.println(oa.getStdout());
+        System.out.println("---------------- stderr ----------------");
+        System.out.println(oa.getStderr());
+        System.out.println("----------------------------------------");
+        System.out.println();
+
+        return oa;
+    }
+
+    protected abstract OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/CommandExecutorException.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+/**
+ * CommandExecutorException encapsulates exceptions thrown (on the "calling side") from the execution of Diagnostic
+ * Commands
+ */
+public class CommandExecutorException extends RuntimeException {
+    private static final long serialVersionUID = -7039597746579144280L;
+
+    public CommandExecutorException(String message, Throwable e) {
+        super(message, e);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/FileJcmdExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,81 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by pid) using the jcmd tool and its ability to read
+ *          Diagnostic Commands from a file.
+ */
+public class FileJcmdExecutor extends PidJcmdExecutor {
+
+    /**
+     * Instantiates a new FileJcmdExecutor targeting the current VM
+     */
+    public FileJcmdExecutor() {
+        super();
+    }
+
+    /**
+     * Instantiates a new FileJcmdExecutor targeting the VM indicated by the given pid
+     *
+     * @param target Pid of the target VM
+     */
+    public FileJcmdExecutor(String target) {
+        super(target);
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        File cmdFile = createTempFile();
+        writeCommandToTemporaryFile(cmd, cmdFile);
+
+        return Arrays.asList(jcmdBinary, Integer.toString(pid),
+                "-f", cmdFile.getAbsolutePath());
+    }
+
+    private void writeCommandToTemporaryFile(String cmd, File cmdFile) {
+        try (PrintWriter pw = new PrintWriter(cmdFile)) {
+            pw.println(cmd);
+        } catch (IOException e) {
+            String message = "Could not write to file: " + cmdFile.getAbsolutePath();
+            throw new CommandExecutorException(message, e);
+        }
+    }
+
+    private File createTempFile() {
+        try {
+            File cmdFile = File.createTempFile("input", "jcmd");
+            cmdFile.deleteOnExit();
+            return cmdFile;
+        } catch (IOException e) {
+            throw new CommandExecutorException("Could not create temporary file", e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/JMXExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,187 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+import javax.management.*;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.management.ManagementFactory;
+
+import java.util.HashMap;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by a host/port combination or a full JMX Service URL) using
+ * the JMX interface. If the target is not the current VM, the JMX Remote interface must be enabled beforehand.
+ */
+public class JMXExecutor extends CommandExecutor {
+
+    private final MBeanServerConnection mbs;
+
+    /**
+     * Instantiates a new JMXExecutor targeting the current VM
+     */
+    public JMXExecutor() {
+        super();
+        mbs = ManagementFactory.getPlatformMBeanServer();
+    }
+
+    /**
+     * Instantiates a new JMXExecutor targeting the VM indicated by the given host/port combination or a full JMX
+     * Service URL
+     *
+     * @param target a host/port combination on the format "host:port" or a full JMX Service URL of the target VM
+     */
+    public JMXExecutor(String target) {
+        String urlStr;
+
+        if (target.matches("^\\w[\\w\\-]*(\\.[\\w\\-]+)*:\\d+$")) {
+            /* Matches "hostname:port" */
+            urlStr = String.format("service:jmx:rmi:///jndi/rmi://%s/jmxrmi", target);
+        } else if (target.startsWith("service:")) {
+            urlStr = target;
+        } else {
+            throw new IllegalArgumentException("Could not recognize target string: " + target);
+        }
+
+        try {
+            JMXServiceURL url = new JMXServiceURL(urlStr);
+            JMXConnector c = JMXConnectorFactory.connect(url, new HashMap<>());
+            mbs = c.getMBeanServerConnection();
+        } catch (IOException e) {
+            throw new CommandExecutorException("Could not initiate connection to target: " + target, e);
+        }
+    }
+
+    protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException {
+        String stdout = "";
+        String stderr = "";
+
+        String[] cmdParts = cmd.split(" ", 2);
+        String operation = commandToMethodName(cmdParts[0]);
+        Object[] dcmdArgs = produceArguments(cmdParts);
+        String[] signature = {String[].class.getName()};
+
+        ObjectName beanName = getMBeanName();
+
+        try {
+            stdout = (String) mbs.invoke(beanName, operation, dcmdArgs, signature);
+        }
+
+        /* Failures on the "local" side, the one invoking the command. */
+        catch (ReflectionException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof NoSuchMethodException) {
+                /* We want JMXExecutor to match the behavior of the other CommandExecutors */
+                String message = "Unknown diagnostic command: " + operation;
+                stderr = exceptionTraceAsString(new IllegalArgumentException(message, e));
+            } else {
+                rethrowExecutorException(operation, dcmdArgs, e);
+            }
+        }
+
+        /* Failures on the "local" side, the one invoking the command. */
+        catch (InstanceNotFoundException | IOException e) {
+            rethrowExecutorException(operation, dcmdArgs, e);
+        }
+
+        /* Failures on the remote side, the one executing the invoked command. */
+        catch (MBeanException e) {
+            stdout = exceptionTraceAsString(e);
+        }
+
+        return new OutputAnalyzer(stdout, stderr);
+    }
+
+    private void rethrowExecutorException(String operation, Object[] dcmdArgs,
+                                          Exception e) throws CommandExecutorException {
+        String message = String.format("Could not invoke: %s %s", operation,
+                String.join(" ", (String[]) dcmdArgs[0]));
+        throw new CommandExecutorException(message, e);
+    }
+
+    private ObjectName getMBeanName() throws CommandExecutorException {
+        String MBeanName = "com.sun.management:type=DiagnosticCommand";
+
+        try {
+            return new ObjectName(MBeanName);
+        } catch (MalformedObjectNameException e) {
+            String message = "MBean not found: " + MBeanName;
+            throw new CommandExecutorException(message, e);
+        }
+    }
+
+    private Object[] produceArguments(String[] cmdParts) {
+        Object[] dcmdArgs = {new String[0]}; /* Default: No arguments */
+
+        if (cmdParts.length == 2) {
+            dcmdArgs[0] = cmdParts[1].split(" ");
+        }
+        return dcmdArgs;
+    }
+
+    /**
+     * Convert from diagnostic command to MBean method name
+     *
+     * Examples:
+     * help            --> help
+     * VM.version      --> vmVersion
+     * VM.command_line --> vmCommandLine
+     */
+    private static String commandToMethodName(String cmd) {
+        String operation = "";
+        boolean up = false; /* First letter is to be lower case */
+
+        /*
+         * If a '.' or '_' is encountered it is not copied,
+         * instead the next character will be converted to upper case
+         */
+        for (char c : cmd.toCharArray()) {
+            if (('.' == c) || ('_' == c)) {
+                up = true;
+            } else if (up) {
+                operation = operation.concat(Character.toString(c).toUpperCase());
+                up = false;
+            } else {
+                operation = operation.concat(Character.toString(c).toLowerCase());
+            }
+        }
+
+        return operation;
+    }
+
+    private static String exceptionTraceAsString(Throwable cause) {
+        StringWriter sw = new StringWriter();
+        cause.printStackTrace(new PrintWriter(sw));
+        return sw.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/JcmdExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+import java.util.List;
+
+/**
+ * Base class for Diagnostic Command Executors using the jcmd tool
+ */
+public abstract class JcmdExecutor extends CommandExecutor {
+    protected String jcmdBinary;
+
+    protected abstract List<String> createCommandLine(String cmd) throws CommandExecutorException;
+
+    protected JcmdExecutor() {
+        jcmdBinary = JDKToolFinder.getJDKTool("jcmd");
+    }
+
+    protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException {
+        List<String> commandLine = createCommandLine(cmd);
+
+        try {
+            System.out.printf("Executing command '%s'%n", commandLine);
+            OutputAnalyzer output = ProcessTools.executeProcess(new ProcessBuilder(commandLine));
+            System.out.printf("Command returned with exit code %d%n", output.getExitValue());
+
+            return output;
+        } catch (Exception e) {
+            String message = String.format("Caught exception while executing '%s'", commandLine);
+            throw new CommandExecutorException(message, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/MainClassJcmdExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by main class) using the jcmd tool
+ */
+public class MainClassJcmdExecutor extends JcmdExecutor {
+    private final String mainClass;
+
+    /**
+     * Instantiates a new MainClassJcmdExecutor targeting the current VM
+     */
+    public MainClassJcmdExecutor() {
+        super();
+        mainClass = System.getProperty("sun.java.command").split(" ")[0];
+    }
+
+    /**
+     * Instantiates a new MainClassJcmdExecutor targeting the VM indicated by the given main class
+     *
+     * @param target Main class of the target VM
+     */
+    public MainClassJcmdExecutor(String target) {
+        super();
+        mainClass = target;
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        return Arrays.asList(jcmdBinary, mainClass, cmd);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dcmd/PidJcmdExecutor.java	Fri Jan 30 20:00:57 2015 +0100
@@ -0,0 +1,63 @@
+/*
+ * 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 com.oracle.java.testlibrary.dcmd;
+
+import com.oracle.java.testlibrary.ProcessTools;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Executes Diagnostic Commands on the target VM (specified by pid) using the jcmd tool
+ */
+public class PidJcmdExecutor extends JcmdExecutor {
+    protected final int pid;
+
+    /**
+     * Instantiates a new PidJcmdExecutor targeting the current VM
+     */
+    public PidJcmdExecutor() {
+        super();
+        try {
+            pid = ProcessTools.getProcessId();
+        } catch (Exception e) {
+            throw new CommandExecutorException("Could not determine own pid", e);
+        }
+    }
+
+    /**
+     * Instantiates a new PidJcmdExecutor targeting the VM indicated by the given pid
+     *
+     * @param target Pid of the target VM
+     */
+    public PidJcmdExecutor(String target) {
+        super();
+        pid = Integer.valueOf(target);
+    }
+
+    protected List<String> createCommandLine(String cmd) throws CommandExecutorException {
+        return Arrays.asList(jcmdBinary, Integer.toString(pid), cmd);
+    }
+
+}