8179249: Improve process output analysis in CDS tests
authoriklam
Wed, 14 Feb 2018 07:08:25 -0800
changeset 48979 514c73a1955b
parent 48978 93996c47d36f
child 48980 ab7784555b4c
8179249: Improve process output analysis in CDS tests Summary: Added new API TestCommon.run(...).assertNormalExit(...), etc Reviewed-by: mseledtsov
test/hotspot/jtreg/runtime/appcds/AppendClasspath.java
test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java
test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java
test/hotspot/jtreg/runtime/appcds/ClassPathAttr.java
test/hotspot/jtreg/runtime/appcds/HelloExtTest.java
test/hotspot/jtreg/runtime/appcds/IgnoreEmptyClassPaths.java
test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java
test/hotspot/jtreg/runtime/appcds/OldClassTest.java
test/hotspot/jtreg/runtime/appcds/PrintSharedArchiveAndExit.java
test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java
test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java
test/hotspot/jtreg/runtime/appcds/TestCommon.java
test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java
test/hotspot/jtreg/runtime/appcds/VerifierTest.java
test/hotspot/jtreg/runtime/appcds/WrongClasspath.java
test/hotspot/jtreg/runtime/appcds/javaldr/ArrayTest.java
test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java
test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDump.java
test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java
test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java
test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java
test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java
test/lib/jdk/test/lib/cds/CDSTestUtils.java
--- a/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,39 +48,33 @@
     TestCommon.testDump(appJar, TestCommon.list("Hello"));
 
     // PASS: 1) runtime with classpath containing the one used in dump time
