8138983: Runtime: implement ranges for Shared*** flags
authorgziemski
Thu, 19 Nov 2015 16:32:41 -0600
changeset 34242 e530decd7c63
parent 34234 e4a23d294f48
child 34243 6f30855e2310
8138983: Runtime: implement ranges for Shared*** flags Summary: Implement ranges. Reviewed-by: ddmitriev, dholmes, jiangli
hotspot/src/share/vm/classfile/compactHashtable.cpp
hotspot/src/share/vm/memory/metaspace.cpp
hotspot/src/share/vm/memory/metaspaceShared.hpp
hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp
hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp
hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java
hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java
hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java
hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp	Thu Nov 19 16:32:41 2015 -0600
@@ -137,7 +137,7 @@
   if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
     base_address = uintx(MetaspaceShared::shared_rs()->base());
     max_delta    = uintx(MetaspaceShared::shared_rs()->size());
-    assert(max_delta <= 0x7fffffff, "range check");
+    assert(max_delta <= MAX_SHARED_DELTA, "range check");
   } else {
     assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
     assert(UseCompressedOops, "UseCompressedOops is required");
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Thu Nov 19 16:32:41 2015 -0600
@@ -3230,36 +3230,6 @@
     SharedMiscDataSize  = align_size_up(SharedMiscDataSize,  max_alignment);
     SharedMiscCodeSize  = align_size_up(SharedMiscCodeSize,  max_alignment);
 
-    // make sure SharedReadOnlySize and SharedReadWriteSize are not less than
-    // the minimum values.
-    if (SharedReadOnlySize < MetaspaceShared::min_ro_size){
-      report_out_of_shared_space(SharedReadOnly);
-    }
-
-    if (SharedReadWriteSize < MetaspaceShared::min_rw_size){
-      report_out_of_shared_space(SharedReadWrite);
-    }
-
-    // the min_misc_data_size and min_misc_code_size estimates are based on
-    // MetaspaceShared::generate_vtable_methods().
-    // The minimum size only accounts for the vtable methods. Any size less than the
-    // minimum required size would cause vm crash when allocating the vtable methods.
-    uint min_misc_data_size = align_size_up(
-      MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
-
-    if (SharedMiscDataSize < min_misc_data_size) {
-      report_out_of_shared_space(SharedMiscData);
-    }
-
-    uintx min_misc_code_size = align_size_up(
-      (MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) *
-        (sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size,
-          max_alignment);
-
-    if (SharedMiscCodeSize < min_misc_code_size) {
-      report_out_of_shared_space(SharedMiscCode);
-    }
-
     // Initialize with the sum of the shared space sizes.  The read-only
     // and read write metaspace chunks will be allocated out of this and the
     // remainder is the misc code and data chunks.
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Thu Nov 19 16:32:41 2015 -0600
@@ -32,14 +32,55 @@
 #include "utilities/exceptions.hpp"
 #include "utilities/macros.hpp"
 
-#define LargeSharedArchiveSize    (300*M)
-#define HugeSharedArchiveSize     (800*M)
-#define ReadOnlyRegionPercentage  0.4
-#define ReadWriteRegionPercentage 0.55
-#define MiscDataRegionPercentage  0.03
-#define MiscCodeRegionPercentage  0.02
-#define LargeThresholdClassCount  5000
-#define HugeThresholdClassCount   40000
+#define DEFAULT_VTBL_LIST_SIZE          (17)  // number of entries in the shared space vtable list.
+#define DEFAULT_VTBL_VIRTUALS_COUNT     (200) // maximum number of virtual functions
+// If virtual functions are added to Metadata,
+// this number needs to be increased.  Also,
+// SharedMiscCodeSize will need to be increased.
+// The following 2 sizes were based on
+// MetaspaceShared::generate_vtable_methods()
+#define DEFAULT_VTBL_METHOD_SIZE        (16)  // conservative size of the mov1 and jmp instructions
+// for the x64 platform
+#define DEFAULT_VTBL_COMMON_CODE_SIZE   (1*K) // conservative size of the "common_code" for the x64 platform
+
+#define DEFAULT_SHARED_READ_WRITE_SIZE  (NOT_LP64(12*M) LP64_ONLY(16*M))
+#define MIN_SHARED_READ_WRITE_SIZE      (NOT_LP64(7*M) LP64_ONLY(12*M))
+
+#define DEFAULT_SHARED_READ_ONLY_SIZE   (NOT_LP64(12*M) LP64_ONLY(16*M))
+#define MIN_SHARED_READ_ONLY_SIZE       (NOT_LP64(8*M) LP64_ONLY(9*M))
+
+// the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on
+// MetaspaceShared::generate_vtable_methods().
+// The minimum size only accounts for the vtable methods. Any size less than the
+// minimum required size would cause vm crash when allocating the vtable methods.
+#define SHARED_MISC_SIZE_FOR(size)      (DEFAULT_VTBL_VIRTUALS_COUNT*DEFAULT_VTBL_LIST_SIZE*size)
+
+#define DEFAULT_SHARED_MISC_DATA_SIZE   (NOT_LP64(2*M) LP64_ONLY(4*M))
+#define MIN_SHARED_MISC_DATA_SIZE       (SHARED_MISC_SIZE_FOR(sizeof(void*)))
+
+#define DEFAULT_SHARED_MISC_CODE_SIZE   (120*K)
+#define MIN_SHARED_MISC_CODE_SIZE       (SHARED_MISC_SIZE_FOR(sizeof(void*))+SHARED_MISC_SIZE_FOR(DEFAULT_VTBL_METHOD_SIZE)+DEFAULT_VTBL_COMMON_CODE_SIZE)
+
+#define DEFAULT_COMBINED_SIZE           (DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)
+
+// the max size is the MAX size (ie. 0x7FFFFFFF) - the total size of
+// the other 3 sections - page size (to avoid overflow in case the final
+// size will get aligned up on page size)
+#define SHARED_PAGE                     ((size_t)os::vm_page_size())
+#define MAX_SHARED_DELTA                (0x7FFFFFFF)
+#define MAX_SHARED_READ_WRITE_SIZE      (MAX_SHARED_DELTA-(MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_READ_ONLY_SIZE       (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_MISC_DATA_SIZE       (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
+#define MAX_SHARED_MISC_CODE_SIZE       (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE)-SHARED_PAGE)
+
+#define LargeSharedArchiveSize          (300*M)
+#define HugeSharedArchiveSize           (800*M)
+#define ReadOnlyRegionPercentage        0.4
+#define ReadWriteRegionPercentage       0.55
+#define MiscDataRegionPercentage        0.03
+#define MiscCodeRegionPercentage        0.02
+#define LargeThresholdClassCount        5000
+#define HugeThresholdClassCount         40000
 
 #define SET_ESTIMATED_SIZE(type, region)                              \
   Shared ##region## Size  = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
@@ -69,21 +110,10 @@
   static bool _archive_loading_failed;
  public:
   enum {
-    vtbl_list_size         = 17,   // number of entries in the shared space vtable list.
-    num_virtuals           = 200,  // maximum number of virtual functions
-                                   // If virtual functions are added to Metadata,
-                                   // this number needs to be increased.  Also,
-                                   // SharedMiscCodeSize will need to be increased.
-                                   // The following 2 sizes were based on
-                                   // MetaspaceShared::generate_vtable_methods()
-    vtbl_method_size       = 16,   // conservative size of the mov1 and jmp instructions
-                                   // for the x64 platform
-    vtbl_common_code_size  = (1*K) // conservative size of the "common_code" for the x64 platform
-  };
-
-  enum {
-    min_ro_size = NOT_LP64(8*M) LP64_ONLY(9*M), // minimum ro and rw regions sizes based on dumping
-    min_rw_size = NOT_LP64(7*M) LP64_ONLY(12*M) // of a shared archive using the default classlist
+    vtbl_list_size         = DEFAULT_VTBL_LIST_SIZE,
+    num_virtuals           = DEFAULT_VTBL_VIRTUALS_COUNT,
+    vtbl_method_size       = DEFAULT_VTBL_METHOD_SIZE,
+    vtbl_common_code_size  = DEFAULT_VTBL_COMMON_CODE_SIZE
   };
 
   enum {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp	Thu Nov 19 16:32:41 2015 -0600
@@ -223,7 +223,7 @@
 #define EMIT_CONSTRAINT_CHECK(func, type)                               , func, CommandLineFlagConstraint::type
 
 // the "name" argument must be a string literal
-#define INITIAL_CONSTRAINTS_SIZE 45
+#define INITIAL_CONSTRAINTS_SIZE 69
 GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
 CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
 
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp	Thu Nov 19 16:32:41 2015 -0600
@@ -279,7 +279,7 @@
 // Generate func argument to pass into emit_range_xxx functions
 #define EMIT_RANGE_CHECK(a, b)                               , a, b
 
-#define INITIAL_RANGES_SIZE 205
+#define INITIAL_RANGES_SIZE 320
 GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
 
 // Check the ranges of all flags that have them
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp	Thu Nov 19 16:32:41 2015 -0600
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
 #define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
 
+#include "memory/metaspaceShared.hpp"
 #include "runtime/globals.hpp"
 #include "utilities/growableArray.hpp"
 
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Thu Nov 19 16:32:41 2015 -0600
@@ -4110,21 +4110,26 @@
           "If PrintSharedArchiveAndExit is true, also print the shared "    \
           "dictionary")                                                     \
                                                                             \
-  product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M),      \
+  product(size_t, SharedReadWriteSize, DEFAULT_SHARED_READ_WRITE_SIZE,      \
           "Size of read-write space for metadata (in bytes)")               \
-                                                                            \
-  product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M),       \
+          range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE)     \
+                                                                            \
+  product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE,        \
           "Size of read-only space for metadata (in bytes)")                \
