mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8179302: Pre-resolve constant pool string entries and cache resolved_reference arrays in CDS archive
8185924: G1NoteEndOfConcMarkClosure::doHeapRegion() does not do remembered set cleanup work for archive region Shared class' constant pool resolved_references array is cached. Co-authored-by: Thomas Schatzl <thomas.schatzl@oracle.com> Reviewed-by: coleenp, iklam, tschatzl
This commit is contained in:
parent
85fedbbb12
commit
4a77945c89
36 changed files with 931 additions and 418 deletions
|
@ -90,7 +90,7 @@ class StableMemoryChecker : public StackObj {
|
|||
|
||||
// --------------------------------------------------------------------------
|
||||
StringTable* StringTable::_the_table = NULL;
|
||||
bool StringTable::_ignore_shared_strings = false;
|
||||
bool StringTable::_shared_string_mapped = false;
|
||||
bool StringTable::_needs_rehashing = false;
|
||||
|
||||
volatile int StringTable::_parallel_claimed_idx = 0;
|
||||
|
@ -678,13 +678,30 @@ int StringtableDCmd::num_arguments() {
|
|||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
// Sharing
|
||||
oop StringTable::create_archived_string(oop s, Thread* THREAD) {
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
|
||||
oop new_s = NULL;
|
||||
typeArrayOop v = java_lang_String::value(s);
|
||||
typeArrayOop new_v = (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
|
||||
if (new_v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
new_s = MetaspaceShared::archive_heap_object(s, THREAD);
|
||||
if (new_s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// adjust the pointer to the 'value' field in the new String oop
|
||||
java_lang_String::set_value_raw(new_s, new_v);
|
||||
return new_s;
|
||||
}
|
||||
|
||||
bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||
CompactStringTableWriter* writer) {
|
||||
#if INCLUDE_CDS && INCLUDE_ALL_GCS && defined(_LP64) && !defined(_WINDOWS)
|
||||
assert(UseG1GC, "Only support G1 GC");
|
||||
assert(UseCompressedOops && UseCompressedClassPointers,
|
||||
"Only support UseCompressedOops and UseCompressedClassPointers enabled");
|
||||
assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
|
||||
|
||||
Thread* THREAD = Thread::current();
|
||||
G1CollectedHeap::heap()->begin_archive_alloc_range();
|
||||
|
@ -697,64 +714,29 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
|||
continue;
|
||||
}
|
||||
|
||||
// allocate the new 'value' array first
|
||||
typeArrayOop v = java_lang_String::value(s);
|
||||
int v_len = v->size();
|
||||
typeArrayOop new_v;
|
||||
if (G1CollectedHeap::heap()->is_archive_alloc_too_large(v_len)) {
|
||||
continue; // skip the current String. The 'value' array is too large to handle
|
||||
} else {
|
||||
new_v = (typeArrayOop)G1CollectedHeap::heap()->archive_mem_allocate(v_len);
|
||||
if (new_v == NULL) {
|
||||
return false; // allocation failed
|
||||
}
|
||||
}
|
||||
// now allocate the new String object
|
||||
int s_len = s->size();
|
||||
oop new_s = (oop)G1CollectedHeap::heap()->archive_mem_allocate(s_len);
|
||||
java_lang_String::set_hash(s, hash);
|
||||
oop new_s = create_archived_string(s, THREAD);
|
||||
if (new_s == NULL) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
s->identity_hash();
|
||||
v->identity_hash();
|
||||
|
||||
// copy the objects' data
|
||||
Copy::aligned_disjoint_words((HeapWord*)s, (HeapWord*)new_s, s_len);
|
||||
Copy::aligned_disjoint_words((HeapWord*)v, (HeapWord*)new_v, v_len);
|
||||
|
||||
// adjust the pointer to the 'value' field in the new String oop. Also pre-compute and set the
|
||||
// 'hash' field. That avoids "write" to the shared strings at runtime by the deduplication process.
|
||||
java_lang_String::set_value_raw(new_s, new_v);
|
||||
if (java_lang_String::hash(new_s) == 0) {
|
||||
java_lang_String::set_hash(new_s, hash);
|
||||
}
|
||||
// set the archived string in bucket
|
||||
bucket->set_literal(new_s);
|
||||
|
||||
// add to the compact table
|
||||
writer->add(hash, new_s);
|
||||
|
||||
MetaspaceShared::relocate_klass_ptr(new_s);
|
||||
MetaspaceShared::relocate_klass_ptr(new_v);
|
||||
}
|
||||
}
|
||||
|
||||
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
|
||||
assert(string_space->length() <= 2, "sanity");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringTable::write_to_archive(GrowableArray<MemRegion> *string_space) {
|
||||
#if INCLUDE_CDS
|
||||
assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
|
||||
|
||||
_shared_table.reset();
|
||||
if (!(UseG1GC && UseCompressedOops && UseCompressedClassPointers)) {
|
||||
log_info(cds)(
|
||||
"Shared strings are excluded from the archive as UseG1GC, "
|
||||
"UseCompressedOops and UseCompressedClassPointers are required."
|
||||
"Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
|
||||
BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
|
||||
BOOL_TO_STR(UseCompressedClassPointers));
|
||||
} else {
|
||||
int num_buckets = the_table()->number_of_entries() /
|
||||
SharedSymbolTableBucketSize;
|
||||
// calculation of num_buckets can result in zero buckets, we need at least one
|
||||
|
@ -765,26 +747,21 @@ void StringTable::write_to_archive(GrowableArray<MemRegion> *string_space) {
|
|||
if (copy_shared_string(string_space, &writer)) {
|
||||
writer.dump(&_shared_table);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void StringTable::serialize(SerializeClosure* soc) {
|
||||
#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
|
||||
_shared_table.set_type(CompactHashtable<oop, char>::_string_table);
|
||||
_shared_table.serialize(soc);
|
||||
|
||||
if (soc->writing()) {
|
||||
_shared_table.reset(); // Sanity. Make sure we don't use the shared table at dump time
|
||||
} else if (_ignore_shared_strings) {
|
||||
} else if (!_shared_string_mapped) {
|
||||
_shared_table.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void StringTable::shared_oops_do(OopClosure* f) {
|
||||
#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
|
||||
_shared_table.oops_do(f);
|
||||
#endif
|
||||
}
|
||||
#endif //INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ private:
|
|||
|
||||
// Shared string table
|
||||
static CompactHashtable<oop, char> _shared_table;
|
||||
static bool _ignore_shared_strings;
|
||||
static bool _shared_string_mapped;
|
||||
|
||||
// Set if one bucket is out of balance due to hash algorithm deficiency
|
||||
static bool _needs_rehashing;
|
||||
|
@ -157,13 +157,14 @@ public:
|
|||
static int verify_and_compare_entries();
|
||||
|
||||
// Sharing
|
||||
static void ignore_shared_strings(bool v) { _ignore_shared_strings = v; }
|
||||
static bool shared_string_ignored() { return _ignore_shared_strings; }
|
||||
static void shared_oops_do(OopClosure* f);
|
||||
static void set_shared_string_mapped() { _shared_string_mapped = true; }
|
||||
static bool shared_string_mapped() { return _shared_string_mapped; }
|
||||
static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static bool copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||
CompactStringTableWriter* ch_table);
|
||||
static void write_to_archive(GrowableArray<MemRegion> *string_space);
|
||||
static void serialize(SerializeClosure* soc);
|
||||
CompactStringTableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
static void write_to_archive(GrowableArray<MemRegion> *string_space) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void serialize(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
// Rehash the symbol table if it gets out of balance
|
||||
static void rehash_table();
|
||||
|
|
|
@ -331,12 +331,13 @@ void G1DefaultPLABAllocator::waste(size_t& wasted, size_t& undo_wasted) {
|
|||
}
|
||||
|
||||
bool G1ArchiveAllocator::_archive_check_enabled = false;
|
||||
G1ArchiveRegionMap G1ArchiveAllocator::_archive_region_map;
|
||||
G1ArchiveRegionMap G1ArchiveAllocator::_closed_archive_region_map;
|
||||
G1ArchiveRegionMap G1ArchiveAllocator::_open_archive_region_map;
|
||||
|
||||
G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h) {
|
||||
G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h, bool open) {
|
||||
// Create the archive allocator, and also enable archive object checking
|
||||
// in mark-sweep, since we will be creating archive regions.
|
||||
G1ArchiveAllocator* result = new G1ArchiveAllocator(g1h);
|
||||
G1ArchiveAllocator* result = new G1ArchiveAllocator(g1h, open);
|
||||
enable_archive_object_check();
|
||||
return result;
|
||||
}
|
||||
|
@ -350,7 +351,11 @@ bool G1ArchiveAllocator::alloc_new_region() {
|
|||
return false;
|
||||
}
|
||||
assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index());
|
||||
hr->set_archive();
|
||||
if (_open) {
|
||||
hr->set_open_archive();
|
||||
} else {
|
||||
hr->set_closed_archive();
|
||||
}
|
||||
_g1h->old_set_add(hr);
|
||||
_g1h->hr_printer()->alloc(hr);
|
||||
_allocated_regions.append(hr);
|
||||
|
@ -362,7 +367,7 @@ bool G1ArchiveAllocator::alloc_new_region() {
|
|||
_max = _bottom + HeapRegion::min_region_size_in_words();
|
||||
|
||||
// Tell mark-sweep that objects in this region are not to be marked.
|
||||
set_range_archive(MemRegion(_bottom, HeapRegion::GrainWords), true);
|
||||
set_range_archive(MemRegion(_bottom, HeapRegion::GrainWords), _open);
|
||||
|
||||
// Since we've modified the old set, call update_sizes.
|
||||
_g1h->g1mm()->update_sizes();
|
||||
|
|
|
@ -321,11 +321,19 @@ protected:
|
|||
};
|
||||
|
||||
// G1ArchiveAllocator is used to allocate memory in archive
|
||||
// regions. Such regions are not modifiable by GC, being neither
|
||||
// scavenged nor compacted, or even marked in the object header.
|
||||
// They can contain no pointers to non-archive heap regions,
|
||||
// regions. Such regions are not scavenged nor compacted by GC.
|
||||
// There are two types of archive regions, which are
|
||||
// differ in the kind of references allowed for the contained objects:
|
||||
//
|
||||
// - 'Closed' archive region contain no references outside of other
|
||||
// closed archive regions. The region is immutable by GC. GC does
|
||||
// not mark object header in 'closed' archive region.
|
||||
// - An 'open' archive region allow references to any other regions,
|
||||
// including closed archive, open archive and other java heap regions.
|
||||
// GC can adjust pointers and mark object header in 'open' archive region.
|
||||
class G1ArchiveAllocator : public CHeapObj<mtGC> {
|
||||
protected:
|
||||
bool _open; // Indicate if the region is 'open' archive.
|
||||
G1CollectedHeap* _g1h;
|
||||
|
||||
// The current allocation region
|
||||
|
@ -347,7 +355,7 @@ protected:
|
|||
bool alloc_new_region();
|
||||
|
||||
public:
|
||||
G1ArchiveAllocator(G1CollectedHeap* g1h) :
|
||||
G1ArchiveAllocator(G1CollectedHeap* g1h, bool open) :
|
||||
_g1h(g1h),
|
||||
_allocation_region(NULL),
|
||||
_allocated_regions((ResourceObj::set_allocation_type((address) &_allocated_regions,
|
||||
|
@ -356,13 +364,14 @@ public:
|
|||
_summary_bytes_used(0),
|
||||
_bottom(NULL),
|
||||
_top(NULL),
|
||||
_max(NULL) { }
|
||||
_max(NULL),
|
||||
_open(open) { }
|
||||
|
||||
virtual ~G1ArchiveAllocator() {
|
||||
assert(_allocation_region == NULL, "_allocation_region not NULL");
|
||||
}
|
||||
|
||||
static G1ArchiveAllocator* create_allocator(G1CollectedHeap* g1h);
|
||||
static G1ArchiveAllocator* create_allocator(G1CollectedHeap* g1h, bool open);
|
||||
|
||||
// Allocate memory for an individual object.
|
||||
HeapWord* archive_mem_allocate(size_t word_size);
|
||||
|
@ -389,18 +398,26 @@ public:
|
|||
static inline void enable_archive_object_check();
|
||||
|
||||
// Set the regions containing the specified address range as archive/non-archive.
|
||||
static inline void set_range_archive(MemRegion range, bool is_archive);
|
||||
static inline void set_range_archive(MemRegion range, bool open);
|
||||
|
||||
// Check if the object is in closed archive
|
||||
static inline bool is_closed_archive_object(oop object);
|
||||
// Check if the object is in open archive
|
||||
static inline bool is_open_archive_object(oop object);
|
||||
// Check if the object is either in closed archive or open archive
|
||||
static inline bool is_archive_object(oop object);
|
||||
|
||||
private:
|
||||
static bool _archive_check_enabled;
|
||||
static G1ArchiveRegionMap _archive_region_map;
|
||||
static G1ArchiveRegionMap _closed_archive_region_map;
|
||||
static G1ArchiveRegionMap _open_archive_region_map;
|
||||
|
||||
// Check if an object is in an archive region using the _archive_region_map.
|
||||
static inline bool in_archive_range(oop object);
|
||||
// Check if an object is in a closed archive region using the _closed_archive_region_map.
|
||||
static inline bool in_closed_archive_range(oop object);
|
||||
// Check if an object is in open archive region using the _open_archive_region_map.
|
||||
static inline bool in_open_archive_range(oop object);
|
||||
|
||||
// Check if archive object checking is enabled, to avoid calling in_archive_range
|
||||
// Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range
|
||||
// unnecessarily.
|
||||
static inline bool archive_check_enabled();
|
||||
};
|
||||
|
|
|
@ -55,37 +55,60 @@ inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
|
|||
}
|
||||
}
|
||||
|
||||
// Create the _archive_region_map which is used to identify archive objects.
|
||||
// Create the maps which is used to identify archive objects.
|
||||
inline void G1ArchiveAllocator::enable_archive_object_check() {
|
||||
assert(!_archive_check_enabled, "archive range check already enabled");
|
||||
if (_archive_check_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
_archive_check_enabled = true;
|
||||
size_t length = Universe::heap()->max_capacity();
|
||||
_archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
|
||||
_closed_archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
|
||||
(HeapWord*)Universe::heap()->base() + length,
|
||||
HeapRegion::GrainBytes);
|
||||
_open_archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
|
||||
(HeapWord*)Universe::heap()->base() + length,
|
||||
HeapRegion::GrainBytes);
|
||||
}
|
||||
|
||||
// Set the regions containing the specified address range as archive/non-archive.
|
||||
inline void G1ArchiveAllocator::set_range_archive(MemRegion range, bool is_archive) {
|
||||
// Set the regions containing the specified address range as archive.
|
||||
inline void G1ArchiveAllocator::set_range_archive(MemRegion range, bool open) {
|
||||
assert(_archive_check_enabled, "archive range check not enabled");
|
||||
_archive_region_map.set_by_address(range, is_archive);
|
||||
if (open) {
|
||||
_open_archive_region_map.set_by_address(range, true);
|
||||
} else {
|
||||
_closed_archive_region_map.set_by_address(range, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an object is in an archive region using the _archive_region_map.
|
||||
inline bool G1ArchiveAllocator::in_archive_range(oop object) {
|
||||
// This is the out-of-line part of is_archive_object test, done separately
|
||||
// Check if an object is in a closed archive region using the _archive_region_map.
|
||||
inline bool G1ArchiveAllocator::in_closed_archive_range(oop object) {
|
||||
// This is the out-of-line part of is_closed_archive_object test, done separately
|
||||
// to avoid additional performance impact when the check is not enabled.
|
||||
return _archive_region_map.get_by_address((HeapWord*)object);
|
||||
return _closed_archive_region_map.get_by_address((HeapWord*)object);
|
||||
}
|
||||
|
||||
// Check if archive object checking is enabled, to avoid calling in_archive_range
|
||||
inline bool G1ArchiveAllocator::in_open_archive_range(oop object) {
|
||||
return _open_archive_region_map.get_by_address((HeapWord*)object);
|
||||
}
|
||||
|
||||
// Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range
|
||||
// unnecessarily.
|
||||
inline bool G1ArchiveAllocator::archive_check_enabled() {
|
||||
return _archive_check_enabled;
|
||||
}
|
||||
|
||||
inline bool G1ArchiveAllocator::is_closed_archive_object(oop object) {
|
||||
return (archive_check_enabled() && in_closed_archive_range(object));
|
||||
}
|
||||
|
||||
inline bool G1ArchiveAllocator::is_open_archive_object(oop object) {
|
||||
return (archive_check_enabled() && in_open_archive_range(object));
|
||||
}
|
||||
|
||||
inline bool G1ArchiveAllocator::is_archive_object(oop object) {
|
||||
return (archive_check_enabled() && in_archive_range(object));
|
||||
return (archive_check_enabled() && (in_closed_archive_range(object) ||
|
||||
in_open_archive_range(object)));
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1ALLOCATOR_HPP
|
||||
|
|
|
@ -614,10 +614,10 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::begin_archive_alloc_range() {
|
||||
void G1CollectedHeap::begin_archive_alloc_range(bool open) {
|
||||
assert_at_safepoint(true /* should_be_vm_thread */);
|
||||
if (_archive_allocator == NULL) {
|
||||
_archive_allocator = G1ArchiveAllocator::create_allocator(this);
|
||||
_archive_allocator = G1ArchiveAllocator::create_allocator(this, open);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,7 +661,9 @@ bool G1CollectedHeap::check_archive_addresses(MemRegion* ranges, size_t count) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
||||
bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges,
|
||||
size_t count,
|
||||
bool open) {
|
||||
assert(!is_init_completed(), "Expect to be called at JVM init time");
|
||||
assert(ranges != NULL, "MemRegion array NULL");
|
||||
assert(count != 0, "No MemRegions provided");
|
||||
|
@ -680,8 +682,8 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
|||
G1ArchiveAllocator::enable_archive_object_check();
|
||||
|
||||
// For each specified MemRegion range, allocate the corresponding G1
|
||||
// regions and mark them as archive regions. We expect the ranges in
|
||||
// ascending starting address order, without overlap.
|
||||
// regions and mark them as archive regions. We expect the ranges
|
||||
// in ascending starting address order, without overlap.
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
MemRegion curr_range = ranges[i];
|
||||
HeapWord* start_address = curr_range.start();
|
||||
|
@ -726,8 +728,8 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
|||
|
||||
}
|
||||
|
||||
// Mark each G1 region touched by the range as archive, add it to the old set,
|
||||
// and set the allocation context and top.
|
||||
// Mark each G1 region touched by the range as archive, add it to
|
||||
// the old set, and set the allocation context and top.
|
||||
HeapRegion* curr_region = _hrm.addr_to_region(start_address);
|
||||
HeapRegion* last_region = _hrm.addr_to_region(last_address);
|
||||
prev_last_region = last_region;
|
||||
|
@ -736,20 +738,30 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
|||
assert(curr_region->is_empty() && !curr_region->is_pinned(),
|
||||
"Region already in use (index %u)", curr_region->hrm_index());
|
||||
curr_region->set_allocation_context(AllocationContext::system());
|
||||
curr_region->set_archive();
|
||||
if (open) {
|
||||
curr_region->set_open_archive();
|
||||
} else {
|
||||
curr_region->set_closed_archive();
|
||||
}
|
||||
_hr_printer.alloc(curr_region);
|
||||
_old_set.add(curr_region);
|
||||
HeapWord* top;
|
||||
HeapRegion* next_region;
|
||||
if (curr_region != last_region) {
|
||||
curr_region->set_top(curr_region->end());
|
||||
curr_region = _hrm.next_region_in_heap(curr_region);
|
||||
top = curr_region->end();
|
||||
next_region = _hrm.next_region_in_heap(curr_region);
|
||||
} else {
|
||||
curr_region->set_top(last_address + 1);
|
||||
curr_region = NULL;
|
||||
top = last_address + 1;
|
||||
next_region = NULL;
|
||||
}
|
||||
curr_region->set_top(top);
|
||||
curr_region->set_first_dead(top);
|
||||
curr_region->set_end_of_live(top);
|
||||
curr_region = next_region;
|
||||
}
|
||||
|
||||
// Notify mark-sweep of the archive range.
|
||||
G1ArchiveAllocator::set_range_archive(curr_range, true);
|
||||
// Notify mark-sweep of the archive
|
||||
G1ArchiveAllocator::set_range_archive(curr_range, open);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -5223,12 +5235,8 @@ public:
|
|||
// We ignore humongous regions. We left the humongous set unchanged.
|
||||
} else {
|
||||
assert(r->is_young() || r->is_free() || r->is_old(), "invariant");
|
||||
// We now consider all regions old, so register as such. Leave
|
||||
// archive regions set that way, however, while still adding
|
||||
// them to the old set.
|
||||
if (!r->is_archive()) {
|
||||
r->set_old();
|
||||
}
|
||||
// We now move all (non-humongous, non-old) regions to old gen, and register them as such.
|
||||
r->move_to_old();
|
||||
_old_set->add(r);
|
||||
}
|
||||
_total_used += r->used();
|
||||
|
|
|
@ -681,7 +681,7 @@ public:
|
|||
// VM thread at safepoints, without the heap lock held. They can be used
|
||||
// to create and archive a set of heap regions which can be mapped at the
|
||||
// same fixed addresses in a subsequent JVM invocation.
|
||||
void begin_archive_alloc_range();
|
||||
void begin_archive_alloc_range(bool open = false);
|
||||
|
||||
// Check if the requested size would be too large for an archive allocation.
|
||||
bool is_archive_alloc_too_large(size_t word_size);
|
||||
|
@ -706,7 +706,7 @@ public:
|
|||
// Commit the appropriate G1 regions containing the specified MemRegions
|
||||
// and mark them as 'archive' regions. The regions in the array must be
|
||||
// non-overlapping and in order of ascending address.
|
||||
bool alloc_archive_regions(MemRegion* range, size_t count);
|
||||
bool alloc_archive_regions(MemRegion* range, size_t count, bool open);
|
||||
|
||||
// Insert any required filler objects in the G1 regions around the specified
|
||||
// ranges to make the regions parseable. This must be called after
|
||||
|
|
|
@ -1134,13 +1134,10 @@ public:
|
|||
const uint humongous_regions_removed() { return _humongous_regions_removed; }
|
||||
|
||||
bool doHeapRegion(HeapRegion *hr) {
|
||||
if (hr->is_archive()) {
|
||||
return false;
|
||||
}
|
||||
_g1->reset_gc_time_stamps(hr);
|
||||
hr->note_end_of_marking();
|
||||
|
||||
if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) {
|
||||
if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young() && !hr->is_archive()) {
|
||||
_freed_bytes += hr->used();
|
||||
hr->set_containing_set(NULL);
|
||||
if (hr->is_humongous()) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, 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
|
||||
|
@ -37,7 +37,9 @@ class G1HeapRegionTraceType : AllStatic {
|
|||
StartsHumongous,
|
||||
ContinuesHumongous,
|
||||
Old,
|
||||
Archive,
|
||||
Pinned,
|
||||
OpenArchive,
|
||||
ClosedArchive,
|
||||
G1HeapRegionTypeEndSentinel
|
||||
};
|
||||
|
||||
|
@ -49,7 +51,9 @@ class G1HeapRegionTraceType : AllStatic {
|
|||
case StartsHumongous: return "Starts Humongous";
|
||||
case ContinuesHumongous: return "Continues Humongous";
|
||||
case Old: return "Old";
|
||||
case Archive: return "Archive";
|
||||
case Pinned: return "Pinned";
|
||||
case OpenArchive: return "OpenArchive";
|
||||
case ClosedArchive: return "ClosedArchive";
|
||||
default: ShouldNotReachHere(); return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,30 +234,63 @@ public:
|
|||
};
|
||||
|
||||
class VerifyArchiveOopClosure: public OopClosure {
|
||||
HeapRegion* _hr;
|
||||
public:
|
||||
VerifyArchiveOopClosure(HeapRegion *hr) { }
|
||||
VerifyArchiveOopClosure(HeapRegion *hr)
|
||||
: _hr(hr) { }
|
||||
void do_oop(narrowOop *p) { do_oop_work(p); }
|
||||
void do_oop( oop *p) { do_oop_work(p); }
|
||||
|
||||
template <class T> void do_oop_work(T *p) {
|
||||
oop obj = oopDesc::load_decode_heap_oop(p);
|
||||
|
||||
if (_hr->is_open_archive()) {
|
||||
guarantee(obj == NULL || G1ArchiveAllocator::is_archive_object(obj),
|
||||
"Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
|
||||
p2i(p), p2i(obj));
|
||||
} else {
|
||||
assert(_hr->is_closed_archive(), "should be closed archive region");
|
||||
guarantee(obj == NULL || G1ArchiveAllocator::is_closed_archive_object(obj),
|
||||
"Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
|
||||
p2i(p), p2i(obj));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerifyArchiveRegionClosure: public ObjectClosure {
|
||||
class VerifyObjectInArchiveRegionClosure: public ObjectClosure {
|
||||
HeapRegion* _hr;
|
||||
public:
|
||||
VerifyArchiveRegionClosure(HeapRegion *hr) { }
|
||||
VerifyObjectInArchiveRegionClosure(HeapRegion *hr, bool verbose)
|
||||
: _hr(hr) { }
|
||||
// Verify that all object pointers are to archive regions.
|
||||
void do_object(oop o) {
|
||||
VerifyArchiveOopClosure checkOop(NULL);
|
||||
VerifyArchiveOopClosure checkOop(_hr);
|
||||
assert(o != NULL, "Should not be here for NULL oops");
|
||||
o->oop_iterate_no_header(&checkOop);
|
||||
}
|
||||
};
|
||||
|
||||
// Should be only used at CDS dump time
|
||||
class VerifyArchivePointerRegionClosure: public HeapRegionClosure {
|
||||
private:
|
||||
G1CollectedHeap* _g1h;
|
||||
public:
|
||||
VerifyArchivePointerRegionClosure(G1CollectedHeap* g1h) { }
|
||||
virtual bool doHeapRegion(HeapRegion* r) {
|
||||
if (r->is_archive()) {
|
||||
VerifyObjectInArchiveRegionClosure verify_oop_pointers(r, false);
|
||||
r->object_iterate(&verify_oop_pointers);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void G1HeapVerifier::verify_archive_regions() {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
VerifyArchivePointerRegionClosure cl(NULL);
|
||||
g1h->heap_region_iterate(&cl);
|
||||
}
|
||||
|
||||
class VerifyRegionClosure: public HeapRegionClosure {
|
||||
private:
|
||||
bool _par;
|
||||
|
@ -279,12 +312,15 @@ public:
|
|||
bool doHeapRegion(HeapRegion* r) {
|
||||
// For archive regions, verify there are no heap pointers to
|
||||
// non-pinned regions. For all others, verify liveness info.
|
||||
if (r->is_archive()) {
|
||||
VerifyArchiveRegionClosure verify_oop_pointers(r);
|
||||
if (r->is_closed_archive()) {
|
||||
VerifyObjectInArchiveRegionClosure verify_oop_pointers(r, false);
|
||||
r->object_iterate(&verify_oop_pointers);
|
||||
return true;
|
||||
}
|
||||
if (!r->is_continues_humongous()) {
|
||||
} else if (r->is_open_archive()) {
|
||||
VerifyObjsInRegionClosure verify_open_archive_oop(r, _vo);
|
||||
r->object_iterate(&verify_open_archive_oop);
|
||||
return true;
|
||||
} else if (!r->is_continues_humongous()) {
|
||||
bool failures = false;
|
||||
r->verify(_vo, &failures);
|
||||
if (failures) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, 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
|
||||
|
@ -109,6 +109,8 @@ public:
|
|||
void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
|
||||
void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
|
||||
void verify_dirty_young_regions() PRODUCT_RETURN;
|
||||
|
||||
static void verify_archive_regions();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1HEAPVERIFIER_HPP
|
||||
|
|
|
@ -222,7 +222,7 @@ class G1AdjustPointersClosure: public HeapRegionClosure {
|
|||
// point all the oops to the new location
|
||||
MarkSweep::adjust_pointers(obj);
|
||||
}
|
||||
} else if (!r->is_pinned()) {
|
||||
} else if (!r->is_closed_archive()) {
|
||||
// This really ought to be "as_CompactibleSpace"...
|
||||
r->adjust_pointers();
|
||||
}
|
||||
|
|
|
@ -185,14 +185,25 @@ void HeapRegion::set_survivor() {
|
|||
_type.set_survivor();
|
||||
}
|
||||
|
||||
void HeapRegion::move_to_old() {
|
||||
if (_type.relabel_as_old()) {
|
||||
report_region_type_change(G1HeapRegionTraceType::Old);
|
||||
}
|
||||
}
|
||||
|
||||
void HeapRegion::set_old() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Old);
|
||||
_type.set_old();
|
||||
}
|
||||
|
||||
void HeapRegion::set_archive() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Archive);
|
||||
_type.set_archive();
|
||||
void HeapRegion::set_open_archive() {
|
||||
report_region_type_change(G1HeapRegionTraceType::OpenArchive);
|
||||
_type.set_open_archive();
|
||||
}
|
||||
|
||||
void HeapRegion::set_closed_archive() {
|
||||
report_region_type_change(G1HeapRegionTraceType::ClosedArchive);
|
||||
_type.set_closed_archive();
|
||||
}
|
||||
|
||||
void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||
|
|
|
@ -434,6 +434,8 @@ class HeapRegion: public G1ContiguousSpace {
|
|||
// should not be marked during mark/sweep. This allows the address
|
||||
// space to be shared by JVM instances.
|
||||
bool is_archive() const { return _type.is_archive(); }
|
||||
bool is_open_archive() const { return _type.is_open_archive(); }
|
||||
bool is_closed_archive() const { return _type.is_closed_archive(); }
|
||||
|
||||
// For a humongous region, region in which it starts.
|
||||
HeapRegion* humongous_start_region() const {
|
||||
|
@ -618,9 +620,11 @@ class HeapRegion: public G1ContiguousSpace {
|
|||
void set_eden_pre_gc();
|
||||
void set_survivor();
|
||||
|
||||
void move_to_old();
|
||||
void set_old();
|
||||
|
||||
void set_archive();
|
||||
void set_open_archive();
|
||||
void set_closed_archive();
|
||||
|
||||
// Determine if an object has been allocated since the last
|
||||
// mark performed by the collector. This returns true iff the object
|
||||
|
|
|
@ -117,7 +117,8 @@ inline bool HeapRegion::is_obj_dead_with_size(const oop obj, const G1CMBitMap* c
|
|||
HeapWord* addr = (HeapWord*) obj;
|
||||
|
||||
assert(addr < top(), "must be");
|
||||
assert(!is_archive(), "Archive regions should not have references into interesting regions.");
|
||||
assert(!is_closed_archive(),
|
||||
"Closed archive regions should not have references into other regions");
|
||||
assert(!is_humongous(), "Humongous objects not handled here");
|
||||
bool obj_is_dead = is_obj_dead(obj, prev_bitmap);
|
||||
|
||||
|
@ -162,7 +163,9 @@ inline size_t HeapRegion::block_size_using_bitmap(const HeapWord* addr, const G1
|
|||
|
||||
inline bool HeapRegion::is_obj_dead(const oop obj, const G1CMBitMap* const prev_bitmap) const {
|
||||
assert(is_in_reserved(obj), "Object " PTR_FORMAT " must be in region", p2i(obj));
|
||||
return !obj_allocated_since_prev_marking(obj) && !prev_bitmap->is_marked((HeapWord*)obj);
|
||||
return !obj_allocated_since_prev_marking(obj) &&
|
||||
!prev_bitmap->is_marked((HeapWord*)obj) &&
|
||||
!is_open_archive();
|
||||
}
|
||||
|
||||
inline size_t HeapRegion::block_size(const HeapWord *addr) const {
|
||||
|
|
|
@ -34,7 +34,8 @@ bool HeapRegionType::is_valid(Tag tag) {
|
|||
case StartsHumongousTag:
|
||||
case ContinuesHumongousTag:
|
||||
case OldTag:
|
||||
case ArchiveTag:
|
||||
case OpenArchiveTag:
|
||||
case ClosedArchiveTag:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -50,7 +51,8 @@ const char* HeapRegionType::get_str() const {
|
|||
case StartsHumongousTag: return "HUMS";
|
||||
case ContinuesHumongousTag: return "HUMC";
|
||||
case OldTag: return "OLD";
|
||||
case ArchiveTag: return "ARC";
|
||||
case OpenArchiveTag: return "OARC";
|
||||
case ClosedArchiveTag: return "CARC";
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL; // keep some compilers happy
|
||||
|
@ -66,7 +68,8 @@ const char* HeapRegionType::get_short_str() const {
|
|||
case StartsHumongousTag: return "HS";
|
||||
case ContinuesHumongousTag: return "HC";
|
||||
case OldTag: return "O";
|
||||
case ArchiveTag: return "A";
|
||||
case OpenArchiveTag: return "OA";
|
||||
case ClosedArchiveTag: return "CA";
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL; // keep some compilers happy
|
||||
|
@ -82,7 +85,8 @@ G1HeapRegionTraceType::Type HeapRegionType::get_trace_type() {
|
|||
case StartsHumongousTag: return G1HeapRegionTraceType::StartsHumongous;
|
||||
case ContinuesHumongousTag: return G1HeapRegionTraceType::ContinuesHumongous;
|
||||
case OldTag: return G1HeapRegionTraceType::Old;
|
||||
case ArchiveTag: return G1HeapRegionTraceType::Archive;
|
||||
case OpenArchiveTag: return G1HeapRegionTraceType::OpenArchive;
|
||||
case ClosedArchiveTag: return G1HeapRegionTraceType::ClosedArchive;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return G1HeapRegionTraceType::Free; // keep some compilers happy
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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
|
||||
|
@ -43,20 +43,23 @@ private:
|
|||
// future, we'll have to increase the size of the latter and hence
|
||||
// decrease the size of the former.
|
||||
//
|
||||
// 0000 0 [ 0] Free
|
||||
// 00000 0 [ 0] Free
|
||||
//
|
||||
// 0001 0 [ 2] Young Mask
|
||||
// 0001 0 [ 2] Eden
|
||||
// 0001 1 [ 3] Survivor
|
||||
// 00001 0 [ 2] Young Mask
|
||||
// 00001 0 [ 2] Eden
|
||||
// 00001 1 [ 3] Survivor
|
||||
//
|
||||
// 0010 0 [ 4] Humongous Mask
|
||||
// 0100 0 [ 8] Pinned Mask
|
||||
// 0110 0 [12] Starts Humongous
|
||||
// 0110 1 [13] Continues Humongous
|
||||
// 00010 0 [ 4] Humongous Mask
|
||||
// 00100 0 [ 8] Pinned Mask
|
||||
// 00110 0 [12] Starts Humongous
|
||||
// 00110 1 [13] Continues Humongous
|
||||
//
|
||||
// 1000 0 [16] Old Mask
|
||||
// 01000 0 [16] Old Mask
|
||||
//
|
||||
// 10000 0 [32] Archive Mask
|
||||
// 11100 0 [56] Open Archive
|
||||
// 11100 1 [57] Closed Archive
|
||||
//
|
||||
// 1100 0 [24] Archive
|
||||
typedef enum {
|
||||
FreeTag = 0,
|
||||
|
||||
|
@ -72,7 +75,18 @@ private:
|
|||
OldMask = 16,
|
||||
OldTag = OldMask,
|
||||
|
||||
ArchiveTag = PinnedMask | OldMask
|
||||
// Archive regions are regions with immutable content (i.e. not reclaimed, and
|
||||
// not allocated into during regular operation). They differ in the kind of references
|
||||
// allowed for the contained objects:
|
||||
// - Closed archive regions form a separate self-contained (closed) object graph
|
||||
// within the set of all of these regions. No references outside of closed
|
||||
// archive regions are allowed.
|
||||
// - Open archive regions have no restrictions on the references of their objects.
|
||||
// Objects within these regions are allowed to have references to objects
|
||||
// contained in any other kind of regions.
|
||||
ArchiveMask = 32,
|
||||
OpenArchiveTag = ArchiveMask | PinnedMask | OldMask,
|
||||
ClosedArchiveTag = ArchiveMask | PinnedMask | OldMask + 1
|
||||
} Tag;
|
||||
|
||||
volatile Tag _tag;
|
||||
|
@ -115,7 +129,9 @@ public:
|
|||
bool is_starts_humongous() const { return get() == StartsHumongousTag; }
|
||||
bool is_continues_humongous() const { return get() == ContinuesHumongousTag; }
|
||||
|
||||
bool is_archive() const { return get() == ArchiveTag; }
|
||||
bool is_archive() const { return (get() & ArchiveMask) != 0; }
|
||||
bool is_open_archive() const { return get() == OpenArchiveTag; }
|
||||
bool is_closed_archive() const { return get() == ClosedArchiveTag; }
|
||||
|
||||
// is_old regions may or may not also be pinned
|
||||
bool is_old() const { return (get() & OldMask) != 0; }
|
||||
|
@ -138,7 +154,27 @@ public:
|
|||
|
||||
void set_old() { set(OldTag); }
|
||||
|
||||
void set_archive() { set_from(ArchiveTag, FreeTag); }
|
||||
// Change the current region type to be of an old region type if not already done so.
|
||||
// Returns whether the region type has been changed or not.
|
||||
bool relabel_as_old() {
|
||||
//assert(!is_free(), "Should not try to move Free region");
|
||||
assert(!is_humongous(), "Should not try to move Humongous region");
|
||||
if (is_old()) {
|
||||
return false;
|
||||
}
|
||||
if (is_eden()) {
|
||||
set_from(OldTag, EdenTag);
|
||||
return true;
|
||||
} else if (is_free()) {
|
||||
set_from(OldTag, FreeTag);
|
||||
return true;
|
||||
} else {
|
||||
set_from(OldTag, SurvTag);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void set_open_archive() { set_from(OpenArchiveTag, FreeTag); }
|
||||
void set_closed_archive() { set_from(ClosedArchiveTag, FreeTag); }
|
||||
|
||||
// Misc
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ template <class T> inline void MarkSweep::mark_and_push(T* p) {
|
|||
if (!oopDesc::is_null(heap_oop)) {
|
||||
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
|
||||
if (!obj->mark()->is_marked() &&
|
||||
!is_archive_object(obj)) {
|
||||
!is_closed_archive_object(obj)) {
|
||||
mark_object(obj);
|
||||
_marking_stack.push(obj);
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ template <class T> inline void MarkSweep::follow_root(T* p) {
|
|||
if (!oopDesc::is_null(heap_oop)) {
|
||||
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
|
||||
if (!obj->mark()->is_marked() &&
|
||||
!is_archive_object(obj)) {
|
||||
!is_closed_archive_object(obj)) {
|
||||
mark_object(obj);
|
||||
follow_object(obj);
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ void MarkSweep::restore_marks() {
|
|||
|
||||
MarkSweep::IsAliveClosure MarkSweep::is_alive;
|
||||
|
||||
bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked() || is_archive_object(p); }
|
||||
bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked() || is_closed_archive_object(p); }
|
||||
|
||||
MarkSweep::KeepAliveClosure MarkSweep::keep_alive;
|
||||
|
||||
|
|
|
@ -134,6 +134,8 @@ class MarkSweep : AllStatic {
|
|||
static void set_ref_processor(ReferenceProcessor* rp);
|
||||
|
||||
// Archive Object handling
|
||||
static inline bool is_closed_archive_object(oop object);
|
||||
static inline bool is_open_archive_object(oop object);
|
||||
static inline bool is_archive_object(oop object);
|
||||
|
||||
static STWGCTimer* gc_timer() { return _gc_timer; }
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define SHARE_VM_GC_SERIAL_MARKSWEEP_INLINE_HPP
|
||||
|
||||
#include "gc/serial/markSweep.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/markOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
|
@ -33,6 +34,22 @@
|
|||
#include "gc/g1/g1Allocator.inline.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
inline bool MarkSweep::is_closed_archive_object(oop object) {
|
||||
#if INCLUDE_ALL_GCS
|
||||
return G1ArchiveAllocator::is_closed_archive_object(object);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool MarkSweep::is_open_archive_object(oop object) {
|
||||
#if INCLUDE_ALL_GCS
|
||||
return G1ArchiveAllocator::is_open_archive_object(object);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool MarkSweep::is_archive_object(oop object) {
|
||||
#if INCLUDE_ALL_GCS
|
||||
return G1ArchiveAllocator::is_archive_object(object);
|
||||
|
@ -52,14 +69,24 @@ template <class T> inline void MarkSweep::adjust_pointer(T* p) {
|
|||
assert(Universe::heap()->is_in(obj), "should be in heap");
|
||||
|
||||
oop new_obj = oop(obj->mark()->decode_pointer());
|
||||
|
||||
assert(is_archive_object(obj) || // no forwarding of archive objects
|
||||
new_obj != NULL || // is forwarding ptr?
|
||||
obj->mark() == markOopDesc::prototype() || // not gc marked?
|
||||
(UseBiasedLocking && obj->mark()->has_bias_pattern()),
|
||||
// not gc marked?
|
||||
"should be forwarded");
|
||||
|
||||
#ifndef PRODUCT
|
||||
// open_archive objects are marked by GC. Their mark should
|
||||
// not have forwarding ptr.
|
||||
if (is_open_archive_object(obj)) {
|
||||
assert(new_obj == NULL, "archive heap object has forwarding ptr");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (new_obj != NULL) {
|
||||
if (!is_archive_object(obj)) {
|
||||
if (!is_closed_archive_object(obj)) {
|
||||
assert(Universe::heap()->is_in_reserved(new_obj),
|
||||
"should be in object space");
|
||||
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
|
@ -447,6 +447,9 @@ public:
|
|||
// Return a size with adjustments as required of the space.
|
||||
virtual size_t adjust_object_size_v(size_t size) const { return size; }
|
||||
|
||||
void set_first_dead(HeapWord* value) { _first_dead = value; }
|
||||
void set_end_of_live(HeapWord* value) { _end_of_live = value; }
|
||||
|
||||
protected:
|
||||
// Used during compaction.
|
||||
HeapWord* _first_dead;
|
||||
|
|
|
@ -351,7 +351,8 @@ bool FileMapInfo::init_from_file(int fd) {
|
|||
size_t len = lseek(fd, 0, SEEK_END);
|
||||
struct FileMapInfo::FileMapHeader::space_info* si =
|
||||
&_header->_space[MetaspaceShared::last_valid_region];
|
||||
if (si->_file_offset >= len || len - si->_file_offset < si->_used) {
|
||||
// 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.");
|
||||
return false;
|
||||
}
|
||||
|
@ -443,7 +444,7 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
|
|||
} else {
|
||||
si->_file_offset = _file_offset;
|
||||
}
|
||||
if (MetaspaceShared::is_string_region(region)) {
|
||||
if (MetaspaceShared::is_heap_region(region)) {
|
||||
assert((base - (char*)Universe::narrow_oop_base()) % HeapWordSize == 0, "Sanity");
|
||||
if (base != NULL) {
|
||||
si->_addr._offset = (intx)oopDesc::encode_heap_oop_not_null((oop)base);
|
||||
|
@ -460,76 +461,66 @@ void FileMapInfo::write_region(int region, char* base, size_t size,
|
|||
write_bytes_aligned(base, (int)size);
|
||||
}
|
||||
|
||||
// Write the string space. The string space contains one or multiple GC(G1) regions.
|
||||
// When the total string space size is smaller than one GC region of the dump time,
|
||||
// only one string region is used for shared strings.
|
||||
// Write out the given archive heap memory regions. GC code combines multiple
|
||||
// consecutive archive GC regions into one MemRegion whenever possible and
|
||||
// produces the 'heap_mem' array.
|
||||
//
|
||||
// If the total string space size is bigger than one GC region, there would be more
|
||||
// than one GC regions allocated for shared strings. The first/bottom GC region might
|
||||
// be a partial GC region with the empty portion at the higher address within that region.
|
||||
// The non-empty portion of the first region is written into the archive as one string
|
||||
// region. The rest are consecutive full GC regions if they exist, which can be written
|
||||
// out in one chunk as another string region.
|
||||
// If the archive heap memory size is smaller than a single dump time GC region
|
||||
// size, there is only one MemRegion in the array.
|
||||
//
|
||||
// Here's the mapping from (GrowableArray<MemRegion> *regions) -> (metaspace string regions).
|
||||
// + We have 1 or more heap regions: r0, r1, r2 ..... rn
|
||||
// + We have 2 metaspace string regions: s0 and s1
|
||||
// If the archive heap memory size is bigger than one dump time GC region size,
|
||||
// the 'heap_mem' array may contain more than one consolidated MemRegions. When
|
||||
// the first/bottom archive GC region is a partial GC region (with the empty
|
||||
// portion at the higher address within the region), one MemRegion is used for
|
||||
// the bottom partial archive GC region. The rest of the consecutive archive
|
||||
// GC regions are combined into another MemRegion.
|
||||
//
|
||||
// If there's a single heap region (r0), then s0 == r0, and s1 is empty.
|
||||
// Here's the mapping from (archive heap GC regions) -> (GrowableArray<MemRegion> *regions).
|
||||
// + We have 1 or more archive heap regions: ah0, ah1, ah2 ..... ahn
|
||||
// + We have 1 or 2 consolidated heap memory regions: r0 and r1
|
||||
//
|
||||
// If there's a single archive GC region (ah0), then r0 == ah0, and r1 is empty.
|
||||
// Otherwise:
|
||||
//
|
||||
// "X" represented space that's occupied by heap objects.
|
||||
// "_" represented unused spaced in the heap region.
|
||||
//
|
||||
//
|
||||
// |r0 | r1 | r2 | ...... | rn |
|
||||
// |ah0 | ah1 | ah2| ...... | ahn |
|
||||
// |XXXXXX|__ |XXXXX|XXXX|XXXXXXXX|XXXX|
|
||||
// |<-s0->| |<- s1 ----------------->|
|
||||
// |<-r0->| |<- r1 ----------------->|
|
||||
// ^^^
|
||||
// |
|
||||
// +-- unmapped space
|
||||
void FileMapInfo::write_string_regions(GrowableArray<MemRegion> *regions,
|
||||
char** st0_start, char** st0_top, char** st0_end,
|
||||
char** st1_start, char** st1_top, char** st1_end) {
|
||||
*st0_start = *st0_top = *st0_end = NULL;
|
||||
*st1_start = *st1_top = *st1_end = NULL;
|
||||
// +-- gap
|
||||
size_t FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> *heap_mem,
|
||||
int first_region_id, int max_num_regions) {
|
||||
assert(max_num_regions <= 2, "Only support maximum 2 memory regions");
|
||||
|
||||
assert(MetaspaceShared::max_strings == 2, "this loop doesn't work for any other value");
|
||||
for (int i = MetaspaceShared::first_string;
|
||||
i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
|
||||
int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
|
||||
if(arr_len > max_num_regions) {
|
||||
fail_stop("Unable to write archive heap memory regions: "
|
||||
"number of memory regions exceeds maximum due to fragmentation");
|
||||
}
|
||||
|
||||
size_t total_size = 0;
|
||||
for (int i = first_region_id, arr_idx = 0;
|
||||
i < first_region_id + max_num_regions;
|
||||
i++, arr_idx++) {
|
||||
char* start = NULL;
|
||||
size_t size = 0;
|
||||
int len = regions->length();
|
||||
if (len > 0) {
|
||||
if (i == MetaspaceShared::first_string) {
|
||||
MemRegion first = regions->first();
|
||||
start = (char*)first.start();
|
||||
size = first.byte_size();
|
||||
*st0_start = start;
|
||||
*st0_top = start + size;
|
||||
if (len > 1) {
|
||||
*st0_end = (char*)regions->at(1).start();
|
||||
} else {
|
||||
*st0_end = start + size;
|
||||
if (arr_idx < arr_len) {
|
||||
start = (char*)heap_mem->at(arr_idx).start();
|
||||
size = heap_mem->at(arr_idx).byte_size();
|
||||
total_size += size;
|
||||
}
|
||||
} else {
|
||||
assert(i == MetaspaceShared::first_string + 1, "must be");
|
||||
if (len > 1) {
|
||||
start = (char*)regions->at(1).start();
|
||||
size = (char*)regions->at(len - 1).end() - start;
|
||||
*st1_start = start;
|
||||
*st1_top = start + size;
|
||||
*st1_end = start + size;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_info(cds)("String region %d " INTPTR_FORMAT " - " INTPTR_FORMAT " = " SIZE_FORMAT_W(8) " bytes",
|
||||
|
||||
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);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
|
||||
// Dump bytes to file -- at the current file position.
|
||||
|
||||
void FileMapInfo::write_bytes(const void* buffer, int nbytes) {
|
||||
|
@ -641,11 +632,11 @@ ReservedSpace FileMapInfo::reserve_shared_memory() {
|
|||
}
|
||||
|
||||
// Memory map a region in the address space.
|
||||
static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
|
||||
"String1", "String2", "OptionalData" };
|
||||
static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
|
||||
"String1", "String2", "OpenArchive1", "OpenArchive2" };
|
||||
|
||||
char* FileMapInfo::map_region(int i) {
|
||||
assert(!MetaspaceShared::is_string_region(i), "sanity");
|
||||
assert(!MetaspaceShared::is_heap_region(i), "sanity");
|
||||
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
|
||||
size_t used = si->_used;
|
||||
size_t alignment = os::vm_allocation_granularity();
|
||||
|
@ -675,101 +666,144 @@ char* FileMapInfo::map_region(int i) {
|
|||
}
|
||||
|
||||
static MemRegion *string_ranges = NULL;
|
||||
static int num_ranges = 0;
|
||||
bool FileMapInfo::map_string_regions() {
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (UseG1GC && UseCompressedOops && UseCompressedClassPointers) {
|
||||
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
|
||||
//
|
||||
// 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 open archive heap objects are mapped below the shared strings in
|
||||
// the runtime java heap. The mapped open archive heap data only contain
|
||||
// references to the shared strings and open archive objects initially.
|
||||
// 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()) {
|
||||
// Check that all the narrow oop and klass encodings match the archive
|
||||
if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
|
||||
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) {
|
||||
log_info(cds)("Shared string data from the CDS archive is being ignored. "
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
string_ranges = new MemRegion[MetaspaceShared::max_strings];
|
||||
struct FileMapInfo::FileMapHeader::space_info* si;
|
||||
// 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();
|
||||
|
||||
for (int i = MetaspaceShared::first_string;
|
||||
i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
|
||||
log_info(cds)("Cached heap data from the CDS archive is being ignored. UseG1GC, "
|
||||
"UseCompressedOops and UseCompressedClassPointers are required.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringTable::shared_string_mapped()) {
|
||||
assert(string_ranges == NULL && num_string_ranges == 0, "sanity");
|
||||
}
|
||||
|
||||
if (!MetaspaceShared::open_archive_heap_region_mapped()) {
|
||||
assert(open_archive_heap_ranges == NULL && num_open_archive_heap_ranges == 0, "sanity");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
int region_num = 0;
|
||||
|
||||
for (int i = first;
|
||||
i < first + max; i++) {
|
||||
si = &_header->_space[i];
|
||||
size_t used = si->_used;
|
||||
if (used > 0) {
|
||||
size_t size = used;
|
||||
char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
|
||||
(narrowOop)si->_addr._offset));
|
||||
string_ranges[num_ranges] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
|
||||
num_ranges ++;
|
||||
regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
|
||||
region_num ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_ranges == 0) {
|
||||
StringTable::ignore_shared_strings(true);
|
||||
return true; // no shared string data
|
||||
if (region_num == 0) {
|
||||
return false; // no archived java heap data
|
||||
}
|
||||
|
||||
// Check that ranges are within the java heap
|
||||
if (!G1CollectedHeap::heap()->check_archive_addresses(string_ranges, num_ranges)) {
|
||||
fail_continue("Unable to allocate shared string space: range is not "
|
||||
"within 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.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocate from java heap
|
||||
if (!G1CollectedHeap::heap()->alloc_archive_regions(string_ranges, num_ranges)) {
|
||||
fail_continue("Unable to allocate shared string space: range is "
|
||||
"already in use.");
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the string data. No need to call MemTracker::record_virtual_memory_type()
|
||||
// for mapped string regions as they are part of the reserved java heap, which
|
||||
// is already recorded.
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
si = &_header->_space[MetaspaceShared::first_string + i];
|
||||
char* addr = (char*)string_ranges[i].start();
|
||||
// Map the archived heap data. No need to call MemTracker::record_virtual_memory_type()
|
||||
// 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];
|
||||
char* addr = (char*)regions[i].start();
|
||||
char* base = os::map_memory(_fd, _full_path, si->_file_offset,
|
||||
addr, string_ranges[i].byte_size(), si->_read_only,
|
||||
addr, regions[i].byte_size(), si->_read_only,
|
||||
si->_allow_exec);
|
||||
if (base == NULL || base != addr) {
|
||||
// dealloc the string regions from java heap
|
||||
dealloc_string_regions();
|
||||
fail_continue("Unable to map shared string space at required address.");
|
||||
// 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.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!verify_string_regions()) {
|
||||
// dealloc the string regions from java heap
|
||||
dealloc_string_regions();
|
||||
fail_continue("Shared string regions are corrupt");
|
||||
if (!verify_mapped_heap_regions(first, region_num)) {
|
||||
// dealloc the regions from java heap
|
||||
dealloc_archive_heap_regions(regions, region_num);
|
||||
log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
|
||||
return false;
|
||||
}
|
||||
|
||||
// the shared string data is mapped successfully
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (log_is_enabled(Info, cds) && _header->_space[MetaspaceShared::first_string]._used > 0) {
|
||||
log_info(cds)("Shared string data from the CDS archive is being ignored. UseG1GC, "
|
||||
"UseCompressedOops and UseCompressedClassPointers are required.");
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here, the shared string data is not mapped
|
||||
assert(string_ranges == NULL && num_ranges == 0, "sanity");
|
||||
StringTable::ignore_shared_strings(true);
|
||||
#endif
|
||||
// the shared heap data is mapped successfully
|
||||
*heap_mem = regions;
|
||||
*num = region_num;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileMapInfo::verify_string_regions() {
|
||||
for (int i = MetaspaceShared::first_string;
|
||||
i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
|
||||
bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
|
||||
for (int i = first;
|
||||
i <= first + num; i++) {
|
||||
if (!verify_region_checksum(i)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -777,17 +811,31 @@ bool FileMapInfo::verify_string_regions() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void FileMapInfo::fixup_string_regions() {
|
||||
#if INCLUDE_ALL_GCS
|
||||
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.
|
||||
if (num_ranges != 0) {
|
||||
if (num_string_ranges != 0) {
|
||||
assert(string_ranges != NULL, "Null string_ranges array with non-zero count");
|
||||
G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_ranges);
|
||||
G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_string_ranges);
|
||||
}
|
||||
|
||||
// do the same for mapped open archive heap regions
|
||||
if (num_open_archive_heap_ranges != 0) {
|
||||
assert(open_archive_heap_ranges != NULL, "NULL open_archive_heap_ranges array with non-zero count");
|
||||
G1CollectedHeap::heap()->fill_archive_regions(open_archive_heap_ranges,
|
||||
num_open_archive_heap_ranges);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// dealloc the archive regions from java heap
|
||||
void FileMapInfo::dealloc_archive_heap_regions(MemRegion* regions, int num) {
|
||||
if (num > 0) {
|
||||
assert(regions != NULL, "Null archive ranges array with non-zero count");
|
||||
G1CollectedHeap::heap()->dealloc_archive_regions(regions, num);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
bool FileMapInfo::verify_region_checksum(int i) {
|
||||
if (!VerifySharedSpaces) {
|
||||
return true;
|
||||
|
@ -798,8 +846,11 @@ bool FileMapInfo::verify_region_checksum(int i) {
|
|||
if (sz == 0) {
|
||||
return true; // no data
|
||||
}
|
||||
if (MetaspaceShared::is_string_region(i) && StringTable::shared_string_ignored()) {
|
||||
return true; // shared string data are not mapped
|
||||
if ((MetaspaceShared::is_string_region(i) &&
|
||||
!StringTable::shared_string_mapped()) ||
|
||||
(MetaspaceShared::is_open_archive_heap_region(i) &&
|
||||
!MetaspaceShared::open_archive_heap_region_mapped())) {
|
||||
return true; // archived heap data is not mapped
|
||||
}
|
||||
const char* buf = _header->region_addr(i);
|
||||
int crc = ClassLoader::crc32(0, buf, (jint)sz);
|
||||
|
@ -813,7 +864,7 @@ bool FileMapInfo::verify_region_checksum(int i) {
|
|||
// Unmap a memory region in the address space.
|
||||
|
||||
void FileMapInfo::unmap_region(int i) {
|
||||
assert(!MetaspaceShared::is_string_region(i), "sanity");
|
||||
assert(!MetaspaceShared::is_heap_region(i), "sanity");
|
||||
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
|
||||
size_t used = si->_used;
|
||||
size_t size = align_up(used, os::vm_allocation_granularity());
|
||||
|
@ -828,16 +879,6 @@ void FileMapInfo::unmap_region(int i) {
|
|||
}
|
||||
}
|
||||
|
||||
// dealloc the archived string region from java heap
|
||||
void FileMapInfo::dealloc_string_regions() {
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (num_ranges > 0) {
|
||||
assert(string_ranges != NULL, "Null string_ranges array with non-zero count");
|
||||
G1CollectedHeap::heap()->dealloc_archive_regions(string_ranges, num_ranges);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileMapInfo::assert_mark(bool check) {
|
||||
if (!check) {
|
||||
fail_stop("Mark mismatch while restoring from shared file.");
|
||||
|
@ -883,9 +924,9 @@ bool FileMapInfo::initialize() {
|
|||
}
|
||||
|
||||
char* FileMapInfo::FileMapHeader::region_addr(int idx) {
|
||||
if (MetaspaceShared::is_string_region(idx)) {
|
||||
return (char*)((void*)oopDesc::decode_heap_oop_not_null(
|
||||
(narrowOop)_space[idx]._addr._offset));
|
||||
if (MetaspaceShared::is_heap_region(idx)) {
|
||||
return _space[idx]._used > 0 ?
|
||||
(char*)((void*)oopDesc::decode_heap_oop_not_null((narrowOop)_space[idx]._addr._offset)) : NULL;
|
||||
} else {
|
||||
return _space[idx]._addr._base;
|
||||
}
|
||||
|
@ -965,15 +1006,15 @@ bool FileMapInfo::validate_header() {
|
|||
}
|
||||
|
||||
// The following method is provided to see whether a given pointer
|
||||
// falls in the mapped shared space.
|
||||
// falls in the mapped shared metadata space.
|
||||
// Param:
|
||||
// p, The given pointer
|
||||
// Return:
|
||||
// True if the p is within the mapped shared space, otherwise, false.
|
||||
bool FileMapInfo::is_in_shared_space(const void* p) {
|
||||
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
|
||||
for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
|
||||
char *base;
|
||||
if (MetaspaceShared::is_string_region(i) && _header->_space[i]._used == 0) {
|
||||
if (_header->_space[i]._used == 0) {
|
||||
continue;
|
||||
}
|
||||
base = _header->region_addr(i);
|
||||
|
@ -985,7 +1026,7 @@ bool FileMapInfo::is_in_shared_space(const void* p) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if a given address is within one of the shared regions ( ro, rw, mc or md)
|
||||
// Check if a given address is within one of the shared regions
|
||||
bool FileMapInfo::is_in_shared_region(const void* p, int idx) {
|
||||
assert(idx == MetaspaceShared::ro ||
|
||||
idx == MetaspaceShared::rw ||
|
||||
|
@ -1014,16 +1055,18 @@ 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_strings; i++) {
|
||||
for (int i = 0; i < MetaspaceShared::num_non_heap_spaces; i++) {
|
||||
char *addr = map_info->_header->region_addr(i);
|
||||
if (addr != NULL && !MetaspaceShared::is_string_region(i)) {
|
||||
if (addr != NULL && !MetaspaceShared::is_heap_region(i)) {
|
||||
map_info->unmap_region(i);
|
||||
map_info->_header->_space[i]._addr._base = NULL;
|
||||
}
|
||||
}
|
||||
// Dealloc the string regions only without unmapping. The string regions are part
|
||||
// Dealloc the archive heap regions only without unmapping. The regions are part
|
||||
// of the java heap. Unmapping of the heap regions are managed by GC.
|
||||
map_info->dealloc_string_regions();
|
||||
map_info->dealloc_archive_heap_regions(open_archive_heap_ranges,
|
||||
num_open_archive_heap_ranges);
|
||||
map_info->dealloc_archive_heap_regions(string_ranges, num_string_ranges);
|
||||
} else if (DumpSharedSpaces) {
|
||||
fail_stop("%s", msg);
|
||||
}
|
||||
|
|
|
@ -242,17 +242,14 @@ public:
|
|||
void write_header();
|
||||
void write_region(int region, char* base, size_t size,
|
||||
bool read_only, bool allow_exec);
|
||||
void write_string_regions(GrowableArray<MemRegion> *regions,
|
||||
char** s0_start, char** s0_top, char** s0_end,
|
||||
char** s1_start, char** s1_top, char** s1_end);
|
||||
size_t write_archive_heap_regions(GrowableArray<MemRegion> *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);
|
||||
char* map_region(int i);
|
||||
bool map_string_regions();
|
||||
bool verify_string_regions();
|
||||
void fixup_string_regions();
|
||||
void map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void unmap_region(int i);
|
||||
void dealloc_string_regions();
|
||||
bool verify_region_checksum(int i);
|
||||
void close();
|
||||
bool is_open() { return _file_open; }
|
||||
|
@ -294,6 +291,12 @@ public:
|
|||
static int get_number_of_share_classpaths() {
|
||||
return _classpath_entry_table_size;
|
||||
}
|
||||
|
||||
private:
|
||||
bool map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
|
||||
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;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_MEMORY_FILEMAP_HPP
|
||||
|
|
|
@ -3347,9 +3347,9 @@ void Metaspace::global_initialize() {
|
|||
// If UseCompressedClassPointers is set then allocate the metaspace area
|
||||
// above the heap and above the CDS area (if it exists).
|
||||
allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
|
||||
// Map the shared string space after compressed pointers
|
||||
// because it relies on compressed class pointers setting to work
|
||||
mapinfo->map_string_regions();
|
||||
// map_heap_regions() compares the current narrow oop and klass encodings
|
||||
// with the archived ones, so it must be done after all encodings are determined.
|
||||
mapinfo->map_heap_regions();
|
||||
}
|
||||
#endif // _LP64
|
||||
} else {
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1Allocator.inline.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#endif
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
@ -68,6 +73,7 @@ MetaspaceSharedStats MetaspaceShared::_stats;
|
|||
bool MetaspaceShared::_has_error_classes;
|
||||
bool MetaspaceShared::_archive_loading_failed = false;
|
||||
bool MetaspaceShared::_remapped_readwrite = false;
|
||||
bool MetaspaceShared::_open_archive_heap_region_mapped = false;
|
||||
address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
|
||||
size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
|
||||
size_t MetaspaceShared::_core_spaces_size = 0;
|
||||
|
@ -79,10 +85,12 @@ size_t MetaspaceShared::_core_spaces_size = 0;
|
|||
// md - misc data (the c++ vtables)
|
||||
// od - optional data (original class files)
|
||||
//
|
||||
// s0 - shared strings #0
|
||||
// s1 - shared strings #1 (may be empty)
|
||||
// s0 - shared strings(closed archive heap space) #0
|
||||
// s1 - shared strings(closed archive heap space) #1 (may be empty)
|
||||
// oa0 - open archive heap space #0
|
||||
// oa1 - open archive heap space #1 (may be empty)
|
||||
//
|
||||
// Except for the s0/s1 regions, the other 5 regions are linearly allocated, starting from
|
||||
// The mc, rw, ro, md and od regions are linearly allocated, starting from
|
||||
// SharedBaseAddress, in the order of mc->rw->ro->md->od. The size of these 5 regions
|
||||
// are page-aligned, and there's no gap between any consecutive regions.
|
||||
//
|
||||
|
@ -97,8 +105,8 @@ size_t MetaspaceShared::_core_spaces_size = 0;
|
|||
// [5] C++ vtables are copied into the md region.
|
||||
// [6] Original class files are copied into the od region.
|
||||
//
|
||||
// The s0/s1 regions are populated inside MetaspaceShared::dump_string_and_symbols. Their
|
||||
// layout is independent of the other 5 regions.
|
||||
// The s0/s1 and oa0/oa1 regions are populated inside MetaspaceShared::dump_java_heap_objects.
|
||||
// Their layout is independent of the other 5 regions.
|
||||
|
||||
class DumpRegion {
|
||||
private:
|
||||
|
@ -194,8 +202,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
|
||||
DumpRegion _s0_region("s0"), _s1_region("s1");
|
||||
size_t _total_string_region_size = 0, _total_open_archive_region_size = 0;
|
||||
|
||||
char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) {
|
||||
return _mc_region.allocate(num_bytes);
|
||||
|
@ -856,10 +865,14 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all, int md_all)
|
|||
class VM_PopulateDumpSharedSpace: public VM_Operation {
|
||||
private:
|
||||
GrowableArray<MemRegion> *_string_regions;
|
||||
GrowableArray<MemRegion> *_open_archive_heap_regions;
|
||||
|
||||
void dump_string_and_symbols();
|
||||
void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void dump_symbols();
|
||||
char* dump_read_only_tables();
|
||||
void print_region_stats();
|
||||
void print_heap_region_stats(GrowableArray<MemRegion> *heap_mem,
|
||||
const char *name, const size_t total_size);
|
||||
public:
|
||||
|
||||
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
|
||||
|
@ -1072,9 +1085,8 @@ public:
|
|||
}
|
||||
|
||||
// We must relocate the System::_well_known_klasses only after we have copied the
|
||||
// strings in during dump_string_and_symbols(): during the string copy, we operate on old
|
||||
// String objects which assert that their klass is the old
|
||||
// SystemDictionary::String_klass().
|
||||
// java objects in during dump_java_heap_objects(): during the object copy, we operate on
|
||||
// old objects which assert that their klass is the original klass.
|
||||
static void relocate_well_known_klasses() {
|
||||
{
|
||||
tty->print_cr("Relocating SystemDictionary::_well_known_klasses[] ... ");
|
||||
|
@ -1127,16 +1139,11 @@ void VM_PopulateDumpSharedSpace::write_region(FileMapInfo* mapinfo, int region_i
|
|||
mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), read_only, allow_exec);
|
||||
}
|
||||
|
||||
void VM_PopulateDumpSharedSpace::dump_string_and_symbols() {
|
||||
tty->print_cr("Dumping string and symbol tables ...");
|
||||
void VM_PopulateDumpSharedSpace::dump_symbols() {
|
||||
tty->print_cr("Dumping symbol table ...");
|
||||
|
||||
NOT_PRODUCT(SymbolTable::verify());
|
||||
NOT_PRODUCT(StringTable::verify());
|
||||
SymbolTable::write_to_archive();
|
||||
|
||||
// The string space has maximum two regions. See FileMapInfo::write_string_regions() for details.
|
||||
_string_regions = new GrowableArray<MemRegion>(2);
|
||||
StringTable::write_to_archive(_string_regions);
|
||||
}
|
||||
|
||||
char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
|
||||
|
@ -1206,7 +1213,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
|||
tty->print_cr(" type array classes = %5d", num_type_array);
|
||||
}
|
||||
|
||||
|
||||
// Ensure the ConstMethods won't be modified at run-time
|
||||
tty->print("Updating ConstMethods ... ");
|
||||
rewrite_nofast_bytecodes_and_calculate_fingerprints();
|
||||
|
@ -1220,7 +1226,13 @@ void VM_PopulateDumpSharedSpace::doit() {
|
|||
ArchiveCompactor::initialize();
|
||||
ArchiveCompactor::copy_and_compact();
|
||||
|
||||
dump_string_and_symbols();
|
||||
dump_symbols();
|
||||
|
||||
// Dump supported java heap objects
|
||||
_string_regions = NULL;
|
||||
_open_archive_heap_regions = NULL;
|
||||
dump_java_heap_objects();
|
||||
|
||||
ArchiveCompactor::relocate_well_known_klasses();
|
||||
|
||||
char* read_only_tables_start = dump_read_only_tables();
|
||||
|
@ -1258,9 +1270,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
|||
mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size());
|
||||
mapinfo->set_core_spaces_size(core_spaces_size);
|
||||
|
||||
char* s0_start, *s0_top, *s0_end;
|
||||
char* s1_start, *s1_top, *s1_end;
|
||||
|
||||
for (int pass=1; pass<=2; pass++) {
|
||||
if (pass == 1) {
|
||||
// The first pass doesn't actually write the data to disk. All it
|
||||
|
@ -1282,9 +1291,14 @@ void VM_PopulateDumpSharedSpace::doit() {
|
|||
write_region(mapinfo, MetaspaceShared::md, &_md_region, /*read_only=*/false,/*allow_exec=*/false);
|
||||
write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false);
|
||||
|
||||
mapinfo->write_string_regions(_string_regions,
|
||||
&s0_start, &s0_top, &s0_end,
|
||||
&s1_start, &s1_top, &s1_end);
|
||||
_total_string_region_size = mapinfo->write_archive_heap_regions(
|
||||
_string_regions,
|
||||
MetaspaceShared::first_string,
|
||||
MetaspaceShared::max_strings);
|
||||
_total_open_archive_region_size = mapinfo->write_archive_heap_regions(
|
||||
_open_archive_heap_regions,
|
||||
MetaspaceShared::first_open_archive_heap_region,
|
||||
MetaspaceShared::max_open_archive_heap_region);
|
||||
}
|
||||
|
||||
mapinfo->close();
|
||||
|
@ -1292,8 +1306,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
|||
// Restore the vtable in case we invoke any virtual methods.
|
||||
MetaspaceShared::clone_cpp_vtables((intptr_t*)vtbl_list);
|
||||
|
||||
_s0_region.init(s0_start, s0_top, s0_end);
|
||||
_s1_region.init(s1_start, s1_top, s1_end);
|
||||
print_region_stats();
|
||||
|
||||
if (log_is_enabled(Info, cds)) {
|
||||
|
@ -1307,11 +1319,13 @@ void VM_PopulateDumpSharedSpace::print_region_stats() {
|
|||
const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
|
||||
_mc_region.reserved() + _md_region.reserved() +
|
||||
_od_region.reserved() +
|
||||
_s0_region.reserved() + _s1_region.reserved();
|
||||
_total_string_region_size +
|
||||
_total_open_archive_region_size;
|
||||
const size_t total_bytes = _ro_region.used() + _rw_region.used() +
|
||||
_mc_region.used() + _md_region.used() +
|
||||
_od_region.used() +
|
||||
_s0_region.used() + _s1_region.used();
|
||||
_total_string_region_size +
|
||||
_total_open_archive_region_size;
|
||||
const double total_u_perc = total_bytes / double(total_reserved) * 100.0;
|
||||
|
||||
_mc_region.print(total_reserved);
|
||||
|
@ -1319,13 +1333,25 @@ void VM_PopulateDumpSharedSpace::print_region_stats() {
|
|||
_ro_region.print(total_reserved);
|
||||
_md_region.print(total_reserved);
|
||||
_od_region.print(total_reserved);
|
||||
_s0_region.print(total_reserved);
|
||||
_s1_region.print(total_reserved);
|
||||
print_heap_region_stats(_string_regions, "st", total_reserved);
|
||||
print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
|
||||
|
||||
tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
|
||||
total_bytes, total_reserved, total_u_perc);
|
||||
}
|
||||
|
||||
void VM_PopulateDumpSharedSpace::print_heap_region_stats(GrowableArray<MemRegion> *heap_mem,
|
||||
const char *name, const size_t total_size) {
|
||||
int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
|
||||
for (int i = 0; i < arr_len; i++) {
|
||||
char* start = (char*)heap_mem->at(i).start();
|
||||
size_t size = heap_mem->at(i).byte_size();
|
||||
char* top = start + size;
|
||||
tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100%% used] at " INTPTR_FORMAT,
|
||||
name, i, size, size/double(total_size)*100.0, size, p2i(start));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Update a Java object to point its Klass* to the new location after
|
||||
// shared archive has been compacted.
|
||||
|
@ -1352,6 +1378,8 @@ class LinkSharedClassesClosure : public KlassClosure {
|
|||
// to -Xverify setting.
|
||||
_made_progress |= MetaspaceShared::try_link_class(ik, THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
|
||||
|
||||
ik->constants()->resolve_class_constants(THREAD);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1556,6 +1584,98 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
|
|||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
|
||||
if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
|
||||
if (log_is_enabled(Info, cds)) {
|
||||
log_info(cds)(
|
||||
"Archived java heap is not supported as UseG1GC, "
|
||||
"UseCompressedOops and UseCompressedClassPointers are required."
|
||||
"Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
|
||||
BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
|
||||
BOOL_TO_STR(UseCompressedClassPointers));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
NoSafepointVerifier nsv;
|
||||
|
||||
// Cache for recording where the archived objects are copied to
|
||||
MetaspaceShared::create_archive_object_cache();
|
||||
|
||||
tty->print_cr("Dumping String objects to closed archive heap region ...");
|
||||
NOT_PRODUCT(StringTable::verify());
|
||||
// The string space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
|
||||
_string_regions = new GrowableArray<MemRegion>(2);
|
||||
StringTable::write_to_archive(_string_regions);
|
||||
|
||||
tty->print_cr("Dumping objects to open archive heap region ...");
|
||||
_open_archive_heap_regions = new GrowableArray<MemRegion>(2);
|
||||
MetaspaceShared::dump_open_archive_heap_objects(_open_archive_heap_regions);
|
||||
}
|
||||
|
||||
G1HeapVerifier::verify_archive_regions();
|
||||
}
|
||||
|
||||
void MetaspaceShared::dump_open_archive_heap_objects(
|
||||
GrowableArray<MemRegion> * open_archive) {
|
||||
assert(UseG1GC, "Only support G1 GC");
|
||||
assert(UseCompressedOops && UseCompressedClassPointers,
|
||||
"Only support UseCompressedOops and UseCompressedClassPointers enabled");
|
||||
|
||||
Thread* THREAD = Thread::current();
|
||||
G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */);
|
||||
|
||||
MetaspaceShared::archive_resolved_constants(THREAD);
|
||||
|
||||
G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
|
||||
os::vm_allocation_granularity());
|
||||
}
|
||||
|
||||
MetaspaceShared::ArchivedObjectCache* MetaspaceShared::_archive_object_cache = NULL;
|
||||
oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
|
||||
assert(DumpSharedSpaces, "dump-time only");
|
||||
|
||||
ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
|
||||
oop* p = cache->get(obj);
|
||||
if (p != NULL) {
|
||||
// already archived
|
||||
return *p;
|
||||
}
|
||||
|
||||
int len = obj->size();
|
||||
if (G1CollectedHeap::heap()->is_archive_alloc_too_large(len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hash = obj->identity_hash();
|
||||
oop archived_oop = (oop)G1CollectedHeap::heap()->archive_mem_allocate(len);
|
||||
if (archived_oop != NULL) {
|
||||
Copy::aligned_disjoint_words((HeapWord*)obj, (HeapWord*)archived_oop, len);
|
||||
relocate_klass_ptr(archived_oop);
|
||||
cache->put(obj, archived_oop);
|
||||
}
|
||||
return archived_oop;
|
||||
}
|
||||
|
||||
void MetaspaceShared::archive_resolved_constants(Thread* THREAD) {
|
||||
int i;
|
||||
for (i = 0; i < _global_klass_objects->length(); i++) {
|
||||
Klass* k = _global_klass_objects->at(i);
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
ik->constants()->archive_resolved_references(THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetaspaceShared::fixup_mapped_heap_regions() {
|
||||
FileMapInfo *mapinfo = FileMapInfo::current_info();
|
||||
mapinfo->fixup_mapped_heap_regions();
|
||||
}
|
||||
#endif // INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
// Closure for serializing initialization data in from a data area
|
||||
// (ptr_array) read from the shared file.
|
||||
|
||||
|
@ -1743,11 +1863,6 @@ void MetaspaceShared::initialize_shared_spaces() {
|
|||
}
|
||||
}
|
||||
|
||||
void MetaspaceShared::fixup_shared_string_regions() {
|
||||
FileMapInfo *mapinfo = FileMapInfo::current_info();
|
||||
mapinfo->fixup_string_regions();
|
||||
}
|
||||
|
||||
// JVM/TI RedefineClasses() support:
|
||||
bool MetaspaceShared::remap_shared_readonly_as_readwrite() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "memory/virtualspace.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
#define MAX_SHARED_DELTA (0x7FFFFFFF)
|
||||
|
||||
|
@ -56,23 +57,32 @@ class MetaspaceShared : AllStatic {
|
|||
static bool _has_error_classes;
|
||||
static bool _archive_loading_failed;
|
||||
static bool _remapped_readwrite;
|
||||
static bool _open_archive_heap_region_mapped;
|
||||
static address _cds_i2i_entry_code_buffers;
|
||||
static size_t _cds_i2i_entry_code_buffers_size;
|
||||
static size_t _core_spaces_size;
|
||||
public:
|
||||
enum {
|
||||
// core archive spaces
|
||||
mc = 0, // miscellaneous code for method trampolines
|
||||
rw = 1, // read-write shared space in the heap
|
||||
ro = 2, // read-only shared space in the heap
|
||||
md = 3, // miscellaneous data for initializing tables, etc.
|
||||
max_strings = 2, // max number of string regions in string space
|
||||
num_non_strings = 4, // number of non-string regions
|
||||
first_string = num_non_strings, // index of first string region
|
||||
// The optional data region is the last region.
|
||||
num_core_spaces = 4, // number of non-string regions
|
||||
|
||||
// optional mapped spaces
|
||||
// Currently it only contains class file data.
|
||||
od = max_strings + num_non_strings,
|
||||
last_valid_region = od,
|
||||
n_regions = od + 1 // total number of regions
|
||||
od = num_core_spaces,
|
||||
num_non_heap_spaces = od + 1,
|
||||
|
||||
// mapped java heap regions
|
||||
first_string = od + 1, // index of first string region
|
||||
max_strings = 2, // max number of string regions in string space
|
||||
first_open_archive_heap_region = first_string + max_strings,
|
||||
max_open_archive_heap_region = 2,
|
||||
|
||||
last_valid_region = first_open_archive_heap_region + max_open_archive_heap_region - 1,
|
||||
n_regions = last_valid_region + 1 // total number of regions
|
||||
};
|
||||
|
||||
static void prepare_for_dumping() NOT_CDS_RETURN;
|
||||
|
@ -80,6 +90,45 @@ class MetaspaceShared : AllStatic {
|
|||
static int preload_classes(const char * class_list_path,
|
||||
TRAPS) NOT_CDS_RETURN_(0);
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
private:
|
||||
static bool obj_equals(oop const& p1, oop const& p2) {
|
||||
return p1 == p2;
|
||||
}
|
||||
static unsigned obj_hash(oop const& p) {
|
||||
unsigned hash = (unsigned)((uintptr_t)&p);
|
||||
return hash ^ (hash >> LogMinObjAlignment);
|
||||
}
|
||||
typedef ResourceHashtable<oop, oop,
|
||||
MetaspaceShared::obj_hash, MetaspaceShared::obj_equals> ArchivedObjectCache;
|
||||
static ArchivedObjectCache* _archive_object_cache;
|
||||
|
||||
public:
|
||||
static ArchivedObjectCache* archive_object_cache() {
|
||||
return _archive_object_cache;
|
||||
}
|
||||
static oop archive_heap_object(oop obj, Thread* THREAD);
|
||||
static void archive_resolved_constants(Thread* THREAD);
|
||||
#endif
|
||||
static bool is_heap_object_archiving_allowed() {
|
||||
CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);)
|
||||
NOT_CDS_JAVA_HEAP(return false;)
|
||||
}
|
||||
static void create_archive_object_cache() {
|
||||
CDS_JAVA_HEAP_ONLY(_archive_object_cache = new ArchivedObjectCache(););
|
||||
}
|
||||
static void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
static void dump_open_archive_heap_objects(GrowableArray<MemRegion> * open_archive) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void set_open_archive_heap_region_mapped() {
|
||||
CDS_JAVA_HEAP_ONLY(_open_archive_heap_region_mapped = true);
|
||||
NOT_CDS_JAVA_HEAP_RETURN;
|
||||
}
|
||||
static bool open_archive_heap_region_mapped() {
|
||||
CDS_JAVA_HEAP_ONLY(return _open_archive_heap_region_mapped);
|
||||
NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
}
|
||||
|
||||
static ReservedSpace* shared_rs() {
|
||||
CDS_ONLY(return &_shared_rs);
|
||||
NOT_CDS(return NULL);
|
||||
|
@ -104,16 +153,29 @@ class MetaspaceShared : AllStatic {
|
|||
}
|
||||
static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false);
|
||||
static void initialize_shared_spaces() NOT_CDS_RETURN;
|
||||
static void fixup_shared_string_regions() NOT_CDS_RETURN;
|
||||
|
||||
// Return true if given address is in the mapped shared space.
|
||||
static bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
|
||||
|
||||
// Return true if given address is in the shared region corresponding to the idx
|
||||
static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
|
||||
|
||||
static bool is_heap_region(int idx) {
|
||||
CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_string &&
|
||||
idx < MetaspaceShared::first_open_archive_heap_region +
|
||||
MetaspaceShared::max_open_archive_heap_region));
|
||||
NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
}
|
||||
static bool is_string_region(int idx) {
|
||||
CDS_ONLY(return (idx >= first_string && idx < first_string + max_strings));
|
||||
NOT_CDS(return false);
|
||||
CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_string &&
|
||||
idx < MetaspaceShared::first_string + MetaspaceShared::max_strings));
|
||||
NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
}
|
||||
static bool is_open_archive_heap_region(int idx) {
|
||||
CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_open_archive_heap_region &&
|
||||
idx < MetaspaceShared::first_open_archive_heap_region +
|
||||
MetaspaceShared::max_open_archive_heap_region));
|
||||
NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
}
|
||||
static bool is_in_trampoline_frame(address addr) NOT_CDS_RETURN_(false);
|
||||
|
||||
|
@ -124,7 +186,6 @@ class MetaspaceShared : AllStatic {
|
|||
static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
|
||||
static void serialize(SerializeClosure* sc);
|
||||
|
||||
|
||||
static MetaspaceSharedStats* stats() {
|
||||
return &_stats;
|
||||
}
|
||||
|
|
|
@ -370,7 +370,7 @@ void Universe::genesis(TRAPS) {
|
|||
SystemDictionary::Cloneable_klass(), "u3");
|
||||
assert(_the_array_interfaces_array->at(1) ==
|
||||
SystemDictionary::Serializable_klass(), "u3");
|
||||
MetaspaceShared::fixup_shared_string_regions();
|
||||
MetaspaceShared::fixup_mapped_heap_regions();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
|
@ -47,6 +48,9 @@
|
|||
#include "runtime/signature.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
|
||||
Array<u1>* tags = MetadataFactory::new_array<u1>(loader_data, length, 0, CHECK_NULL);
|
||||
|
@ -238,11 +242,53 @@ void ConstantPool::klass_at_put(int class_index, Klass* k) {
|
|||
release_tag_at_put(class_index, JVM_CONSTANT_Class);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
// Archive the resolved references
|
||||
void ConstantPool::archive_resolved_references(Thread* THREAD) {
|
||||
if (_cache == NULL) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
InstanceKlass *ik = pool_holder();
|
||||
if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
|
||||
ik->is_shared_app_class())) {
|
||||
// Archiving resolved references for classes from non-builtin loaders
|
||||
// is not yet supported.
|
||||
set_resolved_references(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
objArrayOop rr = resolved_references();
|
||||
if (rr != NULL) {
|
||||
for (int i = 0; i < rr->length(); i++) {
|
||||
oop p = rr->obj_at(i);
|
||||
if (p != NULL) {
|
||||
int index = object_to_cp_index(i);
|
||||
if (tag_at(index).is_string()) {
|
||||
oop op = StringTable::create_archived_string(p, THREAD);
|
||||
// If the String object is not archived (possibly too large),
|
||||
// NULL is returned. Also set it in the array, so we won't
|
||||
// have a 'bad' reference in the archived resolved_reference
|
||||
// array.
|
||||
rr->obj_at_put(i, op);
|
||||
} else {
|
||||
rr->obj_at_put(i, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
oop archived = MetaspaceShared::archive_heap_object(rr, THREAD);
|
||||
_cache->set_archived_references(archived);
|
||||
set_resolved_references(NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// CDS support. Create a new resolved_references array.
|
||||
void ConstantPool::restore_unshareable_info(TRAPS) {
|
||||
assert(is_constantPool(), "ensure C++ vtable is restored");
|
||||
assert(on_stack(), "should always be set for shared constant pools");
|
||||
assert(is_shared(), "should always be set for shared constant pools");
|
||||
assert(_cache != NULL, "constant pool _cache should not be NULL");
|
||||
|
||||
// Only create the new resolved references array if it hasn't been attempted before
|
||||
if (resolved_references() != NULL) return;
|
||||
|
@ -251,25 +297,49 @@ void ConstantPool::restore_unshareable_info(TRAPS) {
|
|||
restore_vtable();
|
||||
|
||||
if (SystemDictionary::Object_klass_loaded()) {
|
||||
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
if (MetaspaceShared::open_archive_heap_region_mapped() &&
|
||||
_cache->archived_references() != NULL) {
|
||||
oop archived = _cache->archived_references();
|
||||
// Make sure GC knows the cached object is now live. This is necessary after
|
||||
// initial GC marking and during concurrent marking as strong roots are only
|
||||
// scanned during initial marking (at the start of the GC marking).
|
||||
assert(UseG1GC, "Requires G1 GC");
|
||||
G1SATBCardTableModRefBS::enqueue(archived);
|
||||
// Create handle for the archived resolved reference array object
|
||||
Handle refs_handle(THREAD, (oop)archived);
|
||||
set_resolved_references(loader_data->add_handle(refs_handle));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// No mapped archived resolved reference array
|
||||
// Recreate the object array and add to ClassLoaderData.
|
||||
int map_length = resolved_reference_length();
|
||||
if (map_length > 0) {
|
||||
objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
|
||||
Handle refs_handle (THREAD, (oop)stom); // must handleize.
|
||||
|
||||
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
|
||||
Handle refs_handle(THREAD, (oop)stom); // must handleize.
|
||||
set_resolved_references(loader_data->add_handle(refs_handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantPool::remove_unshareable_info() {
|
||||
// Resolved references are not in the shared archive.
|
||||
// Save the length for restoration. It is not necessarily the same length
|
||||
// as reference_map.length() if invokedynamic is saved.
|
||||
// as reference_map.length() if invokedynamic is saved. It is needed when
|
||||
// re-creating the resolved reference array if archived heap data cannot be map
|
||||
// at runtime.
|
||||
set_resolved_reference_length(
|
||||
resolved_references() != NULL ? resolved_references()->length() : 0);
|
||||
|
||||
// If archiving heap objects is not allowed, clear the resolved references.
|
||||
// Otherwise, it is cleared after the resolved references array is cached
|
||||
// (see archive_resolved_references()).
|
||||
if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
|
||||
set_resolved_references(NULL);
|
||||
}
|
||||
|
||||
// Shared ConstantPools are in the RO region, so the _flags cannot be modified.
|
||||
// The _on_stack flag is used to prevent ConstantPools from deallocation during
|
||||
|
@ -619,19 +689,19 @@ void ConstantPool::resolve_string_constants_impl(const constantPoolHandle& this_
|
|||
}
|
||||
}
|
||||
|
||||
// Resolve all the classes in the constant pool. If they are all resolved,
|
||||
// the constant pool is read-only. Enhancement: allocate cp entries to
|
||||
// another metaspace, and copy to read-only or read-write space if this
|
||||
// bit is set.
|
||||
bool ConstantPool::resolve_class_constants(TRAPS) {
|
||||
constantPoolHandle cp(THREAD, this);
|
||||
for (int index = 1; index < length(); index++) { // Index 0 is unused
|
||||
if (tag_at(index).is_unresolved_klass() &&
|
||||
klass_at_if_loaded(cp, index) == NULL) {
|
||||
return false;
|
||||
if (tag_at(index).is_string()) {
|
||||
Symbol* sym = cp->unresolved_string_at(index);
|
||||
// Look up only. Only resolve references to already interned strings.
|
||||
oop str = StringTable::lookup(sym);
|
||||
if (str != NULL) {
|
||||
int cache_index = cp->cp_to_object_index(index);
|
||||
cp->string_at_put(index, cache_index, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
// set_preresolution(); or some bit for future use
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -714,6 +714,7 @@ class ConstantPool : public Metadata {
|
|||
}
|
||||
|
||||
// CDS support
|
||||
void archive_resolved_references(Thread *THREAD) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
void remove_unshareable_info();
|
||||
void restore_unshareable_info(TRAPS);
|
||||
bool resolve_class_constants(TRAPS);
|
||||
|
|
|
@ -608,6 +608,18 @@ void ConstantPoolCache::initialize(const intArray& inverse_index_map,
|
|||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
oop ConstantPoolCache::archived_references() {
|
||||
assert(UseSharedSpaces, "UseSharedSpaces expected.");
|
||||
return oopDesc::decode_heap_oop(_archived_references);
|
||||
}
|
||||
|
||||
void ConstantPoolCache::set_archived_references(oop o) {
|
||||
assert(DumpSharedSpaces, "called only during runtime");
|
||||
_archived_references = oopDesc::encode_heap_oop(o);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
// RedefineClasses() API support:
|
||||
// If any entry of this ConstantPoolCache points to any of
|
||||
|
|
|
@ -415,6 +415,9 @@ class ConstantPoolCache: public MetaspaceObj {
|
|||
// object index to original constant pool index
|
||||
jobject _resolved_references;
|
||||
Array<u2>* _reference_map;
|
||||
// The narrowOop pointer to the archived resolved_references. Set at CDS dump
|
||||
// time when caching java heap object is supported.
|
||||
CDS_JAVA_HEAP_ONLY(narrowOop _archived_references;)
|
||||
|
||||
// Sizing
|
||||
debug_only(friend class ClassVerifier;)
|
||||
|
@ -426,6 +429,7 @@ class ConstantPoolCache: public MetaspaceObj {
|
|||
const intStack& invokedynamic_references_map) :
|
||||
_length(length),
|
||||
_constant_pool(NULL) {
|
||||
CDS_JAVA_HEAP_ONLY(_archived_references = 0;)
|
||||
initialize(inverse_index_map, invokedynamic_inverse_index_map,
|
||||
invokedynamic_references_map);
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -448,6 +452,9 @@ class ConstantPoolCache: public MetaspaceObj {
|
|||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
MetaspaceObj::Type type() const { return ConstantPoolCacheType; }
|
||||
|
||||
oop archived_references() NOT_CDS_JAVA_HEAP_RETURN_(NULL);
|
||||
void set_archived_references(oop o) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
|
||||
jobject resolved_references() { return _resolved_references; }
|
||||
void set_resolved_references(jobject s) { _resolved_references = s; }
|
||||
Array<u2>* reference_map() const { return _reference_map; }
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1Allocator.inline.hpp"
|
||||
#endif
|
||||
|
||||
bool always_do_update_barrier = false;
|
||||
|
||||
|
@ -138,3 +141,9 @@ bool oopDesc::has_klass_gap() {
|
|||
// Only has a klass gap when compressed class pointers are used.
|
||||
return UseCompressedClassPointers;
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
bool oopDesc::is_archive_object(oop p) {
|
||||
return (p == NULL) ? false : G1ArchiveAllocator::is_archive_object(p);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -389,6 +389,8 @@ class oopDesc {
|
|||
assert(has_klass_gap(), "only applicable to compressed klass pointers");
|
||||
return klass_offset_in_bytes() + sizeof(narrowKlass);
|
||||
}
|
||||
|
||||
static bool is_archive_object(oop p) NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OOPS_OOP_HPP
|
||||
|
|
|
@ -590,6 +590,9 @@ void oopDesc::forward_to(oop p) {
|
|||
"forwarding to something not aligned");
|
||||
assert(Universe::heap()->is_in_reserved(p),
|
||||
"forwarding to something not in heap");
|
||||
assert(!is_archive_object(oop(this)) &&
|
||||
!is_archive_object(p),
|
||||
"forwarding archive object");
|
||||
markOop m = markOopDesc::encode_pointer_as_mark(p);
|
||||
assert(m->decode_pointer() == p, "encoding must be reversable");
|
||||
set_mark(m);
|
||||
|
|
|
@ -1689,7 +1689,7 @@ WB_END
|
|||
|
||||
WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj))
|
||||
oop obj_oop = JNIHandles::resolve(obj);
|
||||
return MetaspaceShared::is_in_shared_space((void*)obj_oop);
|
||||
return oopDesc::is_archive_object(obj_oop);
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz))
|
||||
|
@ -1697,7 +1697,19 @@ WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz))
|
|||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env))
|
||||
return StringTable::shared_string_ignored();
|
||||
return !StringTable::shared_string_mapped();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jobject, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass clazz))
|
||||
Klass *k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||
ConstantPool *cp = ik->constants();
|
||||
objArrayOop refs = cp->resolved_references();
|
||||
return (jobject)JNIHandles::make_local(env, refs);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_IsCDSIncludedInVmBuild(JNIEnv* env))
|
||||
|
@ -2001,6 +2013,7 @@ static JNINativeMethod methods[] = {
|
|||
{CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared },
|
||||
{CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass },
|
||||
{CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored },
|
||||
{CC"getResolvedReferences", CC"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)&WB_GetResolvedReferences},
|
||||
{CC"isCDSIncludedInVmBuild", CC"()Z", (void*)&WB_IsCDSIncludedInVmBuild },
|
||||
{CC"clearInlineCaches0", CC"(Z)V", (void*)&WB_ClearInlineCaches },
|
||||
{CC"addCompilerDirective", CC"(Ljava/lang/String;)I",
|
||||
|
|
|
@ -536,4 +536,18 @@
|
|||
non_atomic_decl
|
||||
#endif
|
||||
|
||||
#if INCLUDE_CDS && INCLUDE_ALL_GCS && defined(_LP64) && !defined(_WINDOWS)
|
||||
#define INCLUDE_CDS_JAVA_HEAP 1
|
||||
#define CDS_JAVA_HEAP_ONLY(x) x
|
||||
#define NOT_CDS_JAVA_HEAP(x)
|
||||
#define NOT_CDS_JAVA_HEAP_RETURN
|
||||
#define NOT_CDS_JAVA_HEAP_RETURN_(code)
|
||||
#else
|
||||
#define INCLUDE_CDS_JAVA_HEAP 0
|
||||
#define CDS_JAVA_HEAP_ONLY(x)
|
||||
#define NOT_CDS_JAVA_HEAP(x) x
|
||||
#define NOT_CDS_JAVA_HEAP_RETURN {}
|
||||
#define NOT_CDS_JAVA_HEAP_RETURN_(code) { return code; }
|
||||
#endif
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_MACROS_HPP
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue