--- old/src/share/vm/classfile/compactHashtable.cpp 2015-11-06 09:35:33.000000000 -0600 +++ new/src/share/vm/classfile/compactHashtable.cpp 2015-11-06 09:35:33.000000000 -0600 @@ -137,7 +137,7 @@ if (_type == CompactHashtable::_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::_string_table), "unknown table"); assert(UseCompressedOops, "UseCompressedOops is required"); --- old/src/share/vm/memory/metaspace.cpp 2015-11-06 09:35:33.000000000 -0600 +++ new/src/share/vm/memory/metaspace.cpp 2015-11-06 09:35:33.000000000 -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. --- old/src/share/vm/memory/metaspaceShared.hpp 2015-11-06 09:35:34.000000000 -0600 +++ new/src/share/vm/memory/metaspaceShared.hpp 2015-11-06 09:35:34.000000000 -0600 @@ -69,21 +69,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 { --- old/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-11-06 09:35:35.000000000 -0600 +++ new/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-11-06 09:35:35.000000000 -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* CommandLineFlagConstraintList::_constraints = NULL; CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; --- old/src/share/vm/runtime/commandLineFlagRangeList.cpp 2015-11-06 09:35:35.000000000 -0600 +++ new/src/share/vm/runtime/commandLineFlagRangeList.cpp 2015-11-06 09:35:35.000000000 -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 204 +#define INITIAL_RANGES_SIZE 319 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them --- old/src/share/vm/runtime/globals.hpp 2015-11-06 09:35:36.000000000 -0600 +++ new/src/share/vm/runtime/globals.hpp 2015-11-06 09:35:36.000000000 -0600 @@ -533,6 +533,46 @@ #define falseInEmbedded true #endif +// metspace defaults +#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) + +#define SHARED_PAGE ((size_t)os::vm_page_size()) +#define MAX_SHARED_DELTA (0x7FFFFFFF) +#define MAX_SHARED_READ_WRITE_SIZE (MAX_SHARED_DELTA-(DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_READ_ONLY_SIZE (MAX_SHARED_DELTA-(DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_MISC_DATA_SIZE (MAX_SHARED_DELTA-(DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_MISC_CODE_SIZE (MAX_SHARED_DELTA-(DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE)-SHARED_PAGE) + + // develop flags are settable / visible only during development and are constant in the PRODUCT version // product flags are always settable / visible // notproduct flags are settable / visible only during development and are not declared in the PRODUCT version @@ -4101,21 +4141,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)") \ + range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE) \ \ - product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \ + product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE, \ "Size of read-only space for metadata (in bytes)") \ + range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE) \ \ - product(uintx, SharedMiscDataSize, NOT_LP64(2*M) LP64_ONLY(4*M), \ + product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE, \ "Size of the shared miscellaneous data area (in bytes)") \ + range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE) \ \ - product(uintx, SharedMiscCodeSize, 120*K, \ + product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE, \ "Size of the shared miscellaneous code area (in bytes)") \ + range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE) \ \ - product(uintx, SharedBaseAddress, LP64_ONLY(32*G) \ + 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") \ --- old/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java 2015-11-06 09:35:37.000000000 -0600 +++ new/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java 2015-11-06 09:35:36.000000000 -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 --- old/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java 2015-11-06 09:35:37.000000000 -0600 +++ new/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java 2015-11-06 09:35:37.000000000 -0600 @@ -37,6 +37,7 @@ import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.Platform; import jdk.test.lib.ProcessTools; +import java.math.BigDecimal; public class JVMOptionsUtils { @@ -49,6 +50,8 @@ /* Used to start the JVM with the same type as current */ static String VMType; + private static Map 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. --- old/test/runtime/SharedArchiveFile/LimitSharedSizes.java 2015-11-06 09:35:38.000000000 -0600 +++ new/test/runtime/SharedArchiveFile/LimitSharedSizes.java 2015-11-06 09:35:38.000000000 -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); - optionValue = value; - expectedErrorMsg = msg; + public SharedSizeTestData(Region region, String value) { + optionName = "-XX:"+getName(region); + optionValue = value; + 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); + + 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); + } + } + break; + case TOO_SMALL: + { + output.shouldContain("space is not large enough"); 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"); - - 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 OUT_OF_RANGE: + { + output.shouldContain("outside the allowed range"); + output.shouldHaveExitValue(1); + } + break; } } }