--- old/src/hotspot/share/memory/filemap.cpp 2018-08-17 13:58:07.658345156 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2018-08-17 13:58:06.998319856 -0700 @@ -159,8 +159,8 @@ memset((void*)this, 0, sizeof(FileMapInfo)); _file_offset = 0; _file_open = false; - _header = new FileMapHeader(); - _header->_version = _invalid_version; + _header = (FileMapHeader*)os::malloc(sizeof(FileMapHeader), mtInternal); + _header->_version = INVALID_CDS_ARCHIVE_VERSION; _header->_has_platform_or_app_classes = true; } @@ -173,9 +173,9 @@ _header->populate(this, alignment); } -void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) { - _magic = 0xf00baba2; - _version = _current_version; +void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) { + _magic = CDS_ARCHIVE_MAGIC; + _version = CURRENT_CDS_ARCHIVE_VERSION; _alignment = alignment; _obj_alignment = ObjectAlignmentInBytes; _compact_strings = CompactStrings; @@ -497,14 +497,13 @@ // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { - size_t sz = _header->data_size(); - char* addr = _header->data(); - size_t n = os::read(fd, addr, (unsigned int)sz); + size_t sz = sizeof(FileMapHeader); + size_t n = os::read(fd, _header, (unsigned int)sz); if (n != sz) { fail_continue("Unable to read the file header."); return false; } - if (_header->_version != current_version()) { + if (_header->_version != CURRENT_CDS_ARCHIVE_VERSION) { fail_continue("The shared archive file has the wrong version."); return false; } @@ -525,8 +524,7 @@ } size_t len = lseek(fd, 0, SEEK_END); - struct FileMapInfo::FileMapHeader::space_info* si = - &_header->_space[MetaspaceShared::last_valid_region]; + CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region); // The last space might be empty if (si->_file_offset > len || len - si->_file_offset < si->_used) { fail_continue("The shared archive file has been truncated."); @@ -595,10 +593,8 @@ _header->_paths_misc_info_size = info_size; align_file_position(); - size_t sz = _header->data_size(); - char* addr = _header->data(); - write_bytes(addr, (int)sz); // skip the C++ vtable - write_bytes(ClassLoader::get_shared_paths_misc_info(), info_size); + write_bytes(_header, sizeof(FileMapHeader)); + write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size); align_file_position(); } @@ -607,7 +603,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size, bool read_only, bool allow_exec) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[region]; + CDSFileMapRegion* si = space_at(region); if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); @@ -632,7 +628,7 @@ si->_allow_exec = allow_exec; si->_crc = ClassLoader::crc32(0, base, (jint)size); if (base != NULL) { - write_bytes_aligned(base, (int)size); + write_bytes_aligned(base, size); } } @@ -698,9 +694,9 @@ // Dump bytes to file -- at the current file position. -void FileMapInfo::write_bytes(const void* buffer, int nbytes) { +void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) { if (_file_open) { - int n = ::write(_fd, buffer, nbytes); + size_t n = os::write(_fd, buffer, (unsigned int)nbytes); if (n != nbytes) { // It is dangerous to leave the corrupted shared archive file around, // close and remove the file. See bug 6372906. @@ -736,7 +732,7 @@ // Dump bytes to file -- at the current file position. -void FileMapInfo::write_bytes_aligned(const void* buffer, int nbytes) { +void FileMapInfo::write_bytes_aligned(const void* buffer, size_t nbytes) { align_file_position(); write_bytes(buffer, nbytes); align_file_position(); @@ -760,7 +756,7 @@ // Remap the shared readonly space to shared readwrite, private. bool FileMapInfo::remap_shared_readonly_as_readwrite() { int idx = MetaspaceShared::ro; - struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[idx]; + CDSFileMapRegion* si = space_at(idx); if (!si->_read_only) { // the space is already readwrite so we are done return true; @@ -812,7 +808,7 @@ char* FileMapInfo::map_region(int i, char** top_ret) { assert(!MetaspaceShared::is_heap_region(i), "sanity"); - struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; + CDSFileMapRegion* si = space_at(i); size_t used = si->_used; size_t alignment = os::vm_allocation_granularity(); size_t size = align_up(used, alignment); @@ -879,7 +875,7 @@ narrow_oop_shift() != Universe::narrow_oop_shift() || narrow_klass_base() != Universe::narrow_klass_base() || narrow_klass_shift() != Universe::narrow_klass_shift()) { - if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) { + if (log_is_enabled(Info, cds) && space_at(MetaspaceShared::first_string)->_used > 0) { log_info(cds)("Cached heap data from the CDS archive is being ignored. " "The current CompressedOops/CompressedClassPointers encoding differs from " "that archived due to heap size change. The archive was dumped using max heap " @@ -910,7 +906,7 @@ } } } else { - if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) { + if (log_is_enabled(Info, cds) && space_at(MetaspaceShared::first_string)->_used > 0) { log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, " "UseCompressedOops and UseCompressedClassPointers are required."); } @@ -928,12 +924,12 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first, int max, int* num, bool is_open_archive) { MemRegion * regions = new MemRegion[max]; - struct FileMapInfo::FileMapHeader::space_info* si; + CDSFileMapRegion* si; int region_num = 0; for (int i = first; i < first + max; i++) { - si = &_header->_space[i]; + si = space_at(i); size_t used = si->_used; if (used > 0) { size_t size = used; @@ -967,7 +963,7 @@ // for mapped regions as they are part of the reserved java heap, which is // already recorded. for (int i = 0; i < region_num; i++) { - si = &_header->_space[first + i]; + si = space_at(first + i); char* addr = (char*)regions[i].start(); char* base = os::map_memory(_fd, _full_path, si->_file_offset, addr, regions[i].byte_size(), si->_read_only, @@ -1033,7 +1029,7 @@ return true; } - size_t sz = _header->_space[i]._used; + size_t sz = space_at(i)->_used; if (sz == 0) { return true; // no data @@ -1046,7 +1042,7 @@ } const char* buf = _header->region_addr(i); int crc = ClassLoader::crc32(0, buf, (jint)sz); - if (crc != _header->_space[i]._crc) { + if (crc != space_at(i)->_crc) { fail_continue("Checksum verification failed."); return false; } @@ -1057,7 +1053,7 @@ void FileMapInfo::unmap_region(int i) { assert(!MetaspaceShared::is_heap_region(i), "sanity"); - struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; + CDSFileMapRegion* si = space_at(i); size_t used = si->_used; size_t size = align_up(used, os::vm_allocation_granularity()); @@ -1115,7 +1111,7 @@ return true; } -char* FileMapInfo::FileMapHeader::region_addr(int idx) { +char* FileMapHeader::region_addr(int idx) { if (MetaspaceShared::is_heap_region(idx)) { return _space[idx]._used > 0 ? (char*)((void*)CompressedOops::decode_not_null((narrowOop)_space[idx]._addr._offset)) : NULL; @@ -1124,19 +1120,19 @@ } } -int FileMapInfo::FileMapHeader::compute_crc() { - char* header = data(); +int FileMapHeader::compute_crc() { + char* start = (char*)this; // start computing from the field after _crc - char* buf = (char*)&_crc + sizeof(int); - size_t sz = data_size() - (buf - header); + char* buf = (char*)&_crc + sizeof(_crc); + size_t sz = sizeof(FileMapHeader) - (buf - start); int crc = ClassLoader::crc32(0, buf, (jint)sz); return crc; } // This function should only be called during run time with UseSharedSpaces enabled. -bool FileMapInfo::FileMapHeader::validate() { +bool FileMapHeader::validate() { if (VerifySharedSpaces && compute_crc() != _crc) { - fail_continue("Header checksum verification failed."); + FileMapInfo::fail_continue("Header checksum verification failed."); return false; } @@ -1145,11 +1141,11 @@ return false; } - if (_version != current_version()) { + if (_version != CURRENT_CDS_ARCHIVE_VERSION) { FileMapInfo::fail_continue("The shared archive file is the wrong version."); return false; } - if (_magic != (int)0xf00baba2) { + if (_magic != CDS_ARCHIVE_MAGIC) { FileMapInfo::fail_continue("The shared archive file has a bad magic number."); return false; } @@ -1225,7 +1221,7 @@ idx == MetaspaceShared::mc || idx == MetaspaceShared::md, "invalid region index"); char* base = _header->region_addr(idx); - if (p >= base && p < base + _header->_space[idx]._used) { + if (p >= base && p < base + space_at(idx)->_used) { return true; } return false; @@ -1234,7 +1230,7 @@ void FileMapInfo::print_shared_spaces() { tty->print_cr("Shared Spaces:"); for (int i = 0; i < MetaspaceShared::n_regions; i++) { - struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; + CDSFileMapRegion* si = space_at(i); char *base = _header->region_addr(i); tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, shared_region_name[i], @@ -1251,7 +1247,7 @@ char *addr = map_info->_header->region_addr(i); if (addr != NULL && !MetaspaceShared::is_heap_region(i)) { map_info->unmap_region(i); - map_info->_header->_space[i]._addr._base = NULL; + map_info->space_at(i)->_addr._base = NULL; } } // Dealloc the archive heap regions only without unmapping. The regions are part --- old/src/hotspot/share/memory/filemap.hpp 2018-08-17 13:58:10.710462153 -0700 +++ new/src/hotspot/share/memory/filemap.hpp 2018-08-17 13:58:09.574418606 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_FILEMAP_HPP #include "classfile/classLoader.hpp" +#include "include/cds.h" #include "memory/metaspaceShared.hpp" #include "memory/metaspace.hpp" #include "memory/universe.hpp" @@ -87,14 +88,80 @@ } }; +struct FileMapHeader : public CDSFileMapHeaderBase { + size_t _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 + Universe::NARROW_OOP_MODE _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). + + // The following fields are all sanity checks for whether this archive + // will function correctly with this JVM and the bootclasspath it's + // invoked with. + char _jvm_ident[JVM_IDENT_MAX]; // identifier for jvm + + // The _paths_misc_info is a variable-size structure that records "miscellaneous" + // information during dumping. It is generated and validated by the + // SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for + // detailed description. + // + // The _paths_misc_info data is stored as a byte array in the archive file header, + // immediately after the _header field. This information is used only when + // checking the validity of the archive and is deallocated after the archive is loaded. + // + // Note that the _paths_misc_info does NOT include information for JAR files + // that existed during dump time. Their information is stored in _shared_path_table. + int _paths_misc_info_size; + + // The following is a table of all the class path entries that were used + // during dumping. At run time, we require these files to exist and have the same + // size/modification time, or else the archive will refuse to load. + // + // All of these entries must be JAR files. The dumping process would fail if a non-empty + // directory was specified in the classpaths. If an empty directory was specified + // it is checked by the _paths_misc_info as described above. + // + // FIXME -- if JAR files in the tail of the list were specified but not used during dumping, + // they should be removed from this table, to save space and to avoid spurious + // loading failures during runtime. + int _shared_path_table_size; + size_t _shared_path_entry_size; + Array* _shared_path_table; + + jshort _app_class_paths_start_index; // Index of first app classpath entry + jshort _app_module_paths_start_index; // Index of first module path entry + bool _verify_local; // BytecodeVerificationLocal setting + bool _verify_remote; // BytecodeVerificationRemote setting + bool _has_platform_or_app_classes; // Archive contains app classes + + void set_has_platform_or_app_classes(bool v) { + _has_platform_or_app_classes = v; + } + bool has_platform_or_app_classes() { return _has_platform_or_app_classes; } + + char* region_addr(int idx); + + bool validate(); + void populate(FileMapInfo* info, size_t alignment); + int compute_crc(); +}; + + class FileMapInfo : public CHeapObj { private: friend class ManifestStream; friend class VMStructs; - enum { - _invalid_version = -1, - _current_version = 3 - }; + friend struct FileMapHeader; bool _file_open; int _fd; @@ -116,97 +183,7 @@ // methods, we would get sizeof(FileMapHeaderBase) == 1 with gcc. intx _dummy; }; - struct FileMapHeader : FileMapHeaderBase { - // Use data() and data_size() to memcopy to/from the FileMapHeader. We need to - // avoid read/writing the C++ vtable pointer. - static size_t data_size() { - return sizeof(FileMapHeader) - sizeof(FileMapInfo::FileMapHeaderBase); - } - char* data() { - return ((char*)this) + sizeof(FileMapHeaderBase); - } - int _magic; // identify file type. - int _crc; // header crc checksum. - int _version; // (from enum, above.) - size_t _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 - Universe::NARROW_OOP_MODE _narrow_oop_mode; // compressed oop encoding mode - int _narrow_klass_shift; // save narrow klass base and shift - address _narrow_klass_base; - char* _misc_data_patching_start; - char* _read_only_tables_start; - address _cds_i2i_entry_code_buffers; - size_t _cds_i2i_entry_code_buffers_size; - size_t _core_spaces_size; // number of bytes allocated by the core spaces - // (mc, md, ro, rw and od). - struct space_info { - int _crc; // crc checksum of the current space - size_t _file_offset; // sizeof(this) rounded to vm page size - union { - char* _base; // copy-on-write base address - intx _offset; // offset from the compressed oop encoding base, only used - // by archive heap space - } _addr; - size_t _used; // for setting space top on read - bool _read_only; // read only space? - bool _allow_exec; // executable code in space? - } _space[MetaspaceShared::n_regions]; - - // The following fields are all sanity checks for whether this archive - // will function correctly with this JVM and the bootclasspath it's - // invoked with. - char _jvm_ident[JVM_IDENT_MAX]; // identifier for jvm - - // The _paths_misc_info is a variable-size structure that records "miscellaneous" - // information during dumping. It is generated and validated by the - // SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for - // detailed description. - // - // The _paths_misc_info data is stored as a byte array in the archive file header, - // immediately after the _header field. This information is used only when - // checking the validity of the archive and is deallocated after the archive is loaded. - // - // Note that the _paths_misc_info does NOT include information for JAR files - // that existed during dump time. Their information is stored in _shared_path_table. - int _paths_misc_info_size; - - // The following is a table of all the class path entries that were used - // during dumping. At run time, we require these files to exist and have the same - // size/modification time, or else the archive will refuse to load. - // - // All of these entries must be JAR files. The dumping process would fail if a non-empty - // directory was specified in the classpaths. If an empty directory was specified - // it is checked by the _paths_misc_info as described above. - // - // FIXME -- if JAR files in the tail of the list were specified but not used during dumping, - // they should be removed from this table, to save space and to avoid spurious - // loading failures during runtime. - int _shared_path_table_size; - size_t _shared_path_entry_size; - Array* _shared_path_table; - - jshort _app_class_paths_start_index; // Index of first app classpath entry - jshort _app_module_paths_start_index; // Index of first module path entry - bool _verify_local; // BytecodeVerificationLocal setting - bool _verify_remote; // BytecodeVerificationRemote setting - bool _has_platform_or_app_classes; // Archive contains app classes - - void set_has_platform_or_app_classes(bool v) { - _has_platform_or_app_classes = v; - } - bool has_platform_or_app_classes() { return _has_platform_or_app_classes; } - - char* region_addr(int idx); - - bool validate(); - void populate(FileMapInfo* info, size_t alignment); - int compute_crc(); - }; FileMapHeader * _header; @@ -224,7 +201,6 @@ FileMapInfo(); ~FileMapInfo(); - static int current_version() { return _current_version; } int compute_header_crc() { return _header->compute_crc(); } void set_header_crc(int crc) { _header->_crc = crc; } void populate_header(size_t alignment); @@ -275,8 +251,8 @@ bool read_only, bool allow_exec); size_t write_archive_heap_regions(GrowableArray *heap_mem, int first_region_id, int max_num_regions); - void write_bytes(const void* buffer, int count); - void write_bytes_aligned(const void* buffer, int count); + void write_bytes(const void* buffer, size_t count); + void write_bytes_aligned(const void* buffer, size_t count); char* map_region(int i, char** top_ret); void map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN; void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN; @@ -329,6 +305,11 @@ bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false); bool verify_mapped_heap_regions(int first, int num) NOT_CDS_JAVA_HEAP_RETURN_(false); void dealloc_archive_heap_regions(MemRegion* regions, int num) NOT_CDS_JAVA_HEAP_RETURN; + + CDSFileMapRegion* space_at(int i) { + assert(i >= 0 && i <= NUM_CDS_REGIONS, "invalid region"); + return &_header->_space[i]; + } }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP --- old/src/hotspot/share/memory/metaspaceShared.cpp 2018-08-17 13:58:18.154747514 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2018-08-17 13:58:17.698730033 -0700 @@ -333,7 +333,7 @@ int size = FileMapInfo::get_number_of_shared_paths(); if (size > 0) { SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD); - FileMapInfo::FileMapHeader* header = FileMapInfo::current_info()->header(); + FileMapHeader* header = FileMapInfo::current_info()->header(); ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index); ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index); } --- old/src/hotspot/share/prims/cdsoffsets.cpp 2018-08-17 13:58:22.842927225 -0700 +++ new/src/hotspot/share/prims/cdsoffsets.cpp 2018-08-17 13:58:22.330907598 -0700 @@ -42,17 +42,17 @@ #define ADD_NEXT(list, name, value) \ list->add_end(new CDSOffsets(name, value, NULL)) -#define CREATE_OFFSET_MAPS \ - _all = new CDSOffsets("size_t_size", sizeof(size_t), NULL); \ - ADD_NEXT(_all, "FileMapHeader::_magic", offset_of(FileMapInfo::FileMapHeader, _magic)); \ - ADD_NEXT(_all, "FileMapHeader::_crc", offset_of(FileMapInfo::FileMapHeader, _crc)); \ - ADD_NEXT(_all, "FileMapHeader::_version", offset_of(FileMapInfo::FileMapHeader, _version)); \ - ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapInfo::FileMapHeader, _space)); \ - ADD_NEXT(_all, "space_info::_crc", offset_of(FileMapInfo::FileMapHeader::space_info, _crc)); \ - ADD_NEXT(_all, "space_info::_used", offset_of(FileMapInfo::FileMapHeader::space_info, _used)); \ - ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapInfo::FileMapHeader, _paths_misc_info_size)); \ - ADD_NEXT(_all, "file_header_size", sizeof(FileMapInfo::FileMapHeader)); \ - ADD_NEXT(_all, "space_info_size", sizeof(FileMapInfo::FileMapHeader::space_info)); +#define CREATE_OFFSET_MAPS \ + _all = new CDSOffsets("size_t_size", sizeof(size_t), NULL); \ + ADD_NEXT(_all, "FileMapHeader::_magic", offset_of(FileMapHeader, _magic)); \ + ADD_NEXT(_all, "FileMapHeader::_crc", offset_of(FileMapHeader, _crc)); \ + ADD_NEXT(_all, "FileMapHeader::_version", offset_of(FileMapHeader, _version)); \ + ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapHeader, _space)); \ + ADD_NEXT(_all, "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc)); \ + ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used)); \ + ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapHeader, _paths_misc_info_size)); \ + ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader)); \ + ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion)); int CDSOffsets::find_offset(const char* name) { if (_all == NULL) { --- old/src/hotspot/share/runtime/vmStructs.cpp 2018-08-17 13:58:31.707267019 -0700 +++ new/src/hotspot/share/runtime/vmStructs.cpp 2018-08-17 13:58:31.403255365 -0700 @@ -1095,11 +1095,11 @@ /* FileMapInfo fields (CDS archive related) */ \ /********************************************/ \ \ - CDS_ONLY(nonstatic_field(FileMapInfo, _header, FileMapInfo::FileMapHeader*)) \ - CDS_ONLY( static_field(FileMapInfo, _current_info, FileMapInfo*)) \ - CDS_ONLY(nonstatic_field(FileMapInfo::FileMapHeader, _space[0], FileMapInfo::FileMapHeader::space_info))\ - CDS_ONLY(nonstatic_field(FileMapInfo::FileMapHeader::space_info, _addr._base, char*)) \ - CDS_ONLY(nonstatic_field(FileMapInfo::FileMapHeader::space_info, _used, size_t)) \ + CDS_ONLY(nonstatic_field(FileMapInfo, _header, FileMapHeader*)) \ + CDS_ONLY( static_field(FileMapInfo, _current_info, FileMapInfo*)) \ + CDS_ONLY(nonstatic_field(FileMapHeader, _space[0], CDSFileMapRegion)) \ + CDS_ONLY(nonstatic_field(CDSFileMapRegion, _addr._base, char*)) \ + CDS_ONLY(nonstatic_field(CDSFileMapRegion, _used, size_t)) \ \ /******************/ \ /* VMError fields */ \ @@ -1978,9 +1978,8 @@ declare_toplevel_type(Annotations*) \ declare_type(OopMapValue, StackObj) \ declare_type(FileMapInfo, CHeapObj) \ - declare_type(FileMapInfo::FileMapHeaderBase, CHeapObj) \ - declare_type(FileMapInfo::FileMapHeader, FileMapInfo::FileMapHeaderBase)\ - declare_toplevel_type(FileMapInfo::FileMapHeader::space_info) \ + declare_toplevel_type(FileMapHeader) \ + declare_toplevel_type(CDSFileMapRegion) \ \ /************/ \ /* GC types */ \ --- old/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-08-17 13:58:45.295787900 -0700 +++ new/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-08-17 13:58:44.907773026 -0700 @@ -32,6 +32,7 @@ #include #include "libproc_impl.h" #include "salibelf.h" +#include "../../../../hotspot/share/include/cds.h" // This file has the libproc implementation to read core files. // For live processes, refer to ps_proc.c. Portions of this is adapted @@ -203,64 +204,7 @@ // PROT_READ pages. These pages are not dumped into core dump. // With this workaround, these pages are read from classes.jsa. -// FIXME: !HACK ALERT! -// The format of sharing achive file header is needed to read shared heap -// file mappings. For now, I am hard coding portion of FileMapHeader here. -// Refer to filemap.hpp. - -// FileMapHeader describes the shared space data in the file to be -// mapped. This structure gets written to a file. It is not a class, -// so that the compilers don't add any compiler-private data to it. - -#define NUM_SHARED_MAPS 9 - -// Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 3 - -typedef unsigned char* address; -typedef uintptr_t uintx; -typedef intptr_t intx; - -struct FileMapHeader { - int _magic; // identify file type. - int _crc; // header crc checksum. - int _version; // (from enum, above.) - size_t _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 - int _narrow_oop_mode; // compressed oop encoding mode - int _narrow_klass_shift; // save narrow klass base and shift - address _narrow_klass_base; - char* _misc_data_patching_start; - char* _read_only_tables_start; - address _cds_i2i_entry_code_buffers; - size_t _cds_i2i_entry_code_buffers_size; - size_t _core_spaces_size; // number of bytes allocated by the core spaces - // (mc, md, ro, rw and od). - - - struct space_info { - int _crc; // crc checksum of the current space - size_t _file_offset; // sizeof(this) rounded to vm page size - union { - char* _base; // copy-on-write base address - intx _offset; // offset from the compressed oop encoding base, only used - // by archive heap space - } _addr; - size_t _used; // for setting space top on read - // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with - // the C type matching the C++ bool type on any given platform. - // We assume the corresponding C type is char but licensees - // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - } _space[NUM_SHARED_MAPS]; - - // Ignore the rest of the FileMapHeader. We don't need those fields here. -}; +typedef struct CDSFileMapHeaderBase FileMapHeader; static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { jboolean i; @@ -317,7 +261,7 @@ const char *jvm_name = 0; if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) { char classes_jsa[PATH_MAX]; - struct FileMapHeader header; + FileMapHeader header; int fd = -1; int m = 0; size_t n = 0; @@ -375,33 +319,33 @@ } // read FileMapHeader from the file - memset(&header, 0, sizeof(struct FileMapHeader)); - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) - != sizeof(struct FileMapHeader)) { + memset(&header, 0, sizeof(FileMapHeader)); + if ((n = read(fd, &header, sizeof(FileMapHeader))) + != sizeof(FileMapHeader)) { print_debug("can't read shared archive file map header from %s\n", classes_jsa); close(fd); return false; } // check file magic - if (header._magic != 0xf00baba2) { - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", - classes_jsa, header._magic); + if (header._magic != CDS_ARCHIVE_MAGIC) { + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0x%x\n", + classes_jsa, header._magic, CDS_ARCHIVE_MAGIC); close(fd); return false; } // check version - if (header._version != CURRENT_ARCHIVE_VERSION) { + if (header._version != CURRENT_CDS_ARCHIVE_VERSION) { print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); + classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION); close(fd); return false; } ph->core->classes_jsa_fd = fd; // add read-only maps from classes.jsa to the list of maps - for (m = 0; m < NUM_SHARED_MAPS; m++) { + for (m = 0; m < NUM_CDS_REGIONS; m++) { if (header._space[m]._read_only) { base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. --- old/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-08-17 13:58:46.215823167 -0700 +++ new/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-08-17 13:58:45.899811053 -0700 @@ -29,6 +29,7 @@ #include #include #include "libproc_impl.h" +#include "../../../../hotspot/share/include/cds.h" #ifdef __APPLE__ #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" @@ -204,65 +205,7 @@ // PROT_READ pages. These pages are not dumped into core dump. // With this workaround, these pages are read from classes.jsa. -// FIXME: !HACK ALERT! -// The format of sharing achive file header is needed to read shared heap -// file mappings. For now, I am hard coding portion of FileMapHeader here. -// Refer to filemap.hpp. - -// FileMapHeader describes the shared space data in the file to be -// mapped. This structure gets written to a file. It is not a class, -// so that the compilers don't add any compiler-private data to it. - -#define NUM_SHARED_MAPS 9 - -// Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 3 - -typedef unsigned char* address; -typedef uintptr_t uintx; -typedef intptr_t intx; - - -struct FileMapHeader { - int _magic; // identify file type. - int _crc; // header crc checksum. - int _version; // (from enum, above.) - size_t _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 - int _narrow_oop_mode; // compressed oop encoding mode - int _narrow_klass_shift; // save narrow klass base and shift - address _narrow_klass_base; - char* _misc_data_patching_start; - char* _read_only_tables_start; - address _cds_i2i_entry_code_buffers; - size_t _cds_i2i_entry_code_buffers_size; - size_t _core_spaces_size; // number of bytes allocated by the core spaces - // (mc, md, ro, rw and od). - - - struct space_info { - int _crc; // crc checksum of the current space - size_t _file_offset; // sizeof(this) rounded to vm page size - union { - char* _base; // copy-on-write base address - intx _offset; // offset from the compressed oop encoding base, only used - // by archive heap space - } _addr; - size_t _used; // for setting space top on read - // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with - // the C type matching the C++ bool type on any given platform. - // We assume the corresponding C type is char but licensees - // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - } _space[NUM_SHARED_MAPS]; - - // Ignore the rest of the FileMapHeader. We don't need those fields here. -}; +typedef struct CDSFileMapHeaderBase FileMapHeader; static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { jboolean i; @@ -326,7 +269,7 @@ const char *jvm_name = 0; if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) { char classes_jsa[PATH_MAX]; - struct FileMapHeader header; + FileMapHeader header; int fd = -1; uintptr_t base = 0, useSharedSpacesAddr = 0; uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; @@ -381,33 +324,33 @@ } // read FileMapHeader from the file - memset(&header, 0, sizeof(struct FileMapHeader)); - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) - != sizeof(struct FileMapHeader)) { + memset(&header, 0, sizeof(FileMapHeader)); + if ((n = read(fd, &header, sizeof(FileMapHeader))) + != sizeof(FileMapHeader)) { print_debug("can't read shared archive file map header from %s\n", classes_jsa); close(fd); return false; } // check file magic - if (header._magic != 0xf00baba2) { - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", - classes_jsa, header._magic); + if (header._magic != CDS_ARCHIVE_MAGIC) { + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0x%x\n", + classes_jsa, header._magic, CDS_ARCHIVE_MAGIC); close(fd); return false; } // check version - if (header._version != CURRENT_ARCHIVE_VERSION) { + if (header._version != CURRENT_CDS_ARCHIVE_VERSION) { print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); + classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION); close(fd); return false; } ph->core->classes_jsa_fd = fd; // add read-only maps from classes.jsa to the list of maps - for (m = 0; m < NUM_SHARED_MAPS; m++) { + for (m = 0; m < NUM_CDS_REGIONS; m++) { if (header._space[m]._read_only) { base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java 2018-08-17 13:58:50.888002262 -0700 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java 2018-08-17 13:58:50.467986162 -0700 @@ -63,13 +63,13 @@ headerValue = headerAddress.getAddressAt(0); // FileMapHeader - type = db.lookupType("FileMapInfo::FileMapHeader"); + type = db.lookupType("FileMapHeader"); AddressField spaceField = type.getAddressField("_space[0]"); Address spaceValue = headerValue.addOffsetTo(type.getField("_space[0]").getOffset()); mdSpaceValue = spaceValue.addOffsetTo(3 * spaceField.getSize()); // SpaceInfo - type = db.lookupType("FileMapInfo::FileMapHeader::space_info"); + type = db.lookupType("CDSFileMapRegion"); long mdRegionBaseAddressOffset = type.getField("_addr._base").getOffset(); mdRegionBaseAddress = (mdSpaceValue.addOffsetTo(mdRegionBaseAddressOffset)).getAddressAt(0); long mdRegionSizeOffset = type.getField("_used").getOffset(); --- old/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-08-17 13:58:56.780228124 -0700 +++ new/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-08-17 13:58:51.996044736 -0700 @@ -31,6 +31,7 @@ #include #include #include +#include "../../../../hotspot/share/include/cds.h" #define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; } #define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;} @@ -67,6 +68,8 @@ jobject obj2; }; +typedef struct CDSFileMapHeaderBase FileMapHeader; + /* * Portions of user thread level detail gathering code is from pstack source * code. See pstack.c in Solaris 2.8 user commands source code. @@ -173,7 +176,7 @@ int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID); if (classes_jsa_fd != -1) { close(classes_jsa_fd); - struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); + FileMapHeader* pheader = (FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); if (pheader != NULL) { free(pheader); } @@ -484,67 +487,13 @@ return(fill_cframe_list(cd, regs, argc, argv)); } -// part of the class sharing workaround - -// FIXME: !!HACK ALERT!! - -// The format of sharing achive file header is needed to read shared heap -// file mappings. For now, I am hard coding portion of FileMapHeader here. -// Refer to filemap.hpp. - -// FileMapHeader describes the shared space data in the file to be -// mapped. This structure gets written to a file. It is not a class, so -// that the compilers don't add any compiler-private data to it. - -const int NUM_SHARED_MAPS = 9; - -// Refer to FileMapInfo::_current_version in filemap.hpp -const int CURRENT_ARCHIVE_VERSION = 3; - -typedef unsigned char* address; -typedef uintptr_t uintx; -typedef intptr_t intx; - -struct FileMapHeader { - int _magic; // identify file type. - int _crc; // header crc checksum. - int _version; // (from enum, above.) - size_t _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 - int _narrow_oop_mode; // compressed oop encoding mode - int _narrow_klass_shift; // save narrow klass base and shift - address _narrow_klass_base; - char* _misc_data_patching_start; - char* _read_only_tables_start; - address _cds_i2i_entry_code_buffers; - size_t _cds_i2i_entry_code_buffers_size; - size_t _core_spaces_size; // number of bytes allocated by the core spaces - // (mc, md, ro, rw and od). - - - struct space_info { - int _crc; // crc checksum of the current space - size_t _file_offset; // sizeof(this) rounded to vm page size - union { - char* _base; // copy-on-write base address - intx _offset; // offset from the compressed oop encoding base, only used - // by archive heap space - } _addr; - size_t _used; // for setting space top on read - // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with - // the C type matching the C++ bool type on any given platform. - // We assume the corresponding C type is char but licensees - // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - } _space[NUM_SHARED_MAPS]; - -// Ignore the rest of the FileMapHeader. We don't need those fields here. -}; +//--------------------------------------------------------------- +// Part of the class sharing workaround: +// +// With class sharing, pages are mapped from classes.jsa file. +// The read-only class sharing pages are mapped as MAP_SHARED, +// PROT_READ pages. These pages are not dumped into core dump. +// With this workaround, these pages are read from classes.jsa. static bool read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) { @@ -662,16 +611,16 @@ } // parse classes.jsa - struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader)); + FileMapHeader* pheader = (FileMapHeader*) malloc(sizeof(FileMapHeader)); if (pheader == NULL) { close(fd); THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1); } - memset(pheader, 0, sizeof(struct FileMapHeader)); + memset(pheader, 0, sizeof(FileMapHeader)); // read FileMapHeader - size_t n = read(fd, pheader, sizeof(struct FileMapHeader)); - if (n != sizeof(struct FileMapHeader)) { + size_t n = read(fd, pheader, sizeof(FileMapHeader)); + if (n != sizeof(FileMapHeader)) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa); close(fd); @@ -680,27 +629,27 @@ } // check file magic - if (pheader->_magic != 0xf00baba2) { + if (pheader->_magic != CDS_ARCHIVE_MAGIC) { char errMsg[ERR_MSG_SIZE]; - sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2", - classes_jsa, pheader->_magic); + sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0x%x", + classes_jsa, pheader->_magic, CDS_ARCHIVE_MAGIC); close(fd); free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check version - if (pheader->_version != CURRENT_ARCHIVE_VERSION) { + if (pheader->_version != CURRENT_CDS_ARCHIVE_VERSION) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d", - classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION); + classes_jsa, pheader->_version, CURRENT_CDS_ARCHIVE_VERSION); close(fd); free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } if (_libsaproc_debug) { - for (int m = 0; m < NUM_SHARED_MAPS; m++) { + for (int m = 0; m < NUM_CDS_REGIONS; m++) { print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n", pheader->_space[m]._file_offset, pheader->_space[m]._addr._base, pheader->_space[m]._used, pheader->_space[m]._read_only); @@ -1091,10 +1040,10 @@ if (classes_jsa_fd != -1 && address != (jlong)0) { print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address); - struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); + FileMapHeader* pheader = (FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); // walk through the shared mappings -- we just have 9 of them. // so, linear walking is okay. - for (int m = 0; m < NUM_SHARED_MAPS; m++) { + for (int m = 0; m < NUM_CDS_REGIONS; m++) { // We can skip the non-read-only maps. These are mapped as MAP_PRIVATE // and hence will be read by libproc. Besides, the file copy may be --- old/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java 2018-08-17 13:59:01.144395411 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java 2018-08-17 13:59:00.624375478 -0700 @@ -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,11 +62,11 @@ public class SharedArchiveConsistency { public static WhiteBox wb; public static int offset_magic; // FileMapHeader::_magic - public static int sp_offset_crc; // FileMapHeader::space_info::_crc + public static int sp_offset_crc; // CDSFileMapRegion::_crc public static int file_header_size = -1;// total size of header, variant, need calculation - public static int space_info_size; // size of space_info - public static int sp_offset; // offset of FileMapHeader::space_info - public static int sp_used_offset; // offset of space_info::_used + public static int CDSFileMapRegion_size; // size of CDSFileMapRegion + public static int sp_offset; // offset of CDSFileMapRegion + public static int sp_used_offset; // offset of CDSFileMapRegion::_used public static int size_t_size; // size of size_t public static File jsa; // will be updated during test @@ -83,7 +83,7 @@ public static void getFileOffsetInfo() throws Exception { wb = WhiteBox.getWhiteBox(); offset_magic = wb.getOffsetForName("FileMapHeader::_magic"); - sp_offset_crc = wb.getOffsetForName("space_info::_crc"); + sp_offset_crc = wb.getOffsetForName("CDSFileMapRegion::_crc"); try { int nonExistOffset = wb.getOffsetForName("FileMapHeader::_non_exist_offset"); System.exit(-1); // should fail @@ -92,9 +92,9 @@ } sp_offset = wb.getOffsetForName("FileMapHeader::_space[0]") - offset_magic; - sp_used_offset = wb.getOffsetForName("space_info::_used") - sp_offset_crc; + sp_used_offset = wb.getOffsetForName("CDSFileMapRegion::_used") - sp_offset_crc; size_t_size = wb.getOffsetForName("size_t_size"); - space_info_size = wb.getOffsetForName("space_info_size"); + CDSFileMapRegion_size = wb.getOffsetForName("CDSFileMapRegion_size"); } public static int getFileHeaderSize(FileChannel fc) throws Exception { @@ -166,7 +166,7 @@ System.out.printf("%-12s%-12s%-12s%-12s%-12s\n", "Space Name", "Offset", "Used bytes", "Reg Start", "Random Offset"); start0 = getFileHeaderSize(fc); for (int i = 0; i < num_regions; i++) { - used_offset = sp_offset + space_info_size * i + sp_used_offset; + used_offset = sp_offset + CDSFileMapRegion_size * i + sp_used_offset; // read 'used' used[i] = readInt(fc, used_offset, size_t_size); start = start0; @@ -199,7 +199,7 @@ long[] used = new long[num_regions]; System.out.printf("%-12s%-12s\n", "Space name", "Used bytes"); for (int i = 0; i < num_regions; i++) { - used_offset = sp_offset + space_info_size* i + sp_used_offset; + used_offset = sp_offset + CDSFileMapRegion_size* i + sp_used_offset; // read 'used' used[i] = readInt(fc, used_offset, size_t_size); System.out.printf("%-12s%-12d\n", shared_region_name[i], used[i]); --- /dev/null 2018-08-14 18:25:04.628316445 -0700 +++ new/src/hotspot/share/include/cds.h 2018-08-17 13:59:06.248591065 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +#ifndef SHARE_INCLUDE_CDS_H +#define SHARE_INCLUDE_CDS_H + +// This file declares the CDS data structures that are used by the HotSpot Serviceability Agent +// (see C sources inside src/jdk.hotspot.agent). +// +// We should use only standard C types. Do bot use custom types such as bool, intx, +// etc, to avoid introducing unnecessary dependencies to other HotSpot type declarations. +// +// Also, this is a C header file. Do not use C++ here. + +#define NUM_CDS_REGIONS 9 +#define CDS_ARCHIVE_MAGIC 0xf00baba2 +#define CURRENT_CDS_ARCHIVE_VERSION 4 +#define INVALID_CDS_ARCHIVE_VERSION -1 + +struct CDSFileMapRegion { + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + size_t _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read + int _read_only; // read only space? + int _allow_exec; // executable code in space? +}; + +struct CDSFileMapHeaderBase { + unsigned int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // must be CURRENT_CDS_ARCHIVE_VERSION + struct CDSFileMapRegion _space[NUM_CDS_REGIONS]; +}; + +#endif // SHARE_INCLUDE_CDS_H