-                                                                            \
-  product(uintx, SharedMiscDataSize,    NOT_LP64(2*M) LP64_ONLY(4*M),       \
+          range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE)       \
+                                                                            \
+  product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE,        \
           "Size of the shared miscellaneous data area (in bytes)")          \
-                                                                            \
-  product(uintx, SharedMiscCodeSize,    120*K,                              \
+          range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE)       \
+                                                                            \
+  product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE,        \
           "Size of the shared miscellaneous code area (in bytes)")          \
-                                                                            \
-  product(uintx, SharedBaseAddress, LP64_ONLY(32*G)                         \
+          range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE)       \
+                                                                            \
+  product(size_t, SharedBaseAddress, LP64_ONLY(32*G)                        \
           NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)),                           \
           "Address to allocate shared memory region for class data")        \
+          range(0, SIZE_MAX)                                                \
                                                                             \
   product(uintx, SharedSymbolTableBucketSize, 4,                            \
           "Average number of symbols per bucket in shared table")           \
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java	Thu Nov 19 16:32:41 2015 -0600
@@ -55,10 +55,29 @@
          * JDK-8136766
          * Temporarily remove ThreadStackSize from testing because Windows can set it to 0
          * (for default OS size) but other platforms insist it must be greater than 0
-        */
+         */
         allOptionsAsMap.remove("ThreadStackSize");
 
         /*
+         * JDK-8141650
+         * Temporarily exclude SharedMiscDataSize as it will exit the VM with exit code 2 and
+         * "The shared miscellaneous data space is not large enough to preload requested classes."
+         * message at min value.
+         */
+        allOptionsAsMap.remove("SharedMiscDataSize");
+
+        /*
+         * JDK-8142874
+         * Temporarily exclude Shared* flagse as they will exit the VM with exit code 2 and
+         * "The shared miscellaneous data space is not large enough to preload requested classes."
+         * message at max values.
+         */
+        allOptionsAsMap.remove("SharedReadWriteSize");
+        allOptionsAsMap.remove("SharedReadOnlySize");
+        allOptionsAsMap.remove("SharedMiscDataSize");
+        allOptionsAsMap.remove("SharedMiscCodeSize");
+
+        /*
          * Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0)
          */
         allOptionsAsMap.remove("MallocMaxTestWords");
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java	Thu Nov 19 16:32:41 2015 -0600
@@ -223,7 +223,7 @@
             validValues.add("1");
         }
 
