8208658: Make CDS archived heap regions usable even if compressed oop encoding has changed

Relocate and patch archive regions if necessary

Reviewed-by: jiangli, tschatzl
This commit is contained in:
Ioi Lam 2018-08-14 09:59:37 -07:00
parent aafb128d89
commit 5b2c081460
25 changed files with 611 additions and 197 deletions

View File

@ -27,6 +27,7 @@
#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logMessage.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "oops/compressedOops.inline.hpp"
@ -280,8 +281,9 @@ class CompactHashtable_OopIterator {
public:
CompactHashtable_OopIterator(OopClosure *cl) : _closure(cl) {}
inline void do_value(address base_address, u4 offset) const {
narrowOop o = (narrowOop)offset;
_closure->do_oop(&o);
narrowOop v = (narrowOop)offset;
oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
_closure->do_oop(&obj);
}
};

View File

@ -28,7 +28,8 @@
#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/compressedOops.inline.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "oops/oop.hpp"
template <class T, class N>
@ -46,8 +47,8 @@ inline Symbol* CompactHashtable<T, N>::decode_entry(CompactHashtable<Symbol*, ch
template <class T, class N>
inline oop CompactHashtable<T, N>::decode_entry(CompactHashtable<oop, char>* const t,
u4 offset, const char* name, int len) {
narrowOop obj = (narrowOop)offset;
oop string = CompressedOops::decode(obj);
narrowOop v = (narrowOop)offset;
oop string = HeapShared::decode_with_archived_oop_encoding_mode(v);
if (java_lang_String::equals(string, (jchar*)name, len)) {
return string;
}

View File

@ -1213,7 +1213,7 @@ oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
bool java_lang_Class::restore_archived_mirror(Klass *k,
Handle class_loader, Handle module,
Handle protection_domain, TRAPS) {
oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw());
oop m = MetaspaceShared::materialize_archived_object(k->archived_java_mirror_raw_narrow());
if (m == NULL) {
return false;

View File

@ -59,8 +59,8 @@ class StringDedupSharedClosure: public OopClosure {
public:
StringDedupSharedClosure(StringDedupStat* stat) : _stat(stat) {}
virtual void do_oop(oop* p) { ShouldNotReachHere(); }
virtual void do_oop(narrowOop* p) {
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
virtual void do_oop(oop* p) {
oop java_string = RawAccess<>::oop_load(p);
StringDedupTable::deduplicate(java_string, _stat);
}

View File

@ -35,7 +35,7 @@
#define NUM_CDS_REGIONS 9
#define CDS_ARCHIVE_MAGIC 0xf00baba2
#define CURRENT_CDS_ARCHIVE_VERSION 4
#define CURRENT_CDS_ARCHIVE_VERSION 5
#define INVALID_CDS_ARCHIVE_VERSION -1
struct CDSFileMapRegion {
@ -49,6 +49,8 @@ struct CDSFileMapRegion {
size_t _used; // for setting space top on read
int _read_only; // read only space?
int _allow_exec; // executable code in space?
void* _oopmap; // bitmap for relocating embedded oops
size_t _oopmap_size_in_bits;
};
struct CDSFileMapHeaderBase {

View File

@ -35,12 +35,15 @@
#include "logging/logStream.hpp"
#include "logging/logMessage.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/java.hpp"
@ -51,6 +54,7 @@
#include "utilities/defaultStream.hpp"
#if INCLUDE_G1GC
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/heapRegion.hpp"
#endif
# include <sys/stat.h>
@ -188,6 +192,9 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_shared_path_table_size = mapinfo->_shared_path_table_size;
_shared_path_table = mapinfo->_shared_path_table;
_shared_path_entry_size = mapinfo->_shared_path_entry_size;
if (MetaspaceShared::is_heap_object_archiving_allowed()) {
_heap_reserved = Universe::heap()->reserved_region();
}
// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@ -653,13 +660,14 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
// "_" represented unused spaced in the heap region.
//
//
// |ah0 | ah1 | ah2| ...... | ahn |
// |ah0 | ah1 | ah2| ...... | ahn|
// |XXXXXX|__ |XXXXX|XXXX|XXXXXXXX|XXXX|
// |<-r0->| |<- r1 ----------------->|
// ^^^
// |
// +-- gap
size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
int first_region_id, int max_num_regions) {
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
@ -684,6 +692,10 @@ size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_me
log_info(cds)("Archive heap region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
i, p2i(start), p2i(start + size), size);
write_region(i, start, size, false, false);
if (size > 0) {
space_at(i)->_oopmap = oopmaps->at(arr_idx)._oopmap;
space_at(i)->_oopmap_size_in_bits = oopmaps->at(arr_idx)._oopmap_size_in_bits;
}
}
return total_size;
}
@ -762,7 +774,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
if (!open_for_read()) {
return false;
}
char *addr = _header->region_addr(idx);
char *addr = region_addr(idx);
char *base = os::remap_memory(_fd, _full_path, si->_file_offset,
addr, size, false /* !read_only */,
si->_allow_exec);
@ -781,7 +793,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
// Map the whole region at once, assumed to be allocated contiguously.
ReservedSpace FileMapInfo::reserve_shared_memory() {
char* requested_addr = _header->region_addr(0);
char* requested_addr = region_addr(0);
size_t size = FileMapInfo::core_spaces_size();
// Reserve the space first, then map otherwise map will go right over some
@ -808,7 +820,7 @@ char* FileMapInfo::map_region(int i, char** top_ret) {
size_t used = si->_used;
size_t alignment = os::vm_allocation_granularity();
size_t size = align_up(used, alignment);
char *requested_addr = _header->region_addr(i);
char *requested_addr = region_addr(i);
// If a tool agent is in use (debugging enabled), we must map the address space RW
if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) {
@ -838,19 +850,57 @@ char* FileMapInfo::map_region(int i, char** top_ret) {
return base;
}
address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
if (with_current_oop_encoding_mode) {
return (address)CompressedOops::decode_not_null(offset_of_space(spc));
} else {
return (address)HeapShared::decode_with_archived_oop_encoding_mode(offset_of_space(spc));
}
}
static MemRegion *string_ranges = NULL;
static MemRegion *open_archive_heap_ranges = NULL;
static int num_string_ranges = 0;
static int num_open_archive_heap_ranges = 0;
#if INCLUDE_CDS_JAVA_HEAP
bool FileMapInfo::has_heap_regions() {
return (_header->_space[MetaspaceShared::first_string]._used > 0);
}
// Returns the address range of the archived heap regions computed using the
// current oop encoding mode. This range may be different than the one seen at
// dump time due to encoding mode differences. The result is used in determining
// if/how these regions should be relocated at run time.
MemRegion FileMapInfo::get_heap_regions_range_with_current_oop_encoding_mode() {
address start = (address) max_uintx;
address end = NULL;
for (int i = MetaspaceShared::first_string; i <= MetaspaceShared::last_valid_region; i++) {
CDSFileMapRegion* si = space_at(i);
size_t size = si->_used;
if (size > 0) {
address s = start_address_with_current_oop_encoding_mode(si);
address e = s + size;
if (start > s) {
start = s;
}
if (end < e) {
end = e;
}
}
}
assert(end != NULL, "must have at least one used heap region");
return MemRegion((HeapWord*)start, (HeapWord*)end);
}
//
// Map the shared string objects and open archive heap objects to the runtime
// java heap.
//
// The shared strings are mapped near the runtime java heap top. The
// mapped strings contain no out-going references to any other java heap
// regions. GC does not write into the mapped shared strings.
// The shared strings are mapped close to the end of the java heap top in
// closed archive regions. The mapped strings contain no out-going references
// to any other java heap regions. GC does not write into the mapped shared strings.
//
// The open archive heap objects are mapped below the shared strings in
// the runtime java heap. The mapped open archive heap data only contain
@ -858,56 +908,110 @@ static int num_open_archive_heap_ranges = 0;
// During runtime execution, out-going references to any other java heap
// regions may be added. GC may mark and update references in the mapped
// open archive objects.
void FileMapInfo::map_heap_regions() {
if (MetaspaceShared::is_heap_object_archiving_allowed()) {
log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(narrow_klass_base()), narrow_klass_shift());
void FileMapInfo::map_heap_regions_impl() {
if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
log_info(cds)("CDS heap data is being ignored. UseG1GC, "
"UseCompressedOops and UseCompressedClassPointers are required.");
return;
}
// Check that all the narrow oop and klass encodings match the archive
if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
narrow_oop_base() != Universe::narrow_oop_base() ||
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) && 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 "
"size " UINTX_FORMAT "M.", max_heap_size()/M);
log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()),
Universe::narrow_oop_shift());
log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
}
} else {
// First, map string regions as closed archive heap regions.
// GC does not write into the regions.
if (map_heap_data(&string_ranges,
MetaspaceShared::first_string,
MetaspaceShared::max_strings,
&num_string_ranges)) {
StringTable::set_shared_string_mapped();
MemRegion heap_reserved = Universe::heap()->reserved_region();
// Now, map open_archive heap regions, GC can write into the regions.
if (map_heap_data(&open_archive_heap_ranges,
MetaspaceShared::first_open_archive_heap_region,
MetaspaceShared::max_open_archive_heap_region,
&num_open_archive_heap_ranges,
true /* open */)) {
MetaspaceShared::set_open_archive_heap_region_mapped();
}
}
}
log_info(cds)("CDS archive was created with max heap size = " SIZE_FORMAT "M, and the following configuration:",
max_heap_size()/M);
log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(narrow_klass_base()), narrow_klass_shift());
log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
log_info(cds)("The current max heap size = " SIZE_FORMAT "M, HeapRegion::GrainBytes = " SIZE_FORMAT,
heap_reserved.byte_size()/M, HeapRegion::GrainBytes);
log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()), Universe::narrow_oop_shift());
if (narrow_klass_base() != Universe::narrow_klass_base() ||
narrow_klass_shift() != Universe::narrow_klass_shift()) {
log_info(cds)("CDS heap data cannot be used because the archive was created with an incompatible narrow klass encoding mode.");
return;
}
if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
narrow_oop_base() != Universe::narrow_oop_base() ||
narrow_oop_shift() != Universe::narrow_oop_shift()) {
log_info(cds)("CDS heap data need to be relocated because the archive was created with an incompatible oop encoding mode.");
_heap_pointers_need_patching = true;
} else {
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.");
MemRegion range = get_heap_regions_range_with_current_oop_encoding_mode();
if (!heap_reserved.contains(range)) {
log_info(cds)("CDS heap data need to be relocated because");
log_info(cds)("the desired range " PTR_FORMAT " - " PTR_FORMAT, p2i(range.start()), p2i(range.end()));
log_info(cds)("is outside of the heap " PTR_FORMAT " - " PTR_FORMAT, p2i(heap_reserved.start()), p2i(heap_reserved.end()));
_heap_pointers_need_patching = true;
}
}
ptrdiff_t delta = 0;
if (_heap_pointers_need_patching) {
// dumptime heap end ------------v
// [ |archived heap regions| ] runtime heap end ------v
// [ |archived heap regions| ]
// |<-----delta-------------------->|
//
// At dump time, the archived heap regions were near the top of the heap.
// At run time, they may not be inside the heap, so we move them so
// that they are now near the top of the runtime time. This can be done by
// the simple math of adding the delta as shown above.
address dumptime_heap_end = (address)_header->_heap_reserved.end();
address runtime_heap_end = (address)heap_reserved.end();
delta = runtime_heap_end - dumptime_heap_end;
}
log_info(cds)("CDS heap data relocation delta = " INTX_FORMAT " bytes", delta);
HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
CDSFileMapRegion* si = space_at(MetaspaceShared::first_string);
address relocated_strings_bottom = start_address_with_archived_oop_encoding_mode(si);
if (!is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes)) {
// Align the bottom of the string regions at G1 region boundary. This will avoid
// the situation where the highest open region and the lowest string region sharing
// the same G1 region. Otherwise we will fail to map the open regions.
size_t align = size_t(relocated_strings_bottom) % HeapRegion::GrainBytes;
delta -= align;
assert(is_aligned(relocated_strings_bottom + delta, HeapRegion::GrainBytes), "must be");
log_info(cds)("CDS heap data need to be relocated lower by a further " SIZE_FORMAT
" bytes to be aligned with HeapRegion::GrainBytes", align);
HeapShared::init_narrow_oop_decoding(narrow_oop_base() + delta, narrow_oop_shift());
_heap_pointers_need_patching = true;
}
// First, map string regions as closed archive heap regions.
// GC does not write into the regions.
if (map_heap_data(&string_ranges,
MetaspaceShared::first_string,
MetaspaceShared::max_strings,
&num_string_ranges)) {
StringTable::set_shared_string_mapped();
// Now, map open_archive heap regions, GC can write into the regions.
if (map_heap_data(&open_archive_heap_ranges,
MetaspaceShared::first_open_archive_heap_region,
MetaspaceShared::max_open_archive_heap_region,
&num_open_archive_heap_ranges,
true /* open */)) {
MetaspaceShared::set_open_archive_heap_region_mapped();
}
}
}
void FileMapInfo::map_heap_regions() {
if (has_heap_regions()) {
map_heap_regions_impl();
}
if (!StringTable::shared_string_mapped()) {
assert(string_ranges == NULL && num_string_ranges == 0, "sanity");
}
@ -926,13 +1030,13 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
for (int i = first;
i < first + max; i++) {
si = space_at(i);
size_t used = si->_used;
if (used > 0) {
size_t size = used;
char* requested_addr = (char*)((void*)CompressedOops::decode_not_null(
(narrowOop)si->_addr._offset));
regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
size_t size = si->_used;
if (size > 0) {
HeapWord* start = (HeapWord*)start_address_with_archived_oop_encoding_mode(si);
regions[region_num] = MemRegion(start, size / HeapWordSize);
region_num ++;
log_info(cds)("Trying to map heap data: region[%d] at " INTPTR_FORMAT ", size = " SIZE_FORMAT_W(8) " bytes",
i, p2i(start), size);
}
}
@ -942,16 +1046,14 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
// Check that ranges are within the java heap
if (!G1CollectedHeap::heap()->check_archive_addresses(regions, region_num)) {
log_info(cds)("UseSharedSpaces: Unable to allocate region, "
"range is not within java heap.");
log_info(cds)("UseSharedSpaces: Unable to allocate region, range is not within java heap.");
return false;
}
// allocate from java heap
if (!G1CollectedHeap::heap()->alloc_archive_regions(
regions, region_num, is_open_archive)) {
log_info(cds)("UseSharedSpaces: Unable to allocate region, "
"java heap range is already in use.");
log_info(cds)("UseSharedSpaces: Unable to allocate region, java heap range is already in use.");
return false;
}
@ -967,7 +1069,9 @@ bool FileMapInfo::map_heap_data(MemRegion **heap_mem, int first,
if (base == NULL || base != addr) {
// dealloc the regions from java heap
dealloc_archive_heap_regions(regions, region_num);
log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap.");
log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. "
INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes",
p2i(addr), regions[i].byte_size());
return false;
}
}
@ -995,6 +1099,31 @@ bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
return true;
}
void FileMapInfo::patch_archived_heap_embedded_pointers() {
if (!_heap_pointers_need_patching) {
return;
}
patch_archived_heap_embedded_pointers(string_ranges,
num_string_ranges,
MetaspaceShared::first_string);
patch_archived_heap_embedded_pointers(open_archive_heap_ranges,
num_open_archive_heap_ranges,
MetaspaceShared::first_open_archive_heap_region);
}
void FileMapInfo::patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
int first_region_idx) {
for (int i=0; i<num_ranges; i++) {
CDSFileMapRegion* si = space_at(i + first_region_idx);
HeapShared::patch_archived_heap_embedded_pointers(ranges[i], (address)si->_oopmap,
si->_oopmap_size_in_bits);
}
}
// This internally allocates objects using SystemDictionary::Object_klass(), so it
// must be called after the well-known classes are resolved.
void FileMapInfo::fixup_mapped_heap_regions() {
// If any string regions were found, call the fill routine to make them parseable.
// Note that string_ranges may be non-NULL even if no ranges were found.
@ -1036,7 +1165,7 @@ bool FileMapInfo::verify_region_checksum(int i) {
!MetaspaceShared::open_archive_heap_region_mapped())) {
return true; // archived heap data is not mapped
}
const char* buf = _header->region_addr(i);
const char* buf = region_addr(i);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
if (crc != space_at(i)->_crc) {
fail_continue("Checksum verification failed.");
@ -1057,7 +1186,7 @@ void FileMapInfo::unmap_region(int i) {
return;
}
char* addr = _header->region_addr(i);
char* addr = region_addr(i);
if (!os::unmap_memory(addr, size)) {
fail_stop("Unable to unmap shared space.");
}
@ -1078,6 +1207,7 @@ void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
FileMapInfo* FileMapInfo::_current_info = NULL;
bool FileMapInfo::_heap_pointers_need_patching = false;
Array<u8>* FileMapInfo::_shared_path_table = NULL;
int FileMapInfo::_shared_path_table_size = 0;
size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
@ -1107,12 +1237,14 @@ bool FileMapInfo::initialize() {
return true;
}
char* FileMapHeader::region_addr(int idx) {
char* FileMapInfo::region_addr(int idx) {
CDSFileMapRegion* si = space_at(idx);
if (MetaspaceShared::is_heap_region(idx)) {
return _space[idx]._used > 0 ?
(char*)((void*)CompressedOops::decode_not_null((narrowOop)_space[idx]._addr._offset)) : NULL;
assert(DumpSharedSpaces, "The following doesn't work at runtime");
return si->_used > 0 ?
(char*)start_address_with_current_oop_encoding_mode(si) : NULL;
} else {
return _space[idx]._addr._base;
return si->_addr._base;
}
}
@ -1216,34 +1348,25 @@ bool FileMapInfo::is_in_shared_region(const void* p, int idx) {
idx == MetaspaceShared::rw ||
idx == MetaspaceShared::mc ||
idx == MetaspaceShared::md, "invalid region index");
char* base = _header->region_addr(idx);
char* base = region_addr(idx);
if (p >= base && p < base + space_at(idx)->_used) {
return true;
}
return false;
}
void FileMapInfo::print_shared_spaces() {
tty->print_cr("Shared Spaces:");
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
CDSFileMapRegion* si = space_at(i);
char *base = _header->region_addr(i);
tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT,
shared_region_name[i],
p2i(base), p2i(base + si->_used));
}
}
// Unmap mapped regions of shared space.
void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
map_info->fail_continue("%s", msg);
for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
char *addr = map_info->_header->region_addr(i);
if (addr != NULL && !MetaspaceShared::is_heap_region(i)) {
map_info->unmap_region(i);
map_info->space_at(i)->_addr._base = NULL;
if (!MetaspaceShared::is_heap_region(i)) {
char *addr = map_info->region_addr(i);
if (addr != NULL) {
map_info->unmap_region(i);
map_info->space_at(i)->_addr._base = NULL;
}
}
}
// Dealloc the archive heap regions only without unmapping. The regions are part

