8296754: AutoCreateSharedArchive in JDK 20 is not compatible with JDK 19

Reviewed-by: ccheung, iklam, erikj
This commit is contained in:
Matias Saavedra Silva 2022-11-28 15:26:27 +00:00 committed by Ioi Lam
parent 405b1886b3
commit a249a52501
8 changed files with 234 additions and 58 deletions

View File

@ -770,10 +770,13 @@ define SetupRunJtregTestBody
# Make sure the tmp dir is normalized as some tests will react badly otherwise
$1_TEST_TMP_DIR := $$(abspath $$($1_TEST_SUPPORT_DIR)/tmp)
# test.boot.jdk is used by some test cases that want to execute a previous
# version of the JDK.
$1_JTREG_BASIC_OPTIONS += -$$($1_JTREG_TEST_MODE) \
-verbose:$$(JTREG_VERBOSE) -retain:$$(JTREG_RETAIN) \
-concurrency:$$($1_JTREG_JOBS) -timeoutFactor:$$(JTREG_TIMEOUT_FACTOR) \
-vmoption:-XX:MaxRAMPercentage=$$($1_JTREG_MAX_RAM_PERCENTAGE) \
-vmoption:-Dtest.boot.jdk="$$(BOOT_JDK)" \
-vmoption:-Djava.io.tmpdir="$$($1_TEST_TMP_DIR)"
$1_JTREG_BASIC_OPTIONS += -automatic -ignore:quiet

View File