-        if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) {
+        if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) {
             /*
              * Check for overflow when flag is assigned to the
              * 4 byte int variable
@@ -231,7 +231,7 @@
             validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
         }
 
-        if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) {
+        if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) {
             /*
              * Check for overflow when flag is assigned to the
              * 4 byte unsigned int variable
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java	Thu Nov 19 16:32:41 2015 -0600
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -49,6 +50,8 @@
     /* Used to start the JVM with the same type as current */
     static String VMType;
 
+    private static Map<String, JVMOption> optionsAsMap;
+
     static {
         if (Platform.isServer()) {
             VMType = "-server";
@@ -63,6 +66,84 @@
         }
     }
 
+    public static boolean fitsRange(String optionName, BigDecimal number) throws Exception {
+        JVMOption option;
+        String minRangeString = null;
+        String maxRangeString = null;
+        boolean fits = true;
+
+        if (optionsAsMap == null) {
+            optionsAsMap = getOptionsWithRangeAsMap();
+        }
+
+        option = optionsAsMap.get(optionName);
+        if (option != null) {
+            minRangeString = option.getMin();
+            if (minRangeString != null) {
+                fits = (number.compareTo(new BigDecimal(minRangeString)) >= 0);
+            }
+            maxRangeString = option.getMax();
+            if (maxRangeString != null) {
+                fits &= (number.compareTo(new BigDecimal(maxRangeString)) <= 0);
+            }
+        }
+
+        return fits;
+    }
+
+    public static boolean fitsRange(String optionName, String number) throws Exception {
+        String lowerCase = number.toLowerCase();
+        String multiplier = "1";
+        if (lowerCase.endsWith("k")) {
+            multiplier = "1024";
+            lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+        } else if (lowerCase.endsWith("m")) {
+            multiplier = "1048576"; //1024*1024
+            lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+        } else if (lowerCase.endsWith("g")) {
+            multiplier = "1073741824"; //1024*1024*1024
+            lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+        } else if (lowerCase.endsWith("t")) {
+            multiplier = "1099511627776"; //1024*1024*1024*1024
+            lowerCase = lowerCase.substring(0, lowerCase.length()-1);
+        }
+        BigDecimal valueBig = new BigDecimal(lowerCase);
+        BigDecimal multiplierBig = new BigDecimal(multiplier);
+        return fitsRange(optionName, valueBig.multiply(multiplierBig));
+    }
+
+    public static String getMinOptionRange(String optionName) throws Exception {
+        JVMOption option;
+        String minRange = null;
+
+        if (optionsAsMap == null) {
+            optionsAsMap = getOptionsWithRangeAsMap();
+        }
+
+        option = optionsAsMap.get(optionName);
+        if (option != null) {
+            minRange = option.getMin();
+        }
+
+        return minRange;
+    }
+
+    public static String getMaxOptionRange(String optionName) throws Exception {
+        JVMOption option;
+        String maxRange = null;
+
+        if (optionsAsMap == null) {
+            optionsAsMap = getOptionsWithRangeAsMap();
+        }
+
+        option = optionsAsMap.get(optionName);
+        if (option != null) {
+            maxRange = option.getMax();
+        }
+
+        return maxRange;
+    }
+
     /**
      * Add dependency for option depending on it's name. E.g. enable G1 GC for
      * G1 options or add prepend options to not hit constraints.
@@ -80,6 +161,13 @@
             option.addPrepend("-XX:+UseConcMarkSweepGC");
         }
 
+        if (name.startsWith("Shared")) {
+            option.addPrepend("-XX:+UnlockDiagnosticVMOptions");
+            String fileName = "Test" + name + ".jsa";
+            option.addPrepend("-XX:SharedArchiveFile=" + fileName);
+            option.addPrepend("-Xshare:dump");
+        }
+
         switch (name) {
             case "MinHeapFreeRatio":
                 option.addPrepend("-XX:MaxHeapFreeRatio=100");
@@ -112,7 +200,6 @@
                 /* Do nothing */
                 break;
         }