-    OutputAnalyzer output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", appJar + File.pathSeparator + appJar2,
-        "HelloMore");
-    TestCommon.checkExec(output);
+        "HelloMore")
+      .assertNormalExit();
 
     final String errorMessage1 = "Unable to use shared archive";
     final String errorMessage2 = "shared class paths mismatch";
     // FAIL: 2) runtime with classpath different from the one used in dump time
     // (runtime has an extra jar file prepended to the class path)
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", appJar2 + File.pathSeparator + appJar,
-        "HelloMore");
-    output.shouldContain(errorMessage1);
-    output.shouldContain(errorMessage2);
-    output.shouldHaveExitValue(1);
+        "HelloMore")
+      .assertAbnormalExit(errorMessage1, errorMessage2);
 
     // FAIL: 3) runtime with classpath part of the one used in dump time
     TestCommon.testDump(appJar + File.pathSeparator + appJar2,
                                       TestCommon.list("Hello"));
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", appJar2,
-        "Hello");
-    output.shouldContain(errorMessage1);
-    output.shouldContain(errorMessage2);
-    output.shouldHaveExitValue(1);
+        "Hello")
+      .assertAbnormalExit(errorMessage1, errorMessage2);
 
     // FAIL: 4) runtime with same set of jar files in the classpath but
     // with different order
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", appJar2 + File.pathSeparator + appJar,
-        "HelloMore");
-    output.shouldContain(errorMessage1);
-    output.shouldContain(errorMessage2);
-    output.shouldHaveExitValue(1);
+        "HelloMore")
+      .assertAbnormalExit(errorMessage1, errorMessage2);
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,20 +62,13 @@
     public void testBootClassPathMismatch() throws Exception {
         String appJar = JarBuilder.getOrCreateHelloJar();
         String appClasses[] = {"Hello"};
-        OutputAnalyzer dumpOutput = TestCommon.dump(
+        TestCommon.dump(
             appJar, appClasses, "-Xbootclasspath/a:" + appJar);
         String testDir = TestCommon.getTestDir("newdir");
         String otherJar = testDir + File.separator + "hello.jar";
-        OutputAnalyzer execOutput = TestCommon.exec(
-            appJar, "-verbose:class", "-Xbootclasspath/a:" + otherJar, "Hello");
-        try {
-            TestCommon.checkExec(execOutput, mismatchMessage);
-        } catch (java.lang.RuntimeException re) {
-          String cause = re.getMessage();
-          if (!mismatchMessage.equals(cause)) {
-              throw re;
-          }
-        }
+        TestCommon.run(
+                "-cp", appJar, "-verbose:class", "-Xbootclasspath/a:" + otherJar, "Hello")
+            .assertAbnormalExit(mismatchMessage);
     }
 
     /* Error should be detected if:
@@ -85,17 +78,10 @@
     public void testBootClassPathMismatch2() throws Exception {
         String appJar = JarBuilder.getOrCreateHelloJar();
         String appClasses[] = {"Hello"};
-        OutputAnalyzer dumpOutput = TestCommon.dump(appJar, appClasses);
-        OutputAnalyzer execOutput = TestCommon.exec(
-            appJar, "-verbose:class", "-Xbootclasspath/a:" + appJar, "Hello");
-        try {
-            TestCommon.checkExec(execOutput, mismatchMessage);
-        } catch (java.lang.RuntimeException re) {
-          String cause = re.getMessage();
-          if (!mismatchMessage.equals(cause)) {
-              throw re;
-          }
-        }
+        TestCommon.dump(appJar, appClasses);
+        TestCommon.run(
+                "-cp", appJar, "-verbose:class", "-Xbootclasspath/a:" + appJar, "Hello")
+            .assertAbnormalExit(mismatchMessage);
     }
 
     /* No error if:
@@ -105,13 +91,12 @@
     public void testBootClassPathMatch() throws Exception {
         String appJar = TestCommon.getTestJar("hello.jar");
         String appClasses[] = {"Hello"};
-        OutputAnalyzer dumpOutput = TestCommon.dump(
+        TestCommon.dump(
             appJar, appClasses, "-Xbootclasspath/a:" + appJar);
-        OutputAnalyzer execOutput = TestCommon.exec(
-            appJar, "-verbose:class",
-            "-Xbootclasspath/a:" + appJar, "Hello");
-        TestCommon.checkExec(execOutput,
-                "[class,load] Hello source: shared objects file");
+        TestCommon.run(
+                "-cp", appJar, "-verbose:class",
+                "-Xbootclasspath/a:" + appJar, "Hello")
+            .assertNormalExit("[class,load] Hello source: shared objects file");
     }
 
     private static void copyHelloToNewDir() throws Exception {
--- a/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -76,17 +76,17 @@
         } else {
             jarPathUpper = Paths.get(appJarUpper);
         }
-
-        out = TestCommon.exec(appJarUpper, "Hello", "-Xlog:class+path=info",
-                              "-Xlog:cds");
-        if (TestCommon.isUnableToMap(out))
-            return;
+        boolean isSameFile = Files.isSameFile(jarPath, jarPathUpper);
 
-        if (Files.isSameFile(jarPath, jarPathUpper)) {
-            TestCommon.checkExec(out, "Hello World");
-        } else {
-            out.shouldContain("shared class paths mismatch")
-                .shouldHaveExitValue(1);
-        }
-   }
+        TestCommon.run("-cp", appJarUpper, "Hello", "-Xlog:class+path=info",
+                       "-Xlog:cds")
+            .ifNoMappingFailure(output -> {
+                    if (isSameFile) {
+                        output.shouldContain("Hello World");
+                    } else {
+                        output.shouldContain("shared class paths mismatch");
+                        output.shouldHaveExitValue(1);
+                    }
+                });
+    }
 }
--- a/test/hotspot/jtreg/runtime/appcds/ClassPathAttr.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/ClassPathAttr.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -68,29 +68,30 @@
                                                           "CpAttr4",
                                                           "CpAttr5"));
 
-      OutputAnalyzer output = TestCommon.execCommon(
+      TestCommon.run(
           "-cp", cp,
-          "CpAttr1");
-      TestCommon.checkExec(output);
+          "CpAttr1")
+        .assertNormalExit();
 
       // Logging test for class+path.
-      output = TestCommon.execCommon(
+      TestCommon.run(
           "-Xlog:class+path",
           "-cp", cp,
-          "CpAttr1");
-      if (!TestCommon.isUnableToMap(output)){
-        output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
-        output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
-      }
+          "CpAttr1")
+        .assertNormalExit(output -> {
+            output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
+            output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
+          });
+
       //  Make sure aliased TraceClassPaths still works
-      output = TestCommon.execCommon(
+      TestCommon.run(
           "-XX:+TraceClassPaths",
           "-cp", cp,
-          "CpAttr1");
-      if (!TestCommon.isUnableToMap(output)){
-        output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
-        output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
-      }
+          "CpAttr1")
+        .assertNormalExit(output -> {
+            output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
+            output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
+          });
     }
   }
 
--- a/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/HelloExtTest.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,8 @@
 
 /*
  * @test
- * @summary a simple test for loading a class using the ext class loader in AppCDS
+ * @summary a simple test for loading a class using the platform class loader
+ *          (which used to be called the "extension loader) in AppCDS
  * @requires vm.cds
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
@@ -53,19 +54,20 @@
         TestCommon.list("org/omg/CORBA/ORB", "[Ljava/lang/Comparable;"),
         bootClassPath, "-verbose:class", "--add-modules", "java.corba");
 
-    OutputAnalyzer output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
-        "-cp", appJar, bootClassPath, "-verbose:class", "--add-modules", "java.corba", "HelloExt");
-
     String prefix = ".class.load. ";
     String class_pattern = ".*LambdaForm[$]MH[/][0123456789].*";
     String suffix = ".*source: shared objects file.*";
     String pattern = prefix + class_pattern + suffix;
-    output.shouldNotMatch(pattern);
+
+    TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
+            "-cp", appJar, bootClassPath, "-verbose:class", "--add-modules", "java.corba", "HelloExt")
+        .assertNormalExit(output -> output.shouldNotMatch(pattern));
+
 
-    output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
-        "-cp", appJar, bootClassPath, "-verbose:class",
-        "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary",
-        "--add-modules", "java.corba", "HelloExt");
-    output.shouldNotMatch(class_pattern);
+    TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
+            "-cp", appJar, bootClassPath, "-verbose:class",
+            "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary",
+            "--add-modules", "java.corba", "HelloExt")
+        .assertNormalExit(output ->  output.shouldNotMatch(class_pattern));
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/IgnoreEmptyClassPaths.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/IgnoreEmptyClassPaths.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,12 +51,12 @@
     TestCommon.testDump(cp_dump, TestCommon.list("Hello", "HelloMore"),
                         "-XX:+TraceClassPaths", "-XX:+IgnoreEmptyClassPaths");
 
-    OutputAnalyzer output = TestCommon.execCommon(
+    TestCommon.run(
         "-verbose:class",
         "-cp", cp_exec,
         "-XX:+IgnoreEmptyClassPaths", // should affect classpath even if placed after the "-cp" argument
         "-XX:+TraceClassPaths",
-        "HelloMore");
-    TestCommon.checkExec(output);
+        "HelloMore")
+      .assertNormalExit();
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,8 +59,7 @@
     static void run(String[] extra_matches, String cp, String... args) throws Exception {
         String[] opts = {"-cp", cp, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", use_whitebox_jar};
         opts = TestCommon.concat(opts, args);
-        OutputAnalyzer output = TestCommon.execCommon(opts);
-        TestCommon.checkExec(output, extra_matches);
+        TestCommon.run(opts).assertNormalExit(extra_matches);
     }
 
     public static void main(String[] args) throws Exception {
--- a/test/hotspot/jtreg/runtime/appcds/OldClassTest.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/OldClassTest.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,11 +65,11 @@
     OutputAnalyzer output = TestCommon.dump(jar, appClasses);
     TestCommon.checkExecReturn(output, 0, true, "Pre JDK 1.5 class not supported by CDS");
 
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", jar,
         "-verbose:class",
-        "Hello");
-    TestCommon.checkExecReturn(output, 0, true, "Hello Unicode world (Old)");
+        "Hello")
+      .assertNormalExit("Hello Unicode world (Old)");
 
     // CASE 2: if we exlcude old version of this class, we should not pick up
     //         the newer version of this class in a subsequent classpath element.
@@ -77,11 +77,11 @@
     output = TestCommon.dump(classpath, appClasses);
     TestCommon.checkExecReturn(output, 0, true, "Pre JDK 1.5 class not supported by CDS");
 
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", classpath,
         "-verbose:class",
-        "Hello");
-    TestCommon.checkExecReturn(output, 0, true, "Hello Unicode world (Old)");
+        "Hello")
+      .assertNormalExit("Hello Unicode world (Old)");
   }
 
   static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception {
--- a/test/hotspot/jtreg/runtime/appcds/PrintSharedArchiveAndExit.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/PrintSharedArchiveAndExit.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,81 +67,79 @@
 
     TestCommon.testDump(cp, TestCommon.list("Hello"));
 
-    OutputAnalyzer output;
-
     log("Normal execution -- all the JAR paths should be checked");
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 0, true, lastCheckMsg);
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
 
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
         "-XX:+PrintSharedArchiveAndExit",
-        "-XX:+PrintSharedDictionary");  // Test PrintSharedDictionary as well.
-    check(output, 0, true, lastCheckMsg, "java.lang.Object");
+        "-XX:+PrintSharedDictionary")  // Test PrintSharedDictionary as well.
+      .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg, "java.lang.Object"));
 
     log("Normal execution -- Make sure -version, help message and app main()\n" +
         "class are not invoked. These are checked inside check().");
-    output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-version");
-    check(output, 0, true, lastCheckMsg);
+    TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-version")
+      .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
 
-    output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-help");
-    check(output, 0, true, lastCheckMsg);
+    TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-help")
+      .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
 
-    output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "Hello");
-    check(output, 0, true, lastCheckMsg);
+    TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "Hello")
+      .ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
 
     log("Execution with simple errors -- with 'simple' errors like missing or modified\n" +
         "JAR files, the VM should try to continue to print the remaining information.\n" +
         "Use an invalid Boot CP -- all the JAR paths should be checked");
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
         "-Xbootclasspath/a:foo.jar",
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 1, true, lastCheckMsg, "[BOOT classpath mismatch, ");
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[BOOT classpath mismatch, "));
 
     log("Use an App CP shorter than the one at dump time -- all the JAR paths should be checked");
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", ".",
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 1, true, lastCheckMsg, "Run time APP classpath is shorter than the one at dump time: .");
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "Run time APP classpath is shorter than the one at dump time: ."));
 
     log("Use an invalid App CP -- all the JAR paths should be checked");
     String invalidCP = "non-existing-dir" + File.pathSeparator + cp;
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", invalidCP,
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 1, true, lastCheckMsg, "APP classpath mismatch, actual: -Djava.class.path=" + invalidCP);
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "APP classpath mismatch, actual: -Djava.class.path=" + invalidCP));
 
     log("Changed modification time of hello.jar -- all the JAR paths should be checked");
     (new File(appJar)).setLastModified(System.currentTimeMillis() + 2000);
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 1, true, lastCheckMsg, "[Timestamp mismatch]");
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[Timestamp mismatch]"));
 
     log("Even if hello.jar is out of date, we should still be able to print the dictionary.");
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
         "-XX:+PrintSharedArchiveAndExit",
-        "-XX:+PrintSharedDictionary");  // Test PrintSharedDictionary as well.
-    check(output, 1, true, lastCheckMsg, "java.lang.Object");
+        "-XX:+PrintSharedDictionary")  // Test PrintSharedDictionary as well.
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "java.lang.Object"));
 
 
     log("Remove hello.jar -- all the JAR paths should be checked");
     (new File(appJar)).delete();
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
-        "-XX:+PrintSharedArchiveAndExit");
-    check(output, 1, true, lastCheckMsg, "[Required classpath entry does not exist: " + appJar + "]");
+        "-XX:+PrintSharedArchiveAndExit")
+      .ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[Required classpath entry does not exist: " + appJar + "]"));
 
     log("Execution with major errors -- with 'major' errors like the JSA file\n" +
         "is missing, we should stop immediately to avoid crashing the JVM.");
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", cp,
         "-XX:+PrintSharedArchiveAndExit",
-        "-XX:SharedArchiveFile=./no-such-fileappcds.jsa");
-    check(output, 1, false, lastCheckMsg);
+        "-XX:SharedArchiveFile=./no-such-fileappcds.jsa")
+      .ifNoMappingFailure(output -> check(output, 1, false, lastCheckMsg));
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -77,10 +77,10 @@
         OutputAnalyzer output;
 
         // -Xshare:on
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
-            "-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper");
-        TestCommon.checkExec(output, "Prohibited package name: java.lang");
+            "-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper")
+          .assertNormalExit("Prohibited package name: java.lang");
 
         // -Xshare:auto
         output = TestCommon.execAuto(
--- a/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/SpecifySysLoaderProp.java	Wed Feb 14 07:08:25 2018 -0800
@@ -51,56 +51,49 @@
 
     // (0) Baseline. Do not specify -Djava.system.class.loader
     //     The test class should be loaded from archive
-    OutputAnalyzer output = TestCommon.execCommon(
+    TestCommon.run(
         "-verbose:class",
         "-cp", appJar,
-        "ReportMyLoader");
-    TestCommon.checkExec(output,
-                         "[class,load] ReportMyLoader source: shared objects file",
-                         "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@");
+        "ReportMyLoader")
+      .assertNormalExit("[class,load] ReportMyLoader source: shared objects file",
+                        "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@");
 
     // (1) Try to execute the archive with -Djava.system.class.loader=no.such.Klass,
     //     it should fail
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-cp", appJar,
         "-Djava.system.class.loader=no.such.Klass",
-        "ReportMyLoader");
-    try {
-        output.shouldContain(warning);
-        output.shouldContain("ClassNotFoundException: no.such.Klass");
-    } catch (Exception e) {
-        TestCommon.checkCommonExecExceptions(output, e);
-    }
+        "ReportMyLoader")
+      .assertAbnormalExit(output -> {
+          output.shouldContain(warning);
+          output.shouldContain("ClassNotFoundException: no.such.Klass");
+        });
 
     // (2) Try to execute the archive with -Djava.system.class.loader=TestClassLoader,
     //     it should run, but AppCDS should be disabled
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-verbose:class",
         "-cp", appJar,
         "-Djava.system.class.loader=TestClassLoader",
-        "ReportMyLoader");
-    TestCommon.checkExec(output,
-                         "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", //<-this is still printed because TestClassLoader simply delegates to Launcher$AppLoader, but ...
-                         "TestClassLoader.called = true", //<-but this proves that TestClassLoader was indeed called.
-                         "TestClassLoader: loadClass(\"ReportMyLoader\","); //<- this also proves that TestClassLoader was indeed called.
-    try {
+        "ReportMyLoader")
+      .assertNormalExit("ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", //<-this is still printed because TestClassLoader simply delegates to Launcher$AppLoader, but ...
+             "TestClassLoader.called = true", //<-but this proves that TestClassLoader was indeed called.
+             "TestClassLoader: loadClass(\"ReportMyLoader\",") //<- this also proves that TestClassLoader was indeed called.
+      .assertNormalExit(output -> {
         output.shouldMatch(".class,load. TestClassLoader source: file:");
         output.shouldMatch(".class,load. ReportMyLoader source: file:.*" + jarFileName);
-    } catch (Exception e) {
-        TestCommon.checkCommonExecExceptions(output, e);
-    }
+        });
 
     // (3) Try to change the java.system.class.loader programmatically after
     //     the app's main method is executed. This should have no effect in terms of
     //     changing or switching the actual system class loader that's already in use.
-    output = TestCommon.execCommon(
+    TestCommon.run(
         "-verbose:class",
         "-cp", appJar,
-        "TrySwitchMyLoader");
-    TestCommon.checkExec(output,
-                         "[class,load] ReportMyLoader source: shared objects file",
-                         "TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
-                         "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
-                         "TestClassLoader.called = false");
+        "TrySwitchMyLoader")
+      .assertNormalExit("[class,load] ReportMyLoader source: shared objects file",
+             "TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
+             "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
+             "TestClassLoader.called = false");
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Wed Feb 14 07:08:25 2018 -0800
@@ -28,6 +28,7 @@
 import jdk.test.lib.Platform;
 import jdk.test.lib.cds.CDSOptions;
 import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.cds.CDSTestUtils.Result;
 import jdk.test.lib.process.ProcessTools;
 import jdk.test.lib.process.OutputAnalyzer;
 import java.io.File;
@@ -191,6 +192,14 @@
         return runWithArchive(opts);
     }
 
+    // This is the new API for running a Java process with CDS enabled.
+    // See comments in the CDSTestUtils.Result class for how to use this method.
+    public static Result run(String... suffix) throws Exception {
+        AppCDSOptions opts = (new AppCDSOptions());
+        opts.addSuffix(suffix);
+        return new Result(opts, runWithArchive(opts));
+    }
+
 
     public static OutputAnalyzer exec(String appJar, String... suffix) throws Exception {
         AppCDSOptions opts = (new AppCDSOptions()).setAppJar(appJar);
--- a/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -84,21 +84,22 @@
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps +
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar";
 
-        longClassPath += ps + appJar;
+        String myCP = longClassPath + ps + appJar;
         // Dump an archive with a specified JAR file in -classpath
-        TestCommon.testDump(longClassPath, TestCommon.list("Hello"));
+        TestCommon.testDump(myCP, TestCommon.list("Hello"));
 
         // Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths.
         // The diagnosis "expecting" app classpath trace should show the entire classpath.
-        OutputAnalyzer output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+TraceClassPaths",
             "-cp", appJar,
-            "Hello");
-        output.shouldContain("Unable to use shared archive");
-        output.shouldContain("shared class paths mismatch");
-        // the "expecting" app classpath from -XX:+TraceClassPaths should not
-        // be truncated
-        output.shouldContain(longClassPath);
-        output.shouldHaveExitValue(1);
+            "Hello")
+          .assertAbnormalExit(output -> {
+              output.shouldContain("Unable to use shared archive");
+              output.shouldContain("shared class paths mismatch");
+              // the "expecting" app classpath from -XX:+TraceClassPaths should not
+              // be truncated
+              output.shouldContain(myCP);
+            });
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/VerifierTest.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/VerifierTest.java	Wed Feb 14 07:08:25 2018 -0800
@@ -45,6 +45,7 @@
     static final String MAP_FAIL =
         "shared archive file was created with less restrictive verification setting";
     static final String VFY_ERR = "java.lang.VerifyError";
+    static final String PASS_RESULT = "Hi, how are you?";
 
     enum Testset1Part {
         A, B
@@ -110,12 +111,22 @@
         TestCommon.testDump(jar, appClasses);
     }
 
+    static void checkRuntimeOutput(OutputAnalyzer output, String expected) throws Exception {
+        output.shouldContain(expected);
+        if (expected.equals(PASS_RESULT) ||
+            expected.equals(VFY_ERR)) {
+            output.shouldHaveExitValue(0);
+        } else {
+            output.shouldNotHaveExitValue(0);
+        }
+    }
+
     static void testset_1(String jar, String[] noAppClasses, String[] appClasses, Testset1Part part)
         throws Exception
     {
         String config[][] = {
             // {dump_list, dumptime_verification_setting,
-            //  runtime_verification_setting, runtime_output},
+            //  runtime_verification_setting, expected_output_str},
 
             // Dump app/ext with -Xverify:remote
             {"app",   VFY_REMOTE, VFY_REMOTE, VFY_ERR},
@@ -166,7 +177,7 @@
                 noAppClasses;
             String dump_setting = config[i][1];
             String runtime_setting = config[i][2];
-            String runtime_output = config[i][3];
+            String expected_output_str = config[i][3];
             System.out.println("Test case [" + i + "]: dumping " + config[i][0] +
                                " with " + dump_setting +
                                ", run with " + runtime_setting);
@@ -178,17 +189,10 @@
                                                             "-Xms256m",
                                                             "-Xmx256m");
             }
-            OutputAnalyzer runtimeOutput = TestCommon.execCommon(
-                                                                 "-cp", jar,
-                                                                 runtime_setting,
-                                                                 "VerifierTest0");
-            try {
-                runtimeOutput.shouldContain(runtime_output);
-            } catch (RuntimeException re) {
-                // Check if the failure is due to archive mapping failure.
-                // If not, a RuntimeException will be thrown.
-                runtimeOutput.shouldContain("Unable to use shared archive");
-            }
+            TestCommon.run("-cp", jar,
+                           runtime_setting,
+                           "VerifierTest0")
+                .ifNoMappingFailure(output -> checkRuntimeOutput(output, expected_output_str));
             prev_dump_setting = dump_setting;
         }
     }
@@ -204,10 +208,9 @@
                                      "Hi$MyClass");
         jar = TestCommon.getTestJar(jarName_hi + ".jar") + File.pathSeparator +
             TestCommon.getTestJar(jarName_greet + ".jar");
-        final String PASS_RESULT = "Hi, how are you?";
         String config2[][] = {
             // {dump_list, dumptime_verification_setting,
-            //  runtime_verification_setting, runtime_output},
+            //  runtime_verification_setting, expected_output_str},
 
             // Dump app/ext with -Xverify:remote
             {"app",   VFY_REMOTE, VFY_REMOTE, PASS_RESULT},
@@ -226,7 +229,7 @@
             // config2[i][0] is always set to "app" in this test
             String dump_setting = config2[i][1];
             String runtime_setting = config2[i][2];
-            String runtime_output = config2[i][3];
+            String expected_output_str = config2[i][3];
             System.out.println("Test case [" + i + "]: dumping " + config2[i][0] +
                                " with " + dump_setting +
                                ", run with " + runtime_setting);
@@ -237,19 +240,11 @@
                                                         // issue - assert failure when dumping archive with the -Xverify:all
                                                         "-Xms256m",
                                                         "-Xmx256m");
-            OutputAnalyzer runtimeOutput = TestCommon.execCommon(
-                                                                 "-cp", jar,
-                                                                 runtime_setting,
-                                                                 "Hi");
-            try {
-                runtimeOutput.shouldContain(runtime_output);
-            } catch (RuntimeException re) {
-                // Check if the failure is due to archive mapping failure.
-                // If not, a RuntimeException will be thrown.
-                runtimeOutput.shouldContain("Unable to use shared archive");
-            }
+            TestCommon.run("-cp", jar,
+                           runtime_setting,
+                           "Hi")
+                .ifNoMappingFailure(output -> checkRuntimeOutput(output, expected_output_str));
         }
-
     }
 
     static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception {
--- a/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,11 +45,10 @@
     TestCommon.testDump(appJar, TestCommon.list("Hello"));
 
     // Then try to execute the archive without -classpath -- it should fail
-    OutputAnalyzer output = TestCommon.execCommon(
+    TestCommon.run(
         /* "-cp", appJar, */ // <- uncomment this and the execution should succeed
-        "Hello");
-    output.shouldContain("Unable to use shared archive");
-    output.shouldContain("shared class paths mismatch");
-    output.shouldHaveExitValue(1);
+        "Hello")
+      .assertAbnormalExit("Unable to use shared archive",
+                          "shared class paths mismatch");
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/ArrayTest.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/ArrayTest.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,6 @@
         }
         String[] opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        output = TestCommon.execCommon(opts);
