--- a/src/hotspot/share/memory/dynamicArchive.cpp Thu Nov 14 10:02:52 2019 +0800
+++ b/src/hotspot/share/memory/dynamicArchive.cpp Wed Nov 13 16:36:54 2019 -0800
@@ -29,12 +29,13 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "logging/log.hpp"
+#include "memory/archiveUtils.inline.hpp"
+#include "memory/dynamicArchive.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
-#include "memory/dynamicArchive.hpp"
#include "oops/compressedOops.hpp"
#include "oops/objArrayKlass.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
@@ -50,7 +51,6 @@
#endif
class DynamicArchiveBuilder : ResourceObj {
- CHeapBitMap _ptrmap;
static unsigned my_hash(const address& a) {
return primitive_hash<address>(a);
}
@@ -64,7 +64,7 @@
16384, ResourceObj::C_HEAP> RelocationTable;
RelocationTable _new_loc_table;
- intx _buffer_to_target_delta;
+ static intx _buffer_to_target_delta;
DumpRegion* _current_dump_space;
@@ -77,10 +77,7 @@
public:
void mark_pointer(address* ptr_loc) {
- if (is_in_buffer_space(ptr_loc)) {
- size_t idx = pointer_delta(ptr_loc, _alloc_bottom, sizeof(address));
- _ptrmap.set_bit(idx);
- }
+ ArchivePtrMarker::mark_pointer(ptr_loc);
}
DumpRegion* current_dump_space() const {
@@ -128,6 +125,28 @@
return pp != NULL;
}
+ static int dynamic_dump_method_comparator(Method* a, Method* b) {
+ Symbol* a_name = a->name();
+ Symbol* b_name = b->name();
+
+ if (a_name == b_name) {
+ return 0;
+ }
+
+ if (!MetaspaceShared::is_in_shared_metaspace(a_name)) {
+ // a_name points to a Symbol in the top archive.
+ // When this method is called, a_name is still pointing to the output space.
+ // Translate it to point to the output space, so that it can be compared with
+ // Symbols in the base archive.
+ a_name = (Symbol*)(address(a_name) + _buffer_to_target_delta);
+ }
+ if (!MetaspaceShared::is_in_shared_metaspace(b_name)) {
+ b_name = (Symbol*)(address(b_name) + _buffer_to_target_delta);
+ }
+
+ return a_name->fast_compare(b_name);
+ }
+
protected:
enum FollowMode {
make_a_copy, point_to_it, set_to_null
@@ -240,6 +259,16 @@
return true; // keep recursing until every object is visited exactly once.
}
+
+ virtual void push_special(SpecialRef type, Ref* ref, intptr_t* p) {
+ assert(type == _method_entry_ref, "only special type allowed for now");
+ address obj = ref->obj();
+ address new_obj = _builder->get_new_loc(ref);
+ size_t offset = pointer_delta(p, obj, sizeof(u1));
+ intptr_t* new_p = (intptr_t*)(new_obj + offset);
+ assert(*p == *new_p, "must be a copy");
+ ArchivePtrMarker::mark_pointer((address*)new_p);
+ }
};
class EmbeddedRefUpdater: public MetaspaceClosure {
@@ -331,7 +360,7 @@
public:
EmbeddedRefMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
virtual bool do_ref(Ref* ref, bool read_only) {
- if (ref->not_null() && _builder->is_in_buffer_space(ref->obj())) {
+ if (ref->not_null()) {
_builder->mark_pointer(ref->addr());
}
return false; // Do not recurse.
@@ -441,10 +470,10 @@
p2i(obj), p2i(p), bytes,
MetaspaceObj::type_name(ref->msotype()));
memcpy(p, obj, bytes);
-
intptr_t* cloned_vtable = MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(ref->msotype(), p);
if (cloned_vtable != NULL) {
update_pointer((address*)p, (address)cloned_vtable, "vtb", 0, /*is_mso_pointer*/false);
+ mark_pointer((address*)p);
}
return (address)p;
@@ -551,6 +580,9 @@
address reserved_bottom = reserve_space_and_init_buffer_to_target_delta();
init_header(reserved_bottom);
+ CHeapBitMap ptrmap;
+ ArchivePtrMarker::initialize(&ptrmap, (address*)reserved_bottom, (address*)current_dump_space()->top());
+
verify_estimate_size(sizeof(DynamicArchiveHeader), "header");
log_info(cds, dynamic)("Copying %d klasses and %d symbols",
@@ -576,10 +608,6 @@
iterate_roots(&ro_copier);
}
- size_t bitmap_size = pointer_delta(current_dump_space()->top(),
- _alloc_bottom, sizeof(address));
- _ptrmap.initialize(bitmap_size);
-
{
log_info(cds)("Relocating embedded pointers ... ");
ResourceMark rm;
@@ -653,7 +681,7 @@
it->push(&_symbols->at(i));
}
- _header->shared_path_table_metaspace_pointers_do(it);
+ FileMapInfo::metaspace_pointers_do(it);
// Do not call these again, as we have already collected all the classes and symbols
// that we want to archive. Also, these calls would corrupt the tables when
@@ -666,6 +694,9 @@
}
};
+intx DynamicArchiveBuilder::_buffer_to_target_delta;
+
+
size_t DynamicArchiveBuilder::estimate_archive_size() {
// size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's
_estimated_hashtable_bytes = 0;
@@ -688,26 +719,16 @@
address DynamicArchiveBuilder::reserve_space_and_init_buffer_to_target_delta() {
size_t total = estimate_archive_size();
- bool large_pages = false; // No large pages when dumping the CDS archive.
- size_t increment = align_up(1*G, reserve_alignment());
- char* addr = (char*)align_up(CompressedKlassPointers::base() + MetaspaceSize + increment,
- reserve_alignment());
-
- ReservedSpace* rs = MetaspaceShared::reserve_shared_rs(
- total, reserve_alignment(), large_pages, addr);
- while (!rs->is_reserved() && (addr + increment > addr)) {
- addr += increment;
- rs = MetaspaceShared::reserve_shared_rs(
- total, reserve_alignment(), large_pages, addr);
- }
- if (!rs->is_reserved()) {
+ ReservedSpace rs = MetaspaceShared::reserve_shared_space(total);
+ if (!rs.is_reserved()) {
log_error(cds, dynamic)("Failed to reserve %d bytes of output buffer.", (int)total);
vm_direct_exit(0);
}
- address buffer_base = (address)rs->base();
+ address buffer_base = (address)rs.base();
log_info(cds, dynamic)("Reserved output buffer space at : " PTR_FORMAT " [%d bytes]",
p2i(buffer_base), (int)total);
+ MetaspaceShared::set_shared_rs(rs);
// At run time, we will mmap the dynamic archive at target_space_bottom.
// However, at dump time, we may not be able to write into the target_space,
@@ -788,6 +809,7 @@
void DynamicArchiveBuilder::make_klasses_shareable() {
int i, count = _klasses->length();
+ InstanceKlass::disable_method_binary_search();
for (i = 0; i < count; i++) {
InstanceKlass* ik = _klasses->at(i);
sort_methods(ik);
@@ -847,18 +869,24 @@
}
#ifdef ASSERT
- {
+ if (ik->methods() != NULL) {
for (int m = 0; m < ik->methods()->length(); m++) {
Symbol* name = ik->methods()->at(m)->name();
assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
}
}
+ if (ik->default_methods() != NULL) {
+ for (int m = 0; m < ik->default_methods()->length(); m++) {
+ Symbol* name = ik->default_methods()->at(m)->name();
+ assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
+ }
+ }
#endif
Thread* THREAD = Thread::current();
- Method::sort_methods(ik->methods());
+ Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);
if (ik->default_methods() != NULL) {
- Method::sort_methods(ik->default_methods(), /*set_idnums=*/false);
+ Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);
}
ik->vtable().initialize_vtable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
ik->itable().initialize_itable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
@@ -902,14 +930,60 @@
}
};
-
void DynamicArchiveBuilder::relocate_buffer_to_target() {
RelocateBufferToTarget patcher(this, (address*)_alloc_bottom, _buffer_to_target_delta);
- _ptrmap.iterate(&patcher);
+ ArchivePtrMarker::ptrmap()->iterate(&patcher);
+
+ Array<u8>* table = FileMapInfo::shared_path_table().table();
+ SharedPathTable runtime_table(to_target(table), FileMapInfo::shared_path_table().size());
+ _header->set_shared_path_table(runtime_table);
+
+ address relocatable_base = (address)SharedBaseAddress;
+ address relocatable_end = (address)(current_dump_space()->top()) + _buffer_to_target_delta;
+
+ intx addr_delta = MetaspaceShared::final_delta();
+ if (addr_delta == 0) {
+ ArchivePtrMarker::compact(relocatable_base, relocatable_end);
+ } else {
+ // The base archive is NOT mapped at Arguments::default_SharedBaseAddress() (due to ASLR).
+ // This means that the current content of the dynamic archive is based on a random
+ // address. Let's relocate all the pointers, so that it can be mapped to
+ // Arguments::default_SharedBaseAddress() without runtime relocation.
+ //
+ // Note: both the base and dynamic archive are written with
+ // FileMapHeader::_shared_base_address == Arguments::default_SharedBaseAddress()
+
+ // Patch all pointers that are marked by ptrmap within this region,
+ // where we have just dumped all the metaspace data.
+ address patch_base = (address)_alloc_bottom;
+ address patch_end = (address)current_dump_space()->top();
- Array<u8>* table = _header->shared_path_table().table();
- table = to_target(table);
- _header->relocate_shared_path_table(table);
+ // the current value of the pointers to be patched must be within this
+ // range (i.e., must point to either the top archive (as currently mapped), or to the
+ // (targeted address of) the top archive)
+ address valid_old_base = relocatable_base;
+ address valid_old_end = relocatable_end;
+ size_t base_plus_top_size = valid_old_end - valid_old_base;
+ size_t top_size = patch_end - patch_base;
+ size_t base_size = base_plus_top_size - top_size;
+ assert(base_plus_top_size > base_size, "no overflow");
+ assert(base_plus_top_size > top_size, "no overflow");
+
+ // after patching, the pointers must point inside this range
+ // (the requested location of the archive, as mapped at runtime).
+ address valid_new_base = (address)Arguments::default_SharedBaseAddress();
+ address valid_new_end = valid_new_base + base_plus_top_size;
+
+ log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to "
+ "[" INTPTR_FORMAT " - " INTPTR_FORMAT "], delta = " INTX_FORMAT " bytes",
+ p2i(patch_base + base_size), p2i(patch_end),
+ p2i(valid_new_base + base_size), p2i(valid_new_end), addr_delta);
+
+ SharedDataRelocator<true> patcher((address*)patch_base, (address*)patch_end, valid_old_base, valid_old_end,
+ valid_new_base, valid_new_end, addr_delta, ArchivePtrMarker::ptrmap());
+ ArchivePtrMarker::ptrmap()->iterate(&patcher);
+ ArchivePtrMarker::compact(patcher.max_non_null_offset());
+ }
}
void DynamicArchiveBuilder::write_regions(FileMapInfo* dynamic_info) {
@@ -925,6 +999,7 @@
MetaspaceShared::misc_code_dump_space()->base(),
MetaspaceShared::misc_code_dump_space()->used(),
/*read_only=*/false,/*allow_exec=*/true);
+ dynamic_info->write_bitmap_region(ArchivePtrMarker::ptrmap());
}
void DynamicArchiveBuilder::write_archive(char* serialized_data_start) {
@@ -940,6 +1015,7 @@
const char* archive_name = Arguments::GetSharedDynamicArchivePath();
dynamic_info->open_for_write(archive_name);
write_regions(dynamic_info);
+ dynamic_info->set_final_requested_base((char*)Arguments::default_SharedBaseAddress());
dynamic_info->set_header_crc(dynamic_info->compute_header_crc());
dynamic_info->write_header();
dynamic_info->close();
@@ -948,6 +1024,8 @@
address top = address(current_dump_space()->top()) + _buffer_to_target_delta;
size_t file_size = pointer_delta(top, base, sizeof(char));
+ base += MetaspaceShared::final_delta();
+ top += MetaspaceShared::final_delta();
log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT
" [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",
p2i(base), p2i(top), _header->header_size(), file_size);
@@ -1036,79 +1114,8 @@
}
-static DynamicArchiveHeader *_dynamic_header = NULL;
DynamicArchiveBuilder* DynamicArchive::_builder = NULL;
-void DynamicArchive::map_failed(FileMapInfo* mapinfo) {
- if (mapinfo->dynamic_header() != NULL) {
- os::free((void*)mapinfo->dynamic_header());
- }
- delete mapinfo;
-}
-
-// Returns the top of the mapped address space
-address DynamicArchive::map() {
- assert(UseSharedSpaces, "Sanity");
-
- // Create the dynamic archive map info
- FileMapInfo* mapinfo;
- const char* filename = Arguments::GetSharedDynamicArchivePath();
- struct stat st;
- address result;
- if ((filename != NULL) && (os::stat(filename, &st) == 0)) {
- mapinfo = new FileMapInfo(false);
- if (!mapinfo->open_for_read(filename)) {
- result = NULL;
- }
- result = map_impl(mapinfo);
- if (result == NULL) {
- map_failed(mapinfo);
- mapinfo->restore_shared_path_table();
- }
- } else {
- if (filename != NULL) {
- log_warning(cds, dynamic)("specified dynamic archive doesn't exist: %s", filename);
- }
- result = NULL;
- }
- return result;
-}
-
-address DynamicArchive::map_impl(FileMapInfo* mapinfo) {
- // Read header
- if (!mapinfo->initialize(false)) {
- return NULL;
- }
-
- _dynamic_header = mapinfo->dynamic_header();
- int regions[] = {MetaspaceShared::rw,
- MetaspaceShared::ro,
- MetaspaceShared::mc};
-
- size_t len = sizeof(regions)/sizeof(int);
- char* saved_base[] = {NULL, NULL, NULL};
- char* top = mapinfo->map_regions(regions, saved_base, len);
- if (top == NULL) {
- mapinfo->unmap_regions(regions, saved_base, len);
- FileMapInfo::fail_continue("Unable to use dynamic archive. Failed map_region for using -Xshare:on.");
- return NULL;
- }
-
- if (!validate(mapinfo)) {
- return NULL;
- }
-
- if (_dynamic_header == NULL) {
- return NULL;
- }
-
- intptr_t* buffer = (intptr_t*)_dynamic_header->serialized_data_start();
- ReadClosure rc(&buffer);
- SymbolTable::serialize_shared_table_header(&rc, false);
- SystemDictionaryShared::serialize_dictionary_headers(&rc, false);
-
- return (address)top;
-}
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
// Check if the recorded base archive matches with the current one
@@ -1136,11 +1143,3 @@
}
return true;
}
-
-bool DynamicArchive::is_mapped() {
- return (_dynamic_header != NULL);
-}
-
-void DynamicArchive::disable() {
- _dynamic_header = NULL;
-}