-
     }
 
     /**
--- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java	Wed Nov 18 22:00:09 2015 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java	Thu Nov 19 16:32:41 2015 -0600
@@ -23,50 +23,72 @@
 
 /* @test LimitSharedSizes
  * @summary Test handling of limits on shared space size
- * @library /testlibrary
+ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common
  * @modules java.base/sun.misc
  *          java.management
  * @run main LimitSharedSizes
  */
 
 import jdk.test.lib.*;
+import optionsvalidation.JVMOptionsUtils;
 
 public class LimitSharedSizes {
+    static enum Result {
+        OUT_OF_RANGE,
+        TOO_SMALL,
+        VALID,
+        VALID_ARCHIVE
+    }
+
     static enum Region {
         RO, RW, MD, MC
     }
 
+    private static final boolean fitsRange(String name, String value) throws RuntimeException {
+        boolean fits = true;
+        try {
+            fits = JVMOptionsUtils.fitsRange(name, value);
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+        return fits;
+    }
+
     private static class SharedSizeTestData {
         public String optionName;
         public String optionValue;
-        public String expectedErrorMsg;
+        public Result optionResult;
 
-        public SharedSizeTestData(Region region, String value, String msg) {
-            optionName = getName(region);
+        public SharedSizeTestData(Region region, String value) {
+            optionName = "-XX:"+getName(region);
             optionValue = value;
-            expectedErrorMsg = msg;
+            if (fitsRange(getName(region), value) == false) {
+                optionResult = Result.OUT_OF_RANGE;
+            } else {
+                optionResult = Result.TOO_SMALL;
+            }
         }
 
-        public SharedSizeTestData(Region region, String msg) {
-            optionName = getName(region);
-            optionValue = getValue(region);
-            expectedErrorMsg = msg;
+        public SharedSizeTestData(Region region, String value, Result result) {
+            optionName = "-XX:"+getName(region);
+            optionValue = value;
+            optionResult = result;
         }
 
         private String getName(Region region) {
             String name;
             switch (region) {
                 case RO:
-                    name = "-XX:SharedReadOnlySize";
+                    name = "SharedReadOnlySize";
                     break;
                 case RW:
-                    name = "-XX:SharedReadWriteSize";
+                    name = "SharedReadWriteSize";
                     break;
                 case MD:
-                    name = "-XX:SharedMiscDataSize";
+                    name = "SharedMiscDataSize";
                     break;
                 case MC:
-                    name = "-XX:SharedMiscCodeSize";
+                    name = "SharedMiscCodeSize";
                     break;
                 default:
                     name = "Unknown";
@@ -75,53 +97,37 @@
             return name;
         }
 
-        private String getValue(Region region) {
-            String value;
-            switch (region) {
-                case RO:
-                    value = Platform.is64bit() ? "9M" : "8M";
-                    break;
-                case RW:
-                    value = Platform.is64bit() ? "12M" : "7M";
-                    break;
-                case MD:
-                    value = Platform.is64bit() ? "4M" : "2M";
-                    break;
-                case MC:
-                    value = "120k";
-                    break;
-                default:
-                    value = "0M";
-                    break;
-            }
-            return value;
+        public Result getResult() {
+            return optionResult;
         }
     }
 
     private static final SharedSizeTestData[] testTable = {
         // Too small of a region size should not cause a vm crash.
-        // It should result in an error message like the following:
+        // It should result in an error message either like the following #1:
         // The shared miscellaneous code space is not large enough
         // to preload requested classes. Use -XX:SharedMiscCodeSize=
         // to increase the initial size of shared miscellaneous code space.
-        new SharedSizeTestData(Region.RO, "4M",   "read only"),
-        new SharedSizeTestData(Region.RW, "4M",   "read write"),
-        new SharedSizeTestData(Region.MD, "50k",  "miscellaneous data"),
-        new SharedSizeTestData(Region.MC, "20k",  "miscellaneous code"),
+        // or #2:
+        // The shared miscellaneous code space is outside the allowed range
+        new SharedSizeTestData(Region.RO, "4M"),
+        new SharedSizeTestData(Region.RW, "4M"),
+        new SharedSizeTestData(Region.MD, "50k"),
+        new SharedSizeTestData(Region.MC, "20k"),
 
-        // these values are larger than default ones, but should
+        // these values are larger than default ones, and should
         // be acceptable and not cause failure
-        new SharedSizeTestData(Region.RO, "20M", null),
-        new SharedSizeTestData(Region.RW, "20M", null),
-        new SharedSizeTestData(Region.MD, "20M", null),
-        new SharedSizeTestData(Region.MC, "20M", null),
+        new SharedSizeTestData(Region.RO, "20M", Result.VALID),
+        new SharedSizeTestData(Region.RW, "20M", Result.VALID),
+        new SharedSizeTestData(Region.MD, "20M", Result.VALID),
+        new SharedSizeTestData(Region.MC, "20M", Result.VALID),
 
         // test with sizes which just meet the minimum required sizes
         // the following tests also attempt to use the shared archive
-        new SharedSizeTestData(Region.RO, "UseArchive"),
-        new SharedSizeTestData(Region.RW, "UseArchive"),
-        new SharedSizeTestData(Region.MD, "UseArchive"),
-        new SharedSizeTestData(Region.MC, "UseArchive")
+        new SharedSizeTestData(Region.RO, Platform.is64bit() ? "9M":"8M", Result.VALID_ARCHIVE),
+        new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
+        new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
+        new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
     };
 
     public static void main(String[] args) throws Exception {
@@ -131,6 +137,7 @@
             counter++;
 
             String option = td.optionName + "=" + td.optionValue;
+            System.out.println("testing option number <" + counter + ">");
             System.out.println("testing option <" + option + ">");
 
             ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
@@ -141,43 +148,52 @@
 
             OutputAnalyzer output = new OutputAnalyzer(pb.start());
 
-            if (td.expectedErrorMsg != null) {
-                if (!td.expectedErrorMsg.equals("UseArchive")) {
-                    output.shouldContain("The shared " + td.expectedErrorMsg
-                        + " space is not large enough");
+            switch (td.getResult()) {
+                case VALID:
+                case VALID_ARCHIVE:
+                {
+                  output.shouldNotContain("space is not large enough");
+                  output.shouldHaveExitValue(0);
 
-                    output.shouldHaveExitValue(2);
-                } else {
-                    output.shouldNotContain("space is not large enough");
-                    output.shouldHaveExitValue(0);
-
-                    // try to use the archive
-                    pb = ProcessTools.createJavaProcessBuilder(
-                       "-XX:+UnlockDiagnosticVMOptions",
-                       "-XX:SharedArchiveFile=./" + fileName,
-                       "-XX:+PrintSharedArchiveAndExit",
-                       "-version");
+                  if (td.getResult() == Result.VALID_ARCHIVE) {
+                      // try to use the archive
+                      pb = ProcessTools.createJavaProcessBuilder(
+                         "-XX:+UnlockDiagnosticVMOptions",
+                         "-XX:SharedArchiveFile=./" + fileName,
+                         "-XX:+PrintSharedArchiveAndExit",
+                         "-version");
 
-                    try {
-                        output = new OutputAnalyzer(pb.start());
-                        output.shouldContain("archive is valid");
-                    } catch (RuntimeException e) {
-                        // if sharing failed due to ASLR or similar reasons,
-                        // check whether sharing was attempted at all (UseSharedSpaces)
-                        if ((output.getOutput().contains("Unable to use shared archive") ||
-                             output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
-                             output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
-                             output.getOutput().contains("Unable to reserve shared space at required address")) &&
-                             output.getExitValue() == 1) {
-                             System.out.println("Unable to use shared archive: test not executed; assumed passed");
-                             return;
-                        }
-                    }
-                    output.shouldHaveExitValue(0);
+                      try {
+                          output = new OutputAnalyzer(pb.start());
+                          output.shouldContain("archive is valid");
+                      } catch (RuntimeException e) {
+                          // if sharing failed due to ASLR or similar reasons,
+                          // check whether sharing was attempted at all (UseSharedSpaces)
+                          if ((output.getOutput().contains("Unable to use shared archive") ||
+                               output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
+                               output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
+                               output.getOutput().contains("Unable to reserve shared space at required address")) &&
+                               output.getExitValue() == 1) {
+                               System.out.println("Unable to use shared archive: test not executed; assumed passed");
+                               return;
+                          }
+                      }
+                      output.shouldHaveExitValue(0);
+                  }
                 }
-            } else {
-                output.shouldNotContain("space is not large enough");
-                output.shouldHaveExitValue(0);
+                break;
+                case TOO_SMALL:
+                {
+                    output.shouldContain("space is not large enough");
+                    output.shouldHaveExitValue(2);
+                }
+                break;
+                case OUT_OF_RANGE:
+                {
+                    output.shouldContain("outside the allowed range");
+                    output.shouldHaveExitValue(1);
+                }
+                break;
             }
         }
     }