-        TestCommon.checkExec(output);
+        TestCommon.run(opts).assertNormalExit();
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/CheckAnonymousClass.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,9 +44,6 @@
     TestCommon.dump(appJar, TestCommon.list("Hello", "org/omg/CORBA/ORB"),
         "--add-modules", "java.corba", "-Xlog:class+load=info");
 
-    OutputAnalyzer output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions",
-        "-cp", appJar, "-Xlog:class+load=info", "--add-modules", "java.corba", "Hello");
-
     String prefix = ".class.load. ";
     // class name pattern like the following:
     // jdk.internal.loader.BuiltinClassLoader$$Lambda$1/1816757085
@@ -55,20 +52,14 @@
     String suffix = ".*source: shared objects file.*";
     String pattern = prefix + class_pattern + suffix;
     // during run time, anonymous classes shouldn't be loaded from the archive
-    try {
-        output.shouldNotMatch(pattern);
-    } catch (Exception e) {
-        TestCommon.checkCommonExecExceptions(output, e);
-    }
+    TestCommon.run("-XX:+UnlockDiagnosticVMOptions",
+        "-cp", appJar, "-Xlog:class+load=info", "--add-modules", "java.corba", "Hello")
+      .assertNormalExit(output -> output.shouldNotMatch(pattern));
 
     // inspect the archive and make sure no anonymous class is in there