@ -30,18 +30,18 @@
#include "utilities/globalDefinitions.hpp"
CDSConst CDSConstants::offsets[] = {
{ "GenericCDSFileMapHeader::_magic", offset_of(GenericCDSFileMapHeader, _magic) },
{ "GenericCDSFileMapHeader::_crc", offset_of(GenericCDSFileMapHeader, _crc) },
{ "GenericCDSFileMapHeader::_version", offset_of(GenericCDSFileMapHeader, _version) },
{ "GenericCDSFileMapHeader::_header_size", offset_of(GenericCDSFileMapHeader, _header_size) },
{ "GenericCDSFileMapHeader::_common_app_classpath_prefix_size", offset_of(GenericCDSFileMapHeader, _common_app_classpath_prefix_size) },
{ "GenericCDSFileMapHeader::_base_archive_name_offset", offset_of(GenericCDSFileMapHeader, _base_archive_name_offset) },
{ "GenericCDSFileMapHeader::_base_archive_name_size", offset_of(GenericCDSFileMapHeader, _base_archive_name_size) },
{ "CDSFileMapHeaderBase::_regions[0]", offset_of(CDSFileMapHeaderBase, _regions) },
{ "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) },
{ "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) },
{ "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) },
{ "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) }
{ "GenericCDSFileMapHeader::_magic", offset_of(GenericCDSFileMapHeader, _magic) },
{ "GenericCDSFileMapHeader::_crc", offset_of(GenericCDSFileMapHeader, _crc) },
{ "GenericCDSFileMapHeader::_version", offset_of(GenericCDSFileMapHeader, _version) },
{ "GenericCDSFileMapHeader::_header_size", offset_of(GenericCDSFileMapHeader, _header_size) },
{ "GenericCDSFileMapHeader::_base_archive_name_offset", offset_of(GenericCDSFileMapHeader, _base_archive_name_offset) },
{ "GenericCDSFileMapHeader::_base_archive_name_size", offset_of(GenericCDSFileMapHeader, _base_archive_name_size) },
{ "CDSFileMapHeaderBase::_regions[0]", offset_of(CDSFileMapHeaderBase, _regions) },
{ "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) },
{ "FileMapHeader::_common_app_classpath_prefix_size", offset_of(FileMapHeader, _common_app_classpath_prefix_size) },
{ "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) },
{ "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) },
{ "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) }
};
CDSConst CDSConstants::constants[] = {

View File

@ -1267,10 +1267,6 @@ public:
return false;
}
if (!check_common_app_classpath_prefix_len()) {
return false;
}
// All fields in the GenericCDSFileMapHeader has been validated.
_is_valid = true;
return true;
@ -1351,15 +1347,6 @@ public:
return true;
}
bool check_common_app_classpath_prefix_len() {
int common_path_size = _header->_common_app_classpath_prefix_size;
if (common_path_size < 0) {
FileMapInfo::fail_continue("common app classpath prefix len < 0");
return false;
}
return true;
}
};
// Return value:
@ -1434,6 +1421,12 @@ bool FileMapInfo::init_from_file(int fd) {
return false;
}
int common_path_size = header()->common_app_classpath_prefix_size();
if (common_path_size < 0) {
FileMapInfo::fail_continue("common app classpath prefix len < 0");
return false;
}
unsigned int base_offset = header()->base_archive_name_offset();
unsigned int name_size = header()->base_archive_name_size();
unsigned int header_size = header()->header_size();

View File

@ -189,21 +189,23 @@ private:
// The following fields record the states of the VM during dump time.
// They are compared with the runtime states to see if the archive
// can be used.
size_t _core_region_alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
address _narrow_oop_base; // compressed oop encoding base
int _narrow_oop_shift; // compressed oop encoding shift
bool _compact_strings; // value of CompactStrings
uintx _max_heap_size; // java max heap size during dumping
CompressedOops::Mode _narrow_oop_mode; // compressed oop encoding mode
int _narrow_klass_shift; // save narrow klass base and shift
bool _compressed_oops; // save the flag UseCompressedOops
bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers
size_t _cloned_vtables_offset; // The address of the first cloned vtable
size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
address _heap_begin; // heap begin at dump time.
address _heap_end; // heap end at dump time.
bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath
size_t _core_region_alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
address _narrow_oop_base; // compressed oop encoding base
int _narrow_oop_shift; // compressed oop encoding shift
bool _compact_strings; // value of CompactStrings
uintx _max_heap_size; // java max heap size during dumping
CompressedOops::Mode _narrow_oop_mode; // compressed oop encoding mode
int _narrow_klass_shift; // save narrow klass base and shift
bool _compressed_oops; // save the flag UseCompressedOops
bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers
size_t _cloned_vtables_offset; // The address of the first cloned vtable
size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
address _heap_begin; // heap begin at dump time.
address _heap_end; // heap end at dump time.
bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath
unsigned int _common_app_classpath_prefix_size; // size of the common prefix of app class paths
// 0 if no common prefix exists
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@ -240,21 +242,21 @@ private:
void set_as_offset(char* p, size_t *offset);
public:
// Accessors -- fields declared in GenericCDSFileMapHeader
unsigned int magic() const { return _generic_header._magic; }
int crc() const { return _generic_header._crc; }
int version() const { return _generic_header._version; }
unsigned int header_size() const { return _generic_header._header_size; }
unsigned int base_archive_name_offset() const { return _generic_header._base_archive_name_offset; }
unsigned int base_archive_name_size() const { return _generic_header._base_archive_name_size; }
unsigned int common_app_classpath_prefix_size() const { return _generic_header._common_app_classpath_prefix_size; }
unsigned int magic() const { return _generic_header._magic; }
int crc() const { return _generic_header._crc; }
int version() const { return _generic_header._version; }
unsigned int header_size() const { return _generic_header._header_size; }
unsigned int base_archive_name_offset() const { return _generic_header._base_archive_name_offset; }
unsigned int base_archive_name_size() const { return _generic_header._base_archive_name_size; }
unsigned int common_app_classpath_prefix_size() const { return _common_app_classpath_prefix_size; }
void set_magic(unsigned int m) { _generic_header._magic = m; }
void set_crc(int crc_value) { _generic_header._crc = crc_value; }
void set_version(int v) { _generic_header._version = v; }
void set_header_size(unsigned int s) { _generic_header._header_size = s; }
void set_base_archive_name_offset(unsigned int s) { _generic_header._base_archive_name_offset = s; }
void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; }
void set_common_app_classpath_prefix_size(unsigned int s) { _generic_header._common_app_classpath_prefix_size = s; }
void set_magic(unsigned int m) { _generic_header._magic = m; }
void set_crc(int crc_value) { _generic_header._crc = crc_value; }
void set_version(int v) { _generic_header._version = v; }
void set_header_size(unsigned int s) { _generic_header._header_size = s; }
void set_base_archive_name_offset(unsigned int s) { _generic_header._base_archive_name_offset = s; }
void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; }
void set_common_app_classpath_prefix_size(unsigned int s) { _common_app_classpath_prefix_size = s; }
size_t core_region_alignment() const { return _core_region_alignment; }
int obj_alignment() const { return _obj_alignment; }

View File

@ -39,7 +39,7 @@
#define CDS_ARCHIVE_MAGIC 0xf00baba2
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
#define CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION 13
#define CURRENT_CDS_ARCHIVE_VERSION 16
#define CURRENT_CDS_ARCHIVE_VERSION 17
typedef struct CDSFileMapRegion {
int _crc; // CRC checksum of this region.
@ -73,8 +73,6 @@ typedef struct GenericCDSFileMapHeader {
int _crc; // header crc checksum, start from _base_archive_name_offset
int _version; // CURRENT_CDS_ARCHIVE_VERSION of the jdk that dumped the this archive
unsigned int _header_size; // total size of the header, in bytes
unsigned int _common_app_classpath_prefix_size; // size of the common prefix of app class paths
// 0 if no common prefix exists
unsigned int _base_archive_name_offset; // offset where the base archive name is stored
// static archive: 0
// dynamic archive:

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @summary Check that -XX:+AutoCreateSharedArchive automatically recreates an archive when you change the JDK version.
* @requires os.family == "linux" & vm.bits == "64" & (os.arch=="amd64" | os.arch=="x86_64")
* @library /test/lib
* @compile -source 1.8 -target 1.8 ../test-classes/HelloJDK8.java
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar Hello.jar HelloJDK8
* @run driver TestAutoCreateSharedArchiveUpgrade
*/
import java.io.File;
import jdk.test.lib.helpers.ClassFileInstaller;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class TestAutoCreateSharedArchiveUpgrade {
// The JDK being tested
private static final String TEST_JDK = System.getProperty("test.jdk", null);
// If you're running this test manually, specify the location of a previous version of
// the JDK using "jtreg -vmoption:-Dtest.previous.jdk=${JDK19_HOME} ..."
private static final String PREV_JDK = System.getProperty("test.previous.jdk", null);
// If you're unning this test using something like
// "make test TEST=test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java",
// the test.boot.jdk property is passed by make/RunTests.gmk
private static final String BOOT_JDK = System.getProperty("test.boot.jdk", null);
private static final String USER_DIR = System.getProperty("user.dir", ".");
private static final String FS = System.getProperty("file.separator", "/");
private static final String JAR = ClassFileInstaller.getJarPath("Hello.jar");
private static final String JSA = USER_DIR + FS + "Hello.jsa";
private static String oldJVM;
private static String newJVM;
public static void main(String[] args) throws Throwable {
setupJVMs();
doTest();
}
static void setupJVMs() throws Throwable {
if (TEST_JDK == null) {
throw new RuntimeException("-Dtest.jdk should point to the JDK being tested");
}
newJVM = TEST_JDK + FS + "bin" + FS + "java";
if (PREV_JDK != null) {
oldJVM = PREV_JDK + FS + "bin" + FS + "java";
} else if (BOOT_JDK != null) {
oldJVM = BOOT_JDK + FS + "bin" + FS + "java";
} else {
throw new RuntimeException("Use -Dtest.previous.jdk or -Dtest.boot.jdk to specify a " +
"previous version of the JDK that supports " +
"-XX:+AutoCreateSharedArchive");
}
System.out.println("Using newJVM = " + newJVM);
System.out.println("Using oldJVM = " + oldJVM);
}
static void doTest() throws Throwable {
File jsaF = new File(JSA);
jsaF.delete();
OutputAnalyzer output;
// NEW JDK -- create and then use the JSA
output = run(newJVM);
assertJSANotFound(output);
assertCreatedJSA(output);
output = run(newJVM);
assertUsedJSA(output);
// OLD JDK -- should reject the JSA created by NEW JDK, and create its own
output = run(oldJVM);
assertJSAVersionMismatch(output);
assertCreatedJSA(output);
output = run(oldJVM);
assertUsedJSA(output);
// NEW JDK -- should reject the JSA created by OLD JDK, and create its own
output = run(newJVM);
assertJSAVersionMismatch(output);
assertCreatedJSA(output);
output = run(newJVM);
assertUsedJSA(output);
}
static OutputAnalyzer run(String jvm) throws Throwable {
OutputAnalyzer output =
ProcessTools.executeCommand(jvm, "-XX:+AutoCreateSharedArchive",
"-XX:SharedArchiveFile=" + JSA,
"-Xlog:cds",
"-cp", JAR, "HelloJDK8");
output.shouldHaveExitValue(0);
return output;
}
static void assertJSANotFound(OutputAnalyzer output) {
output.shouldContain("Specified shared archive not found");
}
static void assertCreatedJSA(OutputAnalyzer output) {
output.shouldContain("Dumping shared data to file");
}
static void assertJSAVersionMismatch(OutputAnalyzer output) {
output.shouldContain("does not match the required version");
}
static void assertUsedJSA(OutputAnalyzer output) {
output.shouldContain("Mapped dynamic region #0");
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
// Used by tests like dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java, which
// runs this class in an earlier JDK
//
// It should be compiled like this in the jtreg spec:
// @compile -source 1.8 -target 1.8 test-classes/HelloJDK8.java
public class HelloJDK8 {
public static void main(String args[]) {
System.out.println("This class is compiled by JDK 8");
}
}

View File

@ -94,7 +94,7 @@ public class CDSArchiveUtils {
offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc");
offsetVersion = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_version");
offsetHeaderSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_header_size");
offsetCommonAppClasspathPrefixSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_common_app_classpath_prefix_size");
offsetCommonAppClasspathPrefixSize = wb.getCDSOffsetForName("FileMapHeader::_common_app_classpath_prefix_size");
offsetBaseArchiveNameOffset = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_offset");
offsetBaseArchiveNameSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_size");
offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident");