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.
Summary: Shared class' constant pool resolved_references array is cached.
Reviewed-by: coleenp, iklam, tschatzl
Contributed-by: jiangli.zhou@oracle.com, thomas.schatzl@oracle.com
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -90,7 +90,7 @@
// --------------------------------------------------------------------------
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 @@
}
}
+#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,94 +714,54 @@
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
- CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
- &MetaspaceShared::stats()->string);
+ int num_buckets = the_table()->number_of_entries() /
+ SharedSymbolTableBucketSize;
+ // calculation of num_buckets can result in zero buckets, we need at least one
+ CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
+ &MetaspaceShared::stats()->string);
- // Copy the interned strings into the "string space" within the java heap
- if (copy_shared_string(string_space, &writer)) {
- writer.dump(&_shared_table);
- }
+ // Copy the interned strings into the "string space" within the java heap
+ 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
--- a/hotspot/src/share/vm/classfile/stringTable.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -43,7 +43,7 @@
// 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 @@
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();
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -331,12 +331,13 @@
}
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 @@
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 @@
_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();
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -321,11 +321,19 @@
};
// 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 @@
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 @@
_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 @@
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();
};
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -55,37 +55,60 @@
}
}
-// 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(),
- (HeapWord*)Universe::heap()->base() + length,
- HeapRegion::GrainBytes);
+ _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
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -614,10 +614,10 @@
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 @@
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 @@
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 @@
}
- // 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 @@
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 @@
// 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();
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -681,7 +681,7 @@
// 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 @@
// 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
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -1134,13 +1134,10 @@
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()) {
--- a/hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
StartsHumongous,
ContinuesHumongous,
Old,
- Archive,
+ Pinned,
+ OpenArchive,
+ ClosedArchive,
G1HeapRegionTypeEndSentinel
};
@@ -49,7 +51,9 @@
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;
}
}
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -234,30 +234,63 @@
};
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);
- 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));
+
+ 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 @@
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) {
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
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
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -222,7 +222,7 @@
// 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();
}
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -185,14 +185,25 @@
_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) {
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -433,7 +433,9 @@
// An archive region is a pinned region, also tagged as old, which
// 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_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 @@
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
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -117,7 +117,8 @@
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 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 {
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -34,7 +34,8 @@
case StartsHumongousTag:
case ContinuesHumongousTag:
case OldTag:
- case ArchiveTag:
+ case OpenArchiveTag:
+ case ClosedArchiveTag:
return true;
default:
return false;
@@ -50,7 +51,8 @@
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 @@
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 @@
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
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
// 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
//
- // 1100 0 [24] Archive
+ // 10000 0 [32] Archive Mask
+ // 11100 0 [56] Open Archive
+ // 11100 1 [57] Closed Archive
+ //
typedef enum {
FreeTag = 0,
@@ -72,7 +75,18 @@
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 @@
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 @@
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
--- a/hotspot/src/share/vm/gc/serial/markSweep.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -87,7 +87,7 @@
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 @@
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 @@
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;
--- a/hotspot/src/share/vm/gc/serial/markSweep.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -134,6 +134,8 @@
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; }
--- a/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
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
+
+ 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);
--- a/hotspot/src/share/vm/gc/shared/space.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/space.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
// 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;
--- a/hotspot/src/share/vm/memory/filemap.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/filemap.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -351,7 +351,8 @@
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 @@
} 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 @@
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 archive heap memory size is smaller than a single dump time GC region
+// size, there is only one MemRegion in the 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 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.
//
-// 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
+// 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 heap region (r0), then s0 == r0, and s1 is empty.
+// 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;
- }
- } 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;
- }
- }
+ if (arr_idx < arr_len) {
+ start = (char*)heap_mem->at(arr_idx).start();
+ size = heap_mem->at(arr_idx).byte_size();
+ total_size += 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 @@
}
// 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 @@
}
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++) {
- 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 ++;
+ // 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();
}
}
-
- if (num_ranges == 0) {
- StringTable::ignore_shared_strings(true);
- return true; // no shared string 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.");
- 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.");
- 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();
- char* base = os::map_memory(_fd, _full_path, si->_file_offset,
- addr, string_ranges[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.");
- return false;
- }
- }
-
- if (!verify_string_regions()) {
- // dealloc the string regions from java heap
- dealloc_string_regions();
- fail_continue("Shared string 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, "
+ log_info(cds)("Cached heap 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
+ 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));
+ regions[region_num] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+ region_num ++;
+ }
+ }
+
+ 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(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(
+ 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 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, regions[i].byte_size(), si->_read_only,
+ si->_allow_exec);
+ if (base == NULL || base != addr) {
+ // dealloc the regions from java heap
+ dealloc_archive_heap_regions(regions, region_num);
+ log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap.");
+ return false;
+ }
+ }
+
+ 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 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 @@
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 @@
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 @@
// 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 @@
}
}
-// 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 @@
}
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 @@
}
// 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 @@
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 @@
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);
}
--- a/hotspot/src/share/vm/memory/filemap.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/filemap.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -242,17 +242,14 @@
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 @@
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
--- a/hotspot/src/share/vm/memory/metaspace.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -3347,9 +3347,9 @@
// 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 {
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -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,21 +73,24 @@
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;
// The CDS archive is divided into the following regions:
-// mc - misc code (the method entry trampolines)
-// rw - read-write metadata
-// ro - read-only metadata and read-only tables
-// md - misc data (the c++ vtables)
-// od - optional data (original class files)
+// mc - misc code (the method entry trampolines)
+// rw - read-write metadata
+// ro - read-only metadata and read-only tables
+// 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 @@
// [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 @@
}
};
+
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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)) {
@@ -1304,14 +1316,16 @@
void VM_PopulateDumpSharedSpace::print_region_stats() {
// Print statistics of all the regions
- 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();
- 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();
+ const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
+ _mc_region.reserved() + _md_region.reserved() +
+ _od_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() +
+ _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 @@
_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 @@
// 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 @@
}
}
+#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::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");
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
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.
+ num_core_spaces = 4, // number of non-string regions
+
+ // optional mapped spaces
+ // Currently it only contains class file data.
+ 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
- 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.
- // 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
+ 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 @@
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 @@
}
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 @@
static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
static void serialize(SerializeClosure* sc);
-
static MetaspaceSharedStats* stats() {
return &_stats;
}
--- a/hotspot/src/share/vm/memory/universe.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/memory/universe.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -370,7 +370,7 @@
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
{
--- a/hotspot/src/share/vm/oops/constantPool.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
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,14 +297,30 @@
restore_vtable();
if (SystemDictionary::Object_klass_loaded()) {
- // 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();
+ 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.
+ set_resolved_references(loader_data->add_handle(refs_handle));
+ }
}
}
}
@@ -266,10 +328,18 @@
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);
- set_resolved_references(NULL);
+
+ // 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 @@
}
}
-// 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;
}
--- a/hotspot/src/share/vm/oops/constantPool.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -714,6 +714,7 @@
}
// 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);
--- a/hotspot/src/share/vm/oops/cpCache.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -608,6 +608,18 @@
}
}
+#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
--- a/hotspot/src/share/vm/oops/cpCache.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/cpCache.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -415,6 +415,9 @@
// 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 @@
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++) {
@@ -444,9 +448,12 @@
const intStack& invokedynamic_references_map, TRAPS);
bool is_constantPoolCache() const { return true; }
- int length() const { return _length; }
+ int length() const { return _length; }
void metaspace_pointers_do(MetaspaceClosure* it);
- MetaspaceObj::Type type() const { return ConstantPoolCacheType; }
+ 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; }
--- a/hotspot/src/share/vm/oops/oop.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -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 @@
// 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
--- a/hotspot/src/share/vm/oops/oop.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -389,6 +389,8 @@
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
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -590,6 +590,9 @@
"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);
--- a/hotspot/src/share/vm/prims/whitebox.cpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Mon Aug 14 14:32:17 2017 -0400
@@ -1689,7 +1689,7 @@
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_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 @@
{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",
--- a/hotspot/src/share/vm/utilities/macros.hpp Mon Aug 14 16:48:44 2017 +0200
+++ b/hotspot/src/share/vm/utilities/macros.hpp Mon Aug 14 14:32:17 2017 -0400
@@ -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