-    output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions",
+    TestCommon.run("-XX:+UnlockDiagnosticVMOptions",
         "-cp", appJar, "-Xlog:class+load=info", "-XX:+PrintSharedArchiveAndExit",
-        "-XX:+PrintSharedDictionary", "--add-modules", "java.corba", "Hello");
-    try {
-        output.shouldNotMatch(class_pattern);
-    } catch (Exception e) {
-        TestCommon.checkCommonExecExceptions(output, e);
-    }
+        "-XX:+PrintSharedDictionary", "--add-modules", "java.corba", "Hello")
+      .assertNormalExit(output -> output.shouldNotMatch(class_pattern));
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDump.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCDuringDump.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,13 +67,13 @@
             TestCommon.testDump(appJar, TestCommon.list("Hello"),
                                 extraArg, "-Xmx32m", gcLog);
 
-            OutputAnalyzer output = TestCommon.execCommon(
+            TestCommon.run(
                 "-cp", appJar,
                 "-Xmx32m",
                 "-XX:+PrintSharedSpaces",
                 gcLog,
-                "Hello");
-            TestCommon.checkExec(output);
+                "Hello")
+              .assertNormalExit();
         }
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -113,7 +113,7 @@
                     "-XX:SharedArchiveConfigFile=" + sharedArchiveCfgFile);
             }
 
-            output = TestCommon.execCommon(
+            TestCommon.run(
                 "-cp", appJar,
                 bootClassPath,
                 "-Xmx32m",
@@ -124,8 +124,8 @@
                 "-XX:+WhiteBoxAPI",
                 "-XX:SharedReadOnlySize=30m",
                 gcLog,
-                "GCSharedStringsDuringDumpWb");
-            TestCommon.checkExec(output);
+                "GCSharedStringsDuringDumpWb")
+              .assertNormalExit();
         }
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,13 +90,13 @@
 
         String classPath = appJar + File.pathSeparator + classDir;
         System.out.println("classPath: " + classPath);
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "-cp", classPath,
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
-            "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello");
-        TestCommon.checkExec(output,
+            "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello")
+          .assertNormalExit(
             "I pass!",
             "Hello!",
             "Hello source: shared objects file");
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,12 +72,12 @@
                 "PatchMain", "javax.naming.myspi.NamingManager");
         TestCommon.checkDump(output, "Preload Warning: Cannot find javax/naming/myspi/NamingManager");
 
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.myspi.NamingManager");
-        TestCommon.checkExec(output, "I pass!");
+            "PatchMain", "javax.naming.myspi.NamingManager")
+          .assertNormalExit("I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,12 +72,12 @@
         TestCommon.checkDump(output, "Loading classes to share");
 
         // javax.naming.spi.NamingManager is not patched at runtime
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming2=" + moduleJar,
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        output.shouldNotContain("I pass!");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit(o -> o.shouldNotContain("I pass!"));
 
         // Case 2: --patch-module specified for dump time but not for run time
         System.out.println("Case 2: --patch-module specified for dump time but not for run time");
@@ -89,11 +89,11 @@
         TestCommon.checkDump(output, "Loading classes to share");
 
         // javax.naming.spi.NamingManager is not patched at runtime
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        output.shouldNotContain("I pass!");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit(o -> o.shouldNotContain("I pass!"));
 
         // Case 3: --patch-module specified for run time but not for dump time
         System.out.println("Case 3: --patch-module specified for run time but not for dump time");
@@ -104,12 +104,12 @@
         TestCommon.checkDump(output, "Loading classes to share");
 
         // javax.naming.spi.NamingManager is patched at runtime
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkExec(output, "I pass!");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit("I pass!");
 
         // Case 4: mismatched --patch-module entry counts between dump time and run time
         System.out.println("Case 4: mismatched --patch-module entry counts between dump time and run time");
@@ -121,12 +121,12 @@
         TestCommon.checkDump(output, "Loading classes to share");
 
         // javax.naming.spi.NamingManager is patched at runtime
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar,
             "--patch-module=java.naming2=" + moduleJar,
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkExec(output, "I pass!");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit("I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,10 +64,11 @@
                 "PatchMain", "java.lang.NewClass");
         TestCommon.checkDump(output, "Loading classes to share");
 
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.base=" + moduleJar,
-            "PatchMain", "java.lang.NewClass");
-        output.shouldContain("CDS is disabled when java.base module is patched");
+            "PatchMain", "java.lang.NewClass")
+          .assertAbnormalExit("Unable to use shared archive",
+                              "CDS is disabled when java.base module is patched");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java	Wed Feb 14 07:08:25 2018 -0800
@@ -70,12 +70,12 @@
                 "PatchMain", "javax.naming.spi.NamingManager");
         TestCommon.checkDump(output, "Loading classes to share");
 
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkExec(output, "I pass!");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit("I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,13 +92,13 @@
 
         String classPath = appJar + File.pathSeparator + classDir;
         System.out.println("classPath: " + classPath);
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "-cp", classPath,
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
-            "PatchMain", "javax.naming.Reference", "mypackage.MyReference");
-        TestCommon.checkExec(output,
+            "PatchMain", "javax.naming.Reference", "mypackage.MyReference")
+          .assertNormalExit(
             "I pass!",
             "MyReference source: file:");
     }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -89,12 +89,12 @@
                 "PatchMain", "javax.naming.spi.NamingManager");
         TestCommon.checkDump(output, "Loading classes to share");
 
-        output = TestCommon.execCommon(
+        TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar2 + File.pathSeparator + moduleJar,
             "-Xlog:class+load",
             "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkExec(output, "I pass");
+            "PatchMain", "javax.naming.spi.NamingManager")
+          .assertNormalExit("I pass");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/DummyClassesInBootClassPath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -70,10 +70,10 @@
         }
         String[] arguments = new String[argsList.size()];
         arguments = argsList.toArray(arguments);
-        OutputAnalyzer execOutput = TestCommon.execCommon(
+        Testcommon.run(
             "--add-modules", "java.activation", "-Xbootclasspath/a:" + appJar,
-            "DummyClassHelper", arguments[0], arguments[1]);
-        checkOutput(execOutput, classNames);
+            "DummyClassHelper", arguments[0], arguments[1])
+          .assertNormalExit(output -> checkOutput(output, classNames));
 
         JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox");
         String whiteBoxJar = TestCommon.getTestJar("WhiteBox.jar");
@@ -87,8 +87,8 @@
         String[] opts = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
             "--add-modules", "java.activation", bootClassPath, "-Xlog:class+path=trace",
             "DummyClassHelper", arguments[0], arguments[1], arguments[2]};
-        execOutput = TestCommon.execCommon(opts);
-        checkOutput(execOutput, classNames);
+        Testcommon.run(opts)
+          .assertNormalExit(output -> checkOutput(output, classNames));
     }
 }
 
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -73,16 +73,14 @@
         argsList.add("useAppLoader");
         String[] opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        OutputAnalyzer runOutput = TestCommon.execCommon(opts);