View File

@ -88,6 +88,11 @@ public:
}
};
struct ArchiveHeapOopmapInfo {
address _oopmap; // bitmap for relocating embedded oops
size_t _oopmap_size_in_bits;
};
struct FileMapHeader : public CDSFileMapHeaderBase {
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
@ -104,6 +109,7 @@ struct FileMapHeader : public CDSFileMapHeaderBase {
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).
MemRegion _heap_reserved; // reserved region for the entire heap at dump time.
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@ -152,13 +158,15 @@ struct FileMapHeader : public CDSFileMapHeaderBase {
jshort max_used_path_index() { return _max_used_path_index; }
jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
char* region_addr(int idx);
bool validate();
void populate(FileMapInfo* info, size_t alignment);
int compute_crc();
};
CDSFileMapRegion* space_at(int i) {
assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
return &_space[i];
}
};
class FileMapInfo : public CHeapObj<mtInternal> {
private:
@ -194,6 +202,7 @@ public:
char* _paths_misc_info;
static FileMapInfo* _current_info;
static bool _heap_pointers_need_patching;
bool init_from_file(int fd);
void align_file_position();
@ -253,12 +262,19 @@ public:
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
size_t write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
GrowableArray<ArchiveHeapOopmapInfo> *oopmaps,
int first_region_id, int max_num_regions);
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_impl() NOT_CDS_JAVA_HEAP_RETURN;
void map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
void patch_archived_heap_embedded_pointers() NOT_CDS_JAVA_HEAP_RETURN;
void patch_archived_heap_embedded_pointers(MemRegion* ranges, int num_ranges,
int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN;
bool has_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false);
MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
void unmap_region(int i);
bool verify_region_checksum(int i);
void close();
@ -274,7 +290,6 @@ public:
static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
void print_shared_spaces() NOT_CDS_RETURN;
// Stop CDS sharing and unmap CDS regions.
static void stop_sharing_and_unmap(const char* msg);
@ -303,6 +318,8 @@ public:
return _shared_path_table_size;
}
char* region_addr(int idx);
private:
bool map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
@ -310,9 +327,24 @@ public:
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];
return _header->space_at(i);
}
narrowOop offset_of_space(CDSFileMapRegion* spc) {
return (narrowOop)(spc->_addr._offset);
}
// The starting address of spc, as calculated with CompressedOop::decode_non_null()
address start_address_with_current_oop_encoding_mode(CDSFileMapRegion* spc) {
return decode_start_address(spc, true);
}
// The starting address of spc, as calculated with HeapShared::decode_with_archived_oop_encoding_mode()
address start_address_with_archived_oop_encoding_mode(CDSFileMapRegion* spc) {
return decode_start_address(spc, false);
}
address decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode);
};
#endif // SHARE_VM_MEMORY_FILEMAP_HPP

View File

@ -29,7 +29,7 @@
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
#include "memory/heapShared.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
@ -38,6 +38,7 @@
#include "oops/compressedOops.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#if INCLUDE_CDS_JAVA_HEAP
KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL;
@ -72,6 +73,9 @@ KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) {
return info;
}
address HeapShared::_narrow_oop_base;
int HeapShared::_narrow_oop_shift;
int HeapShared::num_of_subgraph_infos() {
int num = 0;
KlassSubGraphInfo* info = _subgraph_info_list;
@ -320,7 +324,7 @@ void HeapShared::initialize_from_archived_subgraph(Klass* k) {
// point. All objects in the subgraph reachable from the object are
// also 'known' by GC.
oop v = MetaspaceShared::materialize_archived_object(
CompressedOops::decode(entry_field_records->at(i+1)));
entry_field_records->at(i+1));
m->obj_field_put(field_offset, v);
i += 2;
}
@ -601,4 +605,96 @@ void HeapShared::archive_module_graph_objects(Thread* THREAD) {
archive_reachable_objects_from_static_field(info->klass, info->offset, info->type, CHECK);
}
}
// At dump-time, find the location of all the non-null oop pointers in an archived heap
// region. This way we can quickly relocate all the pointers without using
// BasicOopIterateClosure at runtime.
class FindEmbeddedNonNullPointers: public BasicOopIterateClosure {
narrowOop* _start;
BitMap *_oopmap;
int _num_total_oops;
int _num_null_oops;
public:
FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap)
: _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {}
virtual bool should_verify_oops(void) {
return false;
}
virtual void do_oop(narrowOop* p) {
_num_total_oops ++;
narrowOop v = *p;
if (!CompressedOops::is_null(v)) {
size_t idx = p - _start;
_oopmap->set_bit(idx);
} else {
_num_null_oops ++;
}
}
virtual void do_oop(oop *p) {
ShouldNotReachHere();
}
int num_total_oops() const { return _num_total_oops; }
int num_null_oops() const { return _num_null_oops; }
};
ResourceBitMap HeapShared::calculate_oopmap(MemRegion region) {
assert(UseCompressedOops, "must be");
size_t num_bits = region.byte_size() / sizeof(narrowOop);
ResourceBitMap oopmap(num_bits);
HeapWord* p = region.start();
HeapWord* end = region.end();
FindEmbeddedNonNullPointers finder((narrowOop*)p, &oopmap);
int num_objs = 0;
while (p < end) {
oop o = (oop)p;
o->oop_iterate(&finder);
p += o->size();
++ num_objs;
}
log_info(cds, heap)("calculate_oopmap: objects = %6d, embedded oops = %7d, nulls = %7d",
num_objs, finder.num_total_oops(), finder.num_null_oops());
return oopmap;
}
void HeapShared::init_narrow_oop_decoding(address base, int shift) {
_narrow_oop_base = base;
_narrow_oop_shift = shift;
}
// Patch all the embedded oop pointers inside an archived heap region,
// to be consistent with the runtime oop encoding.
class PatchEmbeddedPointers: public BitMapClosure {
narrowOop* _start;
public:
PatchEmbeddedPointers(narrowOop* start) : _start(start) {}
bool do_bit(size_t offset) {
narrowOop* p = _start + offset;
narrowOop v = *p;
assert(!CompressedOops::is_null(v), "null oops should have been filtered out at dump time");
oop o = HeapShared::decode_with_archived_oop_encoding_mode(v);
RawAccess<IS_NOT_NULL>::oop_store(p, o);
return true;
}
};
void HeapShared::patch_archived_heap_embedded_pointers(MemRegion region, address oopmap,
size_t oopmap_size_in_bits) {
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
#ifndef PRODUCT
ResourceMark rm;
ResourceBitMap checkBm = calculate_oopmap(region);
assert(bm.is_same(checkBm), "sanity");
#endif
PatchEmbeddedPointers patcher((narrowOop*)region.start());
bm.iterate(&patcher);
}
#endif // INCLUDE_CDS_JAVA_HEAP

View File

@ -30,6 +30,7 @@
#include "oops/objArrayKlass.hpp"
#include "oops/oop.hpp"
#include "oops/typeArrayKlass.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp"
#if INCLUDE_CDS_JAVA_HEAP
@ -123,13 +124,33 @@ class HeapShared: AllStatic {
static int num_of_subgraph_infos();
static size_t build_archived_subgraph_info_records(int num_records);
// Used by decode_with_archived_oop_encoding_mode
static address _narrow_oop_base;
static int _narrow_oop_shift;
#endif // INCLUDE_CDS_JAVA_HEAP
public:
static char* read_archived_subgraph_infos(char* buffer) NOT_CDS_JAVA_HEAP_RETURN_(buffer);
static void write_archived_subgraph_infos() NOT_CDS_JAVA_HEAP_RETURN;
static void initialize_from_archived_subgraph(Klass* k) NOT_CDS_JAVA_HEAP_RETURN;
// NarrowOops stored in the CDS archive may use a different encoding scheme
// than Universe::narrow_oop_{base,shift} -- see FileMapInfo::map_heap_regions_impl.
// To decode them, do not use CompressedOops::decode_not_null. Use this
// function instead.
inline static oop decode_with_archived_oop_encoding_mode(narrowOop v) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static void init_narrow_oop_decoding(address base, int shift) NOT_CDS_JAVA_HEAP_RETURN;
static void patch_archived_heap_embedded_pointers(MemRegion mem, address oopmap,
size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
static void init_archivable_static_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
static void archive_module_graph_objects(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
#if INCLUDE_CDS_JAVA_HEAP
static ResourceBitMap calculate_oopmap(MemRegion region);
#endif
};
#endif // SHARE_VM_MEMORY_HEAPSHARED_HPP

View File

@ -0,0 +1,42 @@
/*
* 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_VM_MEMORY_HEAPSHARED_INLINE_HPP
#define SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP
#include "oops/compressedOops.inline.hpp"
#include "memory/heapShared.hpp"
#if INCLUDE_CDS_JAVA_HEAP
inline oop HeapShared::decode_with_archived_oop_encoding_mode(narrowOop v) {
assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
oop result = (oop)(void*)((uintptr_t)_narrow_oop_base + ((uintptr_t)v << _narrow_oop_shift));
assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
return result;
}
#endif
#endif // SHARE_VM_MEMORY_HEAPSHARED_INLINE_HPP

View File

@ -39,7 +39,7 @@
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.hpp"
#include "memory/heapShared.inline.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
@ -61,6 +61,7 @@
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/hashtable.inline.hpp"
#if INCLUDE_G1GC
@ -227,7 +228,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
// Map in spaces now also
if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
size_t cds_total = core_spaces_size();
cds_address = (address)mapinfo->header()->region_addr(0);
cds_address = (address)mapinfo->region_addr(0);
#ifdef _LP64
if (Metaspace::using_class_space()) {
char* cds_end = (char*)(cds_address + cds_total);
@ -309,10 +310,10 @@ void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
Universe::set_narrow_klass_range(cds_total);
Metaspace::initialize_class_space(tmp_class_space);
tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
log_info(cds)("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
tty->print_cr("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
log_info(cds)("Allocated temporary class space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
CompressedClassSpaceSize, p2i(tmp_class_space.base()));
#endif
@ -424,6 +425,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
soc->do_tag(--tag);
JavaClasses::serialize_offsets(soc);
InstanceMirrorKlass::serialize_offsets(soc);
soc->do_tag(--tag);
soc->do_tag(666);
@ -1017,7 +1019,13 @@ private:
GrowableArray<MemRegion> *_closed_archive_heap_regions;
GrowableArray<MemRegion> *_open_archive_heap_regions;
GrowableArray<ArchiveHeapOopmapInfo> *_closed_archive_heap_oopmaps;
GrowableArray<ArchiveHeapOopmapInfo> *_open_archive_heap_oopmaps;
void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
void dump_archive_heap_oopmaps() NOT_CDS_JAVA_HEAP_RETURN;
void dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps);
void dump_symbols();
char* dump_read_only_tables();
void print_region_stats();
@ -1329,6 +1337,9 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
WriteClosure wc(&_ro_region);
MetaspaceShared::serialize(&wc);
// Write the bitmaps for patching the archive heap regions
dump_archive_heap_oopmaps();
char* newtop = _ro_region.top();
ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - oldtop), true);
return buckets_top;
@ -1471,10 +1482,12 @@ void VM_PopulateDumpSharedSpace::doit() {
_total_string_region_size = mapinfo->write_archive_heap_regions(
_closed_archive_heap_regions,
_closed_archive_heap_oopmaps,
MetaspaceShared::first_string,
MetaspaceShared::max_strings);
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
_open_archive_heap_regions,
_open_archive_heap_oopmaps,
MetaspaceShared::first_open_archive_heap_region,
MetaspaceShared::max_open_archive_heap_region);
}
@ -1810,6 +1823,36 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
G1HeapVerifier::verify_archive_regions();
}
void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps() {
if (MetaspaceShared::is_heap_object_archiving_allowed()) {
_closed_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
dump_archive_heap_oopmaps(_closed_archive_heap_regions, _closed_archive_heap_oopmaps);
_open_archive_heap_oopmaps = new GrowableArray<ArchiveHeapOopmapInfo>(2);
dump_archive_heap_oopmaps(_open_archive_heap_regions, _open_archive_heap_oopmaps);
}
}
void VM_PopulateDumpSharedSpace::dump_archive_heap_oopmaps(GrowableArray<MemRegion>* regions,
GrowableArray<ArchiveHeapOopmapInfo>* oopmaps) {
for (int i=0; i<regions->length(); i++) {
ResourceBitMap oopmap = HeapShared::calculate_oopmap(regions->at(i));
size_t size_in_bits = oopmap.size();
size_t size_in_bytes = oopmap.size_in_bytes();
uintptr_t* buffer = (uintptr_t*)_ro_region.allocate(size_in_bytes, sizeof(intptr_t));
oopmap.write_to(buffer, size_in_bytes);
log_info(cds)("Oopmap = " INTPTR_FORMAT " (" SIZE_FORMAT_W(6) " bytes) for heap region "
INTPTR_FORMAT " (" SIZE_FORMAT_W(8) " bytes)",
p2i(buffer), size_in_bytes,
p2i(regions->at(i).start()), regions->at(i).byte_size());
ArchiveHeapOopmapInfo info;
info._oopmap = (address)buffer;
info._oopmap_size_in_bits = size_in_bits;
oopmaps->append(info);
}
}
void MetaspaceShared::dump_closed_archive_heap_objects(
GrowableArray<MemRegion> * closed_archive) {
assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects");
@ -1896,8 +1939,9 @@ oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
return archived_oop;
}
oop MetaspaceShared::materialize_archived_object(oop obj) {
if (obj != NULL) {
oop MetaspaceShared::materialize_archived_object(narrowOop v) {
if (!CompressedOops::is_null(v)) {
oop obj = HeapShared::decode_with_archived_oop_encoding_mode(v);
return G1CollectedHeap::heap()->materialize_archived_object(obj);
}
return NULL;
@ -1973,7 +2017,7 @@ public:
"Archived heap object is not allowed");
assert(MetaspaceShared::open_archive_heap_region_mapped(),
"Open archive heap region is not mapped");
*p = CompressedOops::decode_not_null(o);
*p = HeapShared::decode_with_archived_oop_encoding_mode(o);
}
}
@ -2003,13 +2047,6 @@ bool MetaspaceShared::is_in_trampoline_frame(address addr) {
return false;
}
void MetaspaceShared::print_shared_spaces() {
if (UseSharedSpaces) {
FileMapInfo::current_info()->print_shared_spaces();
}
}
// Map shared spaces at requested addresses and return if succeeded.
bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
size_t image_alignment = mapinfo->alignment();
@ -2120,6 +2157,8 @@ void MetaspaceShared::initialize_shared_spaces() {
// Initialize the run-time symbol table.
SymbolTable::create_table();
mapinfo->patch_archived_heap_embedded_pointers();
// Close the mapinfo file
mapinfo->close();

View File

@ -79,6 +79,7 @@ class MetaspaceShared : AllStatic {
// mapped java heap regions
first_string = od + 1, // index of first string region
max_strings = 2, // max number of string regions in string space
last_string = first_string + max_strings - 1,
first_open_archive_heap_region = first_string + max_strings,
max_open_archive_heap_region = 2,
@ -111,7 +112,7 @@ class MetaspaceShared : AllStatic {
}
static oop find_archived_heap_object(oop obj);
static oop archive_heap_object(oop obj, Thread* THREAD);
static oop materialize_archived_object(oop obj);
static oop materialize_archived_object(narrowOop v);
static void archive_klass_objects(Thread* THREAD);
#endif
@ -221,8 +222,6 @@ class MetaspaceShared : AllStatic {
NOT_CDS(return false);
}
static void print_shared_spaces();
static bool try_link_class(InstanceKlass* ik, TRAPS);
static void link_and_cleanup_shared_classes(TRAPS);
static void check_shared_class_loader_type(InstanceKlass* ik);

View File

@ -517,8 +517,11 @@ void Universe::fixup_mirrors(TRAPS) {
// that the number of objects allocated at this point is very small.
assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded");
HandleMark hm(THREAD);
// Cache the start of the static fields
InstanceMirrorKlass::init_offset_of_static_fields();
if (!UseSharedSpaces) {
// Cache the start of the static fields
InstanceMirrorKlass::init_offset_of_static_fields();
}
GrowableArray <Klass*>* list = java_lang_Class::fixup_mirror_list();
int list_length = list->length();

View File

@ -777,7 +777,7 @@ oop ConstantPoolCache::archived_references() {
if (CompressedOops::is_null(_archived_references)) {
return NULL;
}
return MetaspaceShared::materialize_archived_object(CompressedOops::decode_not_null(_archived_references));
return MetaspaceShared::materialize_archived_object(_archived_references);
}
void ConstantPoolCache::set_archived_references(oop o) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -66,3 +66,9 @@ int InstanceMirrorKlass::compute_static_oop_field_count(oop obj) {
}
return 0;
}
#if INCLUDE_CDS
void InstanceMirrorKlass::serialize_offsets(SerializeClosure* f) {
f->do_u4((u4*)&_offset_of_static_fields);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -99,6 +99,8 @@ class InstanceMirrorKlass: public InstanceKlass {
void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
static void serialize_offsets(class SerializeClosure* f) NOT_CDS_RETURN;
// Oop fields (and metadata) iterators
//
// The InstanceMirrorKlass iterators also visit the hidden Klass pointer.

View File

@ -571,6 +571,11 @@ oop Klass::archived_java_mirror_raw() {
return CompressedOops::decode(_archived_mirror);
}
narrowOop Klass::archived_java_mirror_raw_narrow() {
assert(has_raw_archived_mirror(), "must have raw archived mirror");
return _archived_mirror;
}
// No GC barrier
void Klass::set_archived_java_mirror_raw(oop m) {
assert(DumpSharedSpaces, "called only during runtime");

View File

@ -261,6 +261,7 @@ protected:
void set_java_mirror(Handle m);
oop archived_java_mirror_raw() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // no GC barrier
narrowOop archived_java_mirror_raw_narrow() NOT_CDS_JAVA_HEAP_RETURN_(0); // no GC barrier
void set_archived_java_mirror_raw(oop m) NOT_CDS_JAVA_HEAP_RETURN; // no GC barrier
// Temporary mirror switch used by RedefineClasses

View File

@ -1585,7 +1585,7 @@ static void no_shared_spaces(const char* message) {
if (RequireSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
"Class data sharing is inconsistent with other specified options.\n");
vm_exit_during_initialization("Unable to use shared archive.", message);
vm_exit_during_initialization("Unable to use shared archive", message);
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}

View File

@ -672,6 +672,11 @@ void BitMap::print_on_error(outputStream* st, const char* prefix) const {
prefix, p2i(map()), p2i((char*)map() + (size() >> LogBitsPerByte)));
}
void BitMap::write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const {
assert(buffer_size_in_bytes == size_in_bytes(), "must be");
memcpy(buffer, _map, size_in_bytes());
}
#ifndef PRODUCT
void BitMap::print_on(outputStream* st) const {

View File

@ -288,6 +288,7 @@ class BitMap {
bool is_full() const;
bool is_empty() const;
void write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const;
void print_on_error(outputStream* st, const char* prefix) const;
#ifndef PRODUCT

View File

@ -0,0 +1,100 @@
/*
* 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.
*
*/
/*
* @test
* @summary Test automatic relocation of archive heap regions dur to heap size changes.
* @requires vm.cds.archived.java.heap
* @requires (vm.gc=="null")
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @modules jdk.jartool/sun.tools.jar
* @compile ../test-classes/Hello.java
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DifferentHeapSizes
*/
import jdk.test.lib.process.OutputAnalyzer;
import sun.hotspot.WhiteBox;
import jdk.test.lib.cds.CDSTestUtils;
public class DifferentHeapSizes {
static class Scenario {
int dumpSize; // in MB
int runSizes[]; // in MB
Scenario(int ds, int... rs) {
dumpSize = ds;
runSizes = rs;
}
}
static Scenario[] scenarios = {
// dump -Xmx , run -Xmx
new Scenario( 32, 32, 64, 512, 2048, 4097, 16374, 31000),
new Scenario( 128, 32, 64, 512, 2048, 4097, 16374, 31000, 40000),
new Scenario( 2048, 32, 512, 2600, 4097, 8500, 31000, 40000),
new Scenario( 17000, 32, 512, 2048, 4097, 8500, 31000, 40000),
new Scenario( 31000, 32, 512, 2048, 4097, 8500, 17000, 40000)
};
public static void main(String[] args) throws Exception {
String dedup = "-XX:+UseStringDeduplication"; // This increases code coverage.
JarBuilder.getOrCreateHelloJar();
String appJar = TestCommon.getTestJar("hello.jar");
String appClasses[] = TestCommon.list("Hello");
for (Scenario s : scenarios) {
String dumpXmx = "-Xmx" + s.dumpSize + "m";
OutputAnalyzer output = TestCommon.dump(appJar, appClasses, dumpXmx);
for (int runSize : s.runSizes) {
String runXmx = "-Xmx" + runSize + "m";
CDSTestUtils.Result result = TestCommon.run("-cp", appJar, "-showversion",
"-Xlog:cds", runXmx, dedup, "Hello");
if (runSize < 32768) {
result
.assertNormalExit("Hello World")
.assertNormalExit(out -> {
out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
});
} else {
result.assertAbnormalExit("Unable to use shared archive: UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.");
}
}
}
String flag = "HeapBaseMinAddress";
String xxflag = "-XX:" + flag + "=";
String mx = "-Xmx128m";
long base = WhiteBox.getWhiteBox().getSizeTVMFlag(flag).longValue();
TestCommon.dump(appJar, appClasses, mx, xxflag + base);
TestCommon.run("-cp", appJar, "-showversion", "-Xlog:cds", mx, xxflag + (base + 256 * 1024 * 1024), dedup, "Hello")
.assertNormalExit("Hello World")
.assertNormalExit(out -> {
out.shouldNotContain(CDSTestUtils.MSG_RANGE_NOT_WITHIN_HEAP);
out.shouldNotContain(CDSTestUtils.MSG_RANGE_ALREADT_IN_USE);
});
}
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 Shared classes can still be used when archived heap regions cannot be
* mapped due to out of range, and -Xshare:on should not fail. Test on
* linux 64-bit only since the HeapBaseMinAddress value is platform specific.
* The value used in the test may cause different behavior on other platforms.
* @requires vm.cds.archived.java.heap
* @requires os.family == "linux"
* @library /test/lib /test/hotspot/jtreg/runtime/appcds
* @modules java.base/jdk.internal.misc
* @modules java.management
* jdk.jartool/sun.tools.jar
* @compile ../test-classes/Hello.java
* @run main RangeNotWithinHeap
*/
import jdk.test.lib.process.OutputAnalyzer;
public class RangeNotWithinHeap {
public static void main(String[] args) throws Exception {
JarBuilder.getOrCreateHelloJar();
String appJar = TestCommon.getTestJar("hello.jar");
String appClasses[] = TestCommon.list("Hello");
OutputAnalyzer output = TestCommon.dump(appJar, appClasses,
"-XX:HeapBaseMinAddress=0x600000000", "-Xmx6G", "-Xlog:gc+heap=trace");
TestCommon.checkDump(output, "oa0 space:");
// Force archive region out of runtime java heap
output = TestCommon.exec(appJar, "Hello");
TestCommon.checkExec(output, "Hello World");
output = TestCommon.exec(appJar,
"-XX:HeapBaseMinAddress=0x600000000", "-Xmx2G", "-Xlog:gc+heap=trace,cds", "Hello");
TestCommon.checkExec(output, "Hello World");
try {
output.shouldContain(
"UseSharedSpaces: Unable to allocate region, range is not within java heap.");
} catch (Exception e) {
// In rare case the heap data is not used.
if (output.getOutput().contains("Cached heap data from the CDS archive is being ignored")) {
return;
}
// Check for common shared class data mapping failures.
TestCommon.checkCommonExecExceptions(output, e);
}
}
}

View File

@ -141,10 +141,10 @@ public class IncompatibleOptions {
// main class param, and fails with "Could not find or load main class"
if (!extraOption.isEmpty()) {
output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
collectorOption, extraOption, "HelloString");
collectorOption, "-Xlog:cds", extraOption, "HelloString");
} else {
output = TestCommon.exec(appJar, "-XX:+UseCompressedOops",
collectorOption, "HelloString");
collectorOption, "-Xlog:cds", "HelloString");
}
if (expectedWarning != null)

View File

@ -36,6 +36,11 @@ import jtreg.SkippedException;
// This class contains common test utilities for testing CDS
public class CDSTestUtils {
public static final String MSG_RANGE_NOT_WITHIN_HEAP =
"UseSharedSpaces: Unable to allocate region, range is not within java heap.";
public static final String MSG_RANGE_ALREADT_IN_USE =
"Unable to allocate region, java heap range is already in use.";
public interface Checker {
public void check(OutputAnalyzer output) throws Exception;
}