< prev index next > src/hotspot/share/cds/archiveBuilder.cpp
Print this page
#include "cds/archiveUtils.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/cppVtables.hpp"
#include "cds/dumpAllocStats.hpp"
#include "cds/dynamicArchive.hpp"
+ #include "cds/finalImageRecipes.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
+ #include "code/SCCache.hpp"
#include "interpreter/abstractInterpreter.hpp"
#include "jvm.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allStatic.hpp"
#include "memory/memoryReserver.hpp"
#include "memory/memRegion.hpp"
#include "memory/resourceArea.hpp"
#include "oops/compressedKlass.inline.hpp"
#include "oops/instanceKlass.hpp"
+ #include "oops/methodCounters.hpp"
+ #include "oops/methodData.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oopHandle.inline.hpp"
+ #include "oops/trainingData.hpp"
#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/sharedRuntime.hpp"
bool do_bit(BitMap::idx_t bit_offset) {
size_t field_offset = size_t(bit_offset - _start_idx) * sizeof(address);
address* ptr_loc = (address*)(_buffered_obj + field_offset);
! address old_p = *ptr_loc;
address new_p = _builder->get_buffered_addr(old_p);
! log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT,
! p2i(ptr_loc), p2i(old_p), p2i(new_p));
ArchivePtrMarker::set_and_mark_pointer(ptr_loc, new_p);
return true; // keep iterating the bitmap
}
};
void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) {
bool do_bit(BitMap::idx_t bit_offset) {
size_t field_offset = size_t(bit_offset - _start_idx) * sizeof(address);
address* ptr_loc = (address*)(_buffered_obj + field_offset);
! address old_p_with_tags = *ptr_loc;
+ assert(old_p_with_tags != nullptr, "null ptrs shouldn't have been marked");
+
+ address old_p = MetaspaceClosure::strip_tags(old_p_with_tags);
+ uintx tags = MetaspaceClosure::decode_tags(old_p_with_tags);
address new_p = _builder->get_buffered_addr(old_p);
! bool nulled;
! if (new_p == nullptr) {
+ // old_p had a FollowMode of set_to_null
+ nulled = true;
+ } else {
+ new_p = MetaspaceClosure::add_tags(new_p, tags);
+ nulled = false;
+ }
+
+ log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT " %zu",
+ p2i(ptr_loc), p2i(old_p) + tags, p2i(new_p), tags);
ArchivePtrMarker::set_and_mark_pointer(ptr_loc, new_p);
+ ArchiveBuilder::current()->count_relocated_pointer(tags != 0, nulled);
return true; // keep iterating the bitmap
}
};
void ArchiveBuilder::SourceObjList::relocate(int i, ArchiveBuilder* builder) {
_mapped_static_archive_top(nullptr),
_buffer_to_requested_delta(0),
_pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive.
_rw_region("rw", MAX_SHARED_DELTA),
_ro_region("ro", MAX_SHARED_DELTA),
+ _cc_region("cc", MAX_SHARED_DELTA),
_ptrmap(mtClassShared),
_rw_ptrmap(mtClassShared),
_ro_ptrmap(mtClassShared),
+ _cc_ptrmap(mtClassShared),
_rw_src_objs(),
_ro_src_objs(),
_src_obj_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
_buffered_to_src_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
_total_heap_region_size(0)
{
_klasses = new (mtClassShared) GrowableArray<Klass*>(4 * K, mtClassShared);
_symbols = new (mtClassShared) GrowableArray<Symbol*>(256 * K, mtClassShared);
_entropy_seed = 0x12345678;
+ _relocated_ptr_info._num_ptrs = 0;
+ _relocated_ptr_info._num_tagged_ptrs = 0;
+ _relocated_ptr_info._num_nulled_ptrs = 0;
assert(_current == nullptr, "must be");
_current = this;
}
ArchiveBuilder::~ArchiveBuilder() {
log_info(cds)("Sorting classes ... ");
_klasses->sort(compare_klass_by_name);
}
address ArchiveBuilder::reserve_buffer() {
! size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M);
ReservedSpace rs = MemoryReserver::reserve(buffer_size,
MetaspaceShared::core_region_alignment(),
os::vm_page_size());
if (!rs.is_reserved()) {
log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size);
log_info(cds)("Sorting classes ... ");
_klasses->sort(compare_klass_by_name);
}
address ArchiveBuilder::reserve_buffer() {
! // SCCache::max_aot_code_size() accounts for cached code region.
+ size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M) + SCCache::max_aot_code_size();
ReservedSpace rs = MemoryReserver::reserve(buffer_size,
MetaspaceShared::core_region_alignment(),
os::vm_page_size());
if (!rs.is_reserved()) {
log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size);
assert(!RegeneratedClasses::has_been_regenerated((address)m->method_holder()),
"Should not archive methods in a class that has been regenerated");
}
#endif
+ if (ref->msotype() == MetaspaceObj::MethodDataType) {
+ MethodData* md = (MethodData*)ref->obj();
+ md->clean_method_data(false /* always_clean */);
+ }
+
assert(p->read_only() == src_info.read_only(), "must be");
if (created && src_info.should_copy()) {
if (read_only) {
_ro_src_objs.append(p);
address obj = ref->obj();
if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(obj)) {
// Don't dump existing shared metadata again.
return point_to_it;
} else if (ref->msotype() == MetaspaceObj::MethodDataType ||
! ref->msotype() == MetaspaceObj::MethodCountersType) {
! return set_to_null;
} else {
if (ref->msotype() == MetaspaceObj::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (is_excluded(klass)) {
address obj = ref->obj();
if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(obj)) {
// Don't dump existing shared metadata again.
return point_to_it;
} else if (ref->msotype() == MetaspaceObj::MethodDataType ||
! ref->msotype() == MetaspaceObj::MethodCountersType ||
! ref->msotype() == MetaspaceObj::KlassTrainingDataType ||
+ ref->msotype() == MetaspaceObj::MethodTrainingDataType ||
+ ref->msotype() == MetaspaceObj::CompileTrainingDataType) {
+ return TrainingData::need_data() ? make_a_copy : set_to_null;
+ } else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) {
+ if (CDSConfig::is_dumping_adapters()) {
+ AdapterHandlerEntry* entry = (AdapterHandlerEntry*)ref->obj();
+ return AdapterHandlerLibrary::is_abstract_method_adapter(entry) ? set_to_null : make_a_copy;
+ } else {
+ return set_to_null;
+ }
} else {
if (ref->msotype() == MetaspaceObj::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (is_excluded(klass)) {
p2i(src_addr));
return p->buffered_addr();
}
+ bool ArchiveBuilder::has_been_archived(address src_addr) const {
+ SourceObjInfo* p = _src_obj_table.get(src_addr);
+ return (p != nullptr);
+ }
+
address ArchiveBuilder::get_source_addr(address buffered_addr) const {
assert(is_in_buffer_space(buffered_addr), "must be");
address* src_p = _buffered_to_src_table.get(buffered_addr);
assert(src_p != nullptr && *src_p != nullptr, "must be");
return *src_p;
void ArchiveBuilder::relocate_metaspaceobj_embedded_pointers() {
log_info(cds)("Relocating embedded pointers in core regions ... ");
relocate_embedded_pointers(&_rw_src_objs);
relocate_embedded_pointers(&_ro_src_objs);
+ log_info(cds)("Relocating %zu pointers, %zu tagged, %zu nulled",
+ _relocated_ptr_info._num_ptrs,
+ _relocated_ptr_info._num_tagged_ptrs,
+ _relocated_ptr_info._num_nulled_ptrs);
}
#define ADD_COUNT(x) \
x += 1; \
x ## _a += aotlinked ? 1 : 0; \
#undef STATS_PARAMS
DynamicArchive::make_array_klasses_shareable();
}
+ void ArchiveBuilder::make_training_data_shareable() {
+ auto clean_td = [&] (address& src_obj, SourceObjInfo& info) {
+ if (!is_in_buffer_space(info.buffered_addr())) {
+ return;
+ }
+
+ if (info.msotype() == MetaspaceObj::KlassTrainingDataType ||
+ info.msotype() == MetaspaceObj::MethodTrainingDataType ||
+ info.msotype() == MetaspaceObj::CompileTrainingDataType) {
+ TrainingData* buffered_td = (TrainingData*)info.buffered_addr();
+ buffered_td->remove_unshareable_info();
+ } else if (info.msotype() == MetaspaceObj::MethodDataType) {
+ MethodData* buffered_mdo = (MethodData*)info.buffered_addr();
+ buffered_mdo->remove_unshareable_info();
+ } else if (info.msotype() == MetaspaceObj::MethodCountersType) {
+ MethodCounters* buffered_mc = (MethodCounters*)info.buffered_addr();
+ buffered_mc->remove_unshareable_info();
+ }
+ };
+ _src_obj_table.iterate_all(clean_td);
+ }
+
void ArchiveBuilder::serialize_dynamic_archivable_items(SerializeClosure* soc) {
SymbolTable::serialize_shared_table_header(soc, false);
SystemDictionaryShared::serialize_dictionary_headers(soc, false);
DynamicArchive::serialize_array_klasses(soc);
AOTLinkedClassBulkLoader::serialize(soc, false);
p = get_buffered_addr(p);
}
return buffer_to_offset(p);
}
+ void ArchiveBuilder::start_cc_region() {
+ ro_region()->pack();
+ start_dump_region(&_cc_region);
+ }
+
+ void ArchiveBuilder::end_cc_region() {
+ _cc_region.pack();
+ }
+
address ArchiveBuilder::offset_to_buffered_address(u4 offset) const {
address requested_addr = _requested_static_archive_bottom + offset;
address buffered_addr = requested_addr - _buffer_to_requested_delta;
assert(is_in_buffer_space(buffered_addr), "bad offset");
return buffered_addr;
return UseCompactObjectHeaders ? CompressedKlassPointers::max_shift() : 0;
}
#endif // _LP64
void ArchiveBuilder::relocate_to_requested() {
! ro_region()->pack();
size_t my_archive_size = buffer_top() - buffer_bottom();
if (CDSConfig::is_dumping_static_archive()) {
_requested_static_archive_top = _requested_static_archive_bottom + my_archive_size;
return UseCompactObjectHeaders ? CompressedKlassPointers::max_shift() : 0;
}
#endif // _LP64
void ArchiveBuilder::relocate_to_requested() {
! if (!ro_region()->is_packed()) {
+ ro_region()->pack();
+ }
size_t my_archive_size = buffer_top() - buffer_bottom();
if (CDSConfig::is_dumping_static_archive()) {
_requested_static_archive_top = _requested_static_archive_bottom + my_archive_size;
static void log_heap_roots() {
LogStreamHandle(Trace, cds, map, oops) st;
if (st.is_enabled()) {
for (int i = 0; i < HeapShared::pending_roots()->length(); i++) {
st.print("roots[%4d]: ", i);
! print_oop_info_cr(&st, HeapShared::pending_roots()->at(i));
}
}
}
// Example output:
static void log_heap_roots() {
LogStreamHandle(Trace, cds, map, oops) st;
if (st.is_enabled()) {
for (int i = 0; i < HeapShared::pending_roots()->length(); i++) {
st.print("roots[%4d]: ", i);
! print_oop_info_cr(&st, HeapShared::pending_roots()->at(i).resolve());
}
}
}
// Example output:
st->print("%s", source_oop->klass()->external_name());
if (java_lang_String::is_instance(source_oop)) {
st->print(" ");
java_lang_String::print(source_oop, st);
+ } else if (java_lang_invoke_MethodType::is_instance(source_oop)) {
+ st->print(" ");
+ java_lang_invoke_MethodType::print_signature(source_oop, st);
} else if (java_lang_Class::is_instance(source_oop)) {
oop scratch_mirror = source_oop;
st->print(" ");
print_class_signature_for_mirror(st, scratch_mirror);
// MetaspaceShared::n_regions (internal to hotspot).
assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity");
write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
// Split pointer map into read-write and read-only bitmaps
! ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap);
size_t bitmap_size_in_bytes;
! char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::rw_ptrmap(), ArchivePtrMarker::ro_ptrmap(), heap_info,
bitmap_size_in_bytes);
if (heap_info->is_used()) {
_total_heap_region_size = mapinfo->write_heap_region(heap_info);
}
// MetaspaceShared::n_regions (internal to hotspot).
assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity");
write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
+ write_region(mapinfo, MetaspaceShared::cc, &_cc_region, /*read_only=*/false,/*allow_exec=*/false);
// Split pointer map into read-write and read-only bitmaps
! ArchivePtrMarker::initialize_rw_ro_cc_maps(&_rw_ptrmap, &_ro_ptrmap, &_cc_ptrmap);
size_t bitmap_size_in_bytes;
! char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::rw_ptrmap(),
+ ArchivePtrMarker::ro_ptrmap(),
+ ArchivePtrMarker::cc_ptrmap(),
+ heap_info,
bitmap_size_in_bytes);
if (heap_info->is_used()) {
_total_heap_region_size = mapinfo->write_heap_region(heap_info);
}
void ArchiveBuilder::write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, bool read_only, bool allow_exec) {
mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), read_only, allow_exec);
}
+ void ArchiveBuilder::count_relocated_pointer(bool tagged, bool nulled) {
+ _relocated_ptr_info._num_ptrs ++;
+ _relocated_ptr_info._num_tagged_ptrs += tagged ? 1 : 0;
+ _relocated_ptr_info._num_nulled_ptrs += nulled ? 1 : 0;
+ }
+
void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* heap_info) {
// Print statistics of all the regions
const size_t bitmap_used = mapinfo->region_at(MetaspaceShared::bm)->used();
const size_t bitmap_reserved = mapinfo->region_at(MetaspaceShared::bm)->used_aligned();
const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
_total_heap_region_size;
const double total_u_perc = percent_of(total_bytes, total_reserved);
_rw_region.print(total_reserved);
_ro_region.print(total_reserved);
+ _cc_region.print(total_reserved);
print_bitmap_region_stats(bitmap_used, total_reserved);
if (heap_info->is_used()) {
print_heap_region_stats(heap_info, total_reserved);
< prev index next >