-        TestCommon.checkExec(runOutput, "appLoader found method main");
+        TestCommon.run(opts).assertNormalExit("appLoader found method main");
 
         // case 2: load class in bootclasspath using boot loader
         argsList.remove(argsList.size() - 1);
         argsList.add("useBootLoader");
         opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        runOutput = TestCommon.execCommon(opts);
-        TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
+        TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
 
         // case 3: load class in bootclasspath using app loader with '--limit-modules java.base'
         argsList.add(0, "--limit-modules");
@@ -91,16 +89,13 @@
         argsList.add("useAppLoader");
         opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        runOutput = TestCommon.execCommon(opts);
-        TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
+        TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
 
         // case 4: load class in bootclasspath using boot loader with '--limit-modules java.base'
         argsList.remove(argsList.size() - 1);
         argsList.add("useBootLoader");
         opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        runOutput = TestCommon.execCommon(opts);
-        TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
-
+        TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -113,10 +113,9 @@
             log("runTestWithAppLoader(): testCaseId = %d", entry.testCaseId);
             String params = TransformTestCommon.getAgentParams(entry, parent, child);
             String agentParam = String.format("-javaagent:%s=%s", agentJar, params);
-            out = TestCommon.execCommon("-Xlog:class+load=info", "-cp", appJar,
-                                        agentParam, child);
-
-            TransformTestCommon.checkResults(entry, out, parent, child);
+            TestCommon.run("-Xlog:class+load=info", "-cp", appJar,
+                           agentParam, child)
+              .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
         }
     }
 
@@ -187,13 +186,13 @@
         String agentParam = "-javaagent:" + agentJar + "=" +
             TransformTestCommon.getAgentParams(entry, parent, child);
 
-        out = TestCommon.execCommon("-Xlog:class+load=info",
-                                    "-cp", appJar,
-                                    "--add-opens=java.base/java.security=ALL-UNNAMED",
-                                    agentParam,
-                                    "CustomLoaderApp",
-                                    customJar, loaderType, child);
-        TransformTestCommon.checkResults(entry, out, parent, child);
+        TestCommon.run("-Xlog:class+load=info",
+                       "-cp", appJar,
+                       "--add-opens=java.base/java.security=ALL-UNNAMED",
+                       agentParam,
+                       "CustomLoaderApp",
+                       customJar, loaderType, child)
+          .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
     }
 
 
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Thu Feb 15 09:22:25 2018 -0800
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Wed Feb 14 07:08:25 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,160 @@
 
 // This class contains common test utilities for testing CDS
 public class CDSTestUtils {
+    public interface Checker {
+        public void check(OutputAnalyzer output) throws Exception;
+    }
+
+    /*
+     * INTRODUCTION
+     *
+     * When testing various CDS functionalities, we need to launch JVM processes
+     * using a "launch method" (such as TestCommon.run), and analyze the results of these
+     * processes.
+     *
+     * While typical jtreg tests would use OutputAnalyzer in such cases, due to the
+     * complexity of CDS failure modes, we have added the CDSTestUtils.Result class
+     * to make the analysis more convenient and less error prone.
+     *
+     * A Java process can end in one of the following 4 states:
+     *
+     *    1: Unexpected error - such as JVM crashing. In this case, the "launch method"
+     *                          will throw a RuntimeException.
+     *    2: Mapping Failure  - this happens when the OS (intermittently) fails to map the
+     *                          CDS archive, normally caused by Address Space Layout Randomization.
+     *                          We usually treat this as "pass".
+     *    3: Normal Exit      - the JVM process has finished without crashing, and the exit code is 0.
+     *    4: Abnormal Exit    - the JVM process has finished without crashing, and the exit code is not 0.
+     *
+     * In most test cases, we need to check the JVM process's output in cases 3 and 4. However, we need
+     * to make sure that our test code is not confused by case 2.
+     *
+     * For example, a JVM process is expected to print the string "Hi" and exit with 0. With the old
+     * CDSTestUtils.runWithArchive API, the test may be written as this:
+     *
+     *     OutputAnalyzer out = CDSTestUtils.runWithArchive(args);
+     *     out.shouldContain("Hi");
+     *
+     * However, if the JVM process fails with mapping failure, the string "Hi" will not be in the output,
+     * and your test case will fail intermittently.
+     *
+     * Instead, the test case should be written as
+     *
+     *      CCDSTestUtils.run(args).assertNormalExit("Hi");
+     *
+     * EXAMPLES/HOWTO
+     *
+     * 1. For simple substring matching:
+     *
+     *      CCDSTestUtils.run(args).assertNormalExit("Hi");
+     *      CCDSTestUtils.run(args).assertNormalExit("a", "b", "x");
+     *      CCDSTestUtils.run(args).assertAbnormalExit("failure 1", "failure2");
+     *
+     * 2. For more complex output matching: using Lambda expressions
+     *
+     *      CCDSTestUtils.run(args)
+     *         .assertNormalExit(output -> output.shouldNotContain("this should not be printed");
+     *      CCDSTestUtils.run(args)
+     *         .assertAbnormalExit(output -> {
+     *             output.shouldNotContain("this should not be printed");
+     *             output.shouldHaveExitValue(123);
+     *           });
+     *
+     * 3. Chaining several checks:
+     *
+     *      CCDSTestUtils.run(args)
+     *         .assertNormalExit(output -> output.shouldNotContain("this should not be printed")
+     *         .assertNormalExit("should have this", "should have that");
+     *
+     * 4. [Rare use case] if a test sometimes exit normally, and sometimes abnormally:
+     *
+     *      CCDSTestUtils.run(args)
+     *         .ifNormalExit("ths string is printed when exiting with 0")
+     *         .ifAbNormalExit("ths string is printed when exiting with 1");
+     *
+     *    NOTE: you usually don't want to write your test case like this -- it should always
+     *    exit with the same exit code. (But I kept this API because some existing test cases
+     *    behave this way -- need to revisit).
+     */
+    public static class Result {
+        private final OutputAnalyzer output;
+        private final CDSOptions options;
+        private final boolean hasMappingFailure;
+        private final boolean hasAbnormalExit;
+        private final boolean hasNormalExit;
+
+        public Result(CDSOptions opts, OutputAnalyzer out) throws Exception {
+            options = opts;
+            output = out;
+            hasMappingFailure = CDSTestUtils.checkCommonExecExceptions(output);
+            hasAbnormalExit   = (!hasMappingFailure) && (output.getExitValue() != 0);
+            hasNormalExit     = (!hasMappingFailure) && (output.getExitValue() == 0);
+
+            if (hasNormalExit) {
+                if ("on".equals(options.xShareMode) && output.getStderr().contains("java version")) {
+                    // "-showversion" is always passed in the command-line by the execXXX methods.
+                    // During normal exit, we require that the VM to show that sharing was enabled.
+                    output.shouldContain("sharing");
+                }
+            }
+        }
+
+        public Result assertNormalExit(Checker checker) throws Exception {
+            if (!hasMappingFailure) {
+                checker.check(output);
+                output.shouldHaveExitValue(0);
+            }
+            return this;
+        }
+
+        public Result assertAbnormalExit(Checker checker) throws Exception {
+            if (!hasMappingFailure) {
+                checker.check(output);
+                output.shouldNotHaveExitValue(0);
+            }
+            return this;
+        }
+
+        public Result ifNormalExit(Checker checker) throws Exception {
+            if (hasNormalExit) {
+                checker.check(output);
+            }
+            return this;
+        }
+
+        public Result ifAbnormalExit(Checker checker) throws Exception {
+            if (hasAbnormalExit) {
+                checker.check(output);
+            }
+            return this;
+        }
+
+        public Result ifNoMappingFailure(Checker checker) throws Exception {
+            if (!hasMappingFailure) {
+                checker.check(output);
+            }
+            return this;
+        }
+
+
+        public Result assertNormalExit(String... matches) throws Exception {
+            if (!hasMappingFailure) {
+                checkMatches(output, matches);
+                output.shouldHaveExitValue(0);
+            }
+            return this;
+        }
+
+        public Result assertAbnormalExit(String... matches) throws Exception {
+            if (!hasMappingFailure) {
+                checkMatches(output, matches);
+                output.shouldNotHaveExitValue(0);
+            }
+
+            return this;
+        }
+    }
+
     // Specify this property to copy sdandard output of the child test process to
     // the parent/main stdout of the test.
     // By default such output is logged into a file, and is copied into the main stdout.
@@ -119,7 +273,7 @@
     // of exceptions and common errors.
     // Exception e argument - an exception to be re-thrown if none of the common
     // exceptions match. Pass null if you wish not to re-throw any exception.
-    public static void checkCommonExecExceptions(OutputAnalyzer output, Exception e)
+    public static boolean checkCommonExecExceptions(OutputAnalyzer output, Exception e)
         throws Exception {
         if (output.getStdout().contains("http://bugreport.java.com/bugreport/crash.jsp")) {
             throw new RuntimeException("Hotspot crashed");
@@ -128,7 +282,7 @@
             throw new RuntimeException("Test Failed");
         }
         if (output.getOutput().contains("shared class paths mismatch")) {
-            throw new RuntimeException("shared class paths mismatch");
+//            throw new RuntimeException("shared class paths mismatch");
         }
         if (output.getOutput().contains("Unable to unmap shared space")) {
             throw new RuntimeException("Unable to unmap shared space");
@@ -139,11 +293,17 @@
         // and can be random (see ASLR).
         if (isUnableToMap(output)) {
             System.out.println(UnableToMapMsg);
-            return;
+            return true;
         }
 
-        if (e != null)
+        if (e != null) {
             throw e;
+        }
+        return false;
+    }
+
+    public static boolean checkCommonExecExceptions(OutputAnalyzer output) throws Exception {
+        return checkCommonExecExceptions(output, null);
     }
 
 
@@ -176,6 +336,12 @@
         return false;
     }
 
+    public static Result run(String... cliPrefix) throws Exception {
+        CDSOptions opts = new CDSOptions();
+        opts.setArchiveName(getDefaultArchiveName());
+        opts.addPrefix(cliPrefix);
+        return new Result(opts, runWithArchive(opts));
+    }
 
     // Execute JVM with CDS archive, specify command line args suffix
     public static OutputAnalyzer runWithArchive(String... cliPrefix)
@@ -246,7 +412,7 @@
             return output;
         }
 
-        checkExtraMatches(output, extraMatches);
+        checkMatches(output, extraMatches);
         return output;
     }
 
@@ -260,13 +426,13 @@
         }
 
         output.shouldHaveExitValue(expectedExitValue);
-        checkExtraMatches(output, extraMatches);
+        checkMatches(output, extraMatches);
         return output;
     }
 
-    public static OutputAnalyzer checkExtraMatches(OutputAnalyzer output,
-                                                    String... extraMatches) throws Exception {
-        for (String match : extraMatches) {
+    public static OutputAnalyzer checkMatches(OutputAnalyzer output,
+                                              String... matches) throws Exception {
+        for (String match : matches) {
             output.shouldContain(match);
         }
         return output;