< prev index next > src/hotspot/share/cds/archiveBuilder.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
+ #include "cds/aotClassLinker.hpp"
+ #include "cds/aotLinkedClassBulkLoader.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveHeapWriter.hpp"
#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/classLoaderExt.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "oops/compressedKlass.inline.hpp"
#include "oops/instanceKlass.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"
_mapped_static_archive_bottom(nullptr),
_mapped_static_archive_top(nullptr),
_buffer_to_requested_delta(0),
_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),
if (ref->msotype() == MetaspaceObj::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (!is_excluded(klass)) {
_klasses->append(klass);
+ if (klass->is_hidden() && klass->is_instance_klass()) {
+ update_hidden_class_loader_type(InstanceKlass::cast(klass));
+ }
}
// See RunTimeClassInfo::get_for()
_estimated_metaspaceobj_bytes += align_up(BytesPerWord, SharedSpaceObjectAlignment);
} else if (ref->msotype() == MetaspaceObj::SymbolType) {
// Make sure the symbol won't be GC'ed while we are dumping the archive.
// TODO -- we need a proper estimate for the archived modules, etc,
// but this should be enough for now
_estimated_metaspaceobj_bytes += 200 * 1024 * 1024;
}
+
+ AOTClassLinker::add_candidates();
}
+ #if INCLUDE_CDS_JAVA_HEAP
+
+ void ArchiveBuilder::update_hidden_class_loader_type(InstanceKlass* ik) {
+ s2 classloader_type;
+ if (HeapShared::is_lambda_form_klass(ik)) {
+ assert(CDSConfig::is_dumping_invokedynamic(), "lambda form classes are archived only if CDSConfig::is_dumping_invokedynamic() is true");
+ classloader_type = ClassLoader::BOOT_LOADER;
+ } else if (SystemDictionaryShared::should_hidden_class_be_archived(ik)) {
+ oop loader = ik->class_loader();
+
+ if (loader == nullptr) {
+ classloader_type = ClassLoader::BOOT_LOADER;
+ } else if (SystemDictionary::is_platform_class_loader(loader)) {
+ classloader_type = ClassLoader::PLATFORM_LOADER;
+ } else if (SystemDictionary::is_system_class_loader(loader)) {
+ classloader_type = ClassLoader::APP_LOADER;
+ } else {
+ ShouldNotReachHere();
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+
+ ik->set_shared_class_loader_type(classloader_type);
+ if (HeapShared::is_lambda_proxy_klass(ik)) {
+ InstanceKlass* nest_host = ik->nest_host_not_null();
+ ik->set_shared_classpath_index(nest_host->shared_classpath_index());
+ } else if (!HeapShared::is_lambda_form_klass(ik)) {
+ // Injected invoker classes: fake this for now. Probably not needed!
+ if (classloader_type == ClassLoader::APP_LOADER) {
+ ik->set_shared_classpath_index(ClassLoaderExt::app_class_paths_start_index()); // HACK
+ } else {
+ ik->set_shared_classpath_index(0);
+ }
+ }
+ }
+
+ #endif //INCLUDE_CDS_JAVA_HEAP
+
int ArchiveBuilder::compare_symbols_by_address(Symbol** a, Symbol** b) {
if (a[0] < b[0]) {
return -1;
} else {
assert(a[0] > b[0], "Duplicated symbol %s unexpected", (*a)->as_C_string());
size_t ArchiveBuilder::estimate_archive_size() {
// size of the symbol table and two dictionaries, plus the RunTimeClassInfo's
size_t symbol_table_est = SymbolTable::estimate_size_for_archive();
size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive();
- _estimated_hashtable_bytes = symbol_table_est + dictionary_est;
+ size_t training_data_est = TrainingData::estimate_size_for_archive();
+ _estimated_hashtable_bytes = symbol_table_est + dictionary_est + training_data_est;
+ if (CDSConfig::is_dumping_aot_linked_classes()) {
+ _estimated_hashtable_bytes += _klasses->length() * 16 * sizeof(Klass*);
+ }
+
+ if (CDSConfig::is_dumping_final_static_archive()) {
+ _estimated_hashtable_bytes += 200 * 1024 * 1024; // FIXME -- need to iterate archived symbols??
+ }
+
+ if (CDSConfig::is_dumping_dynamic_archive()) {
+ // Some extra space for traning data. Be generous. Unused areas will be trimmed from the archive file.
+ _estimated_hashtable_bytes += 200 * 1024 * 1024;
+ }
size_t total = 0;
total += _estimated_metaspaceobj_bytes;
total += _estimated_hashtable_bytes;
bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read_only) {
address src_obj = ref->obj();
if (src_obj == nullptr) {
return false;
}
+
+ remember_embedded_pointer_in_enclosing_obj(ref);
if (RegeneratedClasses::has_been_regenerated(src_obj)) {
// No need to copy it. We will later relocate it to point to the regenerated klass/method.
return false;
}
- remember_embedded_pointer_in_enclosing_obj(ref);
FollowMode follow_mode = get_follow_mode(ref);
SourceObjInfo src_info(ref, read_only, follow_mode);
bool created;
SourceObjInfo* p = _src_obj_table.put_if_absent(src_obj, src_info, &created);
if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);
return SystemDictionaryShared::is_excluded_class(ik);
} else if (klass->is_objArray_klass()) {
Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass();
- if (MetaspaceShared::is_shared_static(bottom)) {
+ if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_shared_static(bottom)) {
// The bottom class is in the static archive so it's clearly not excluded.
assert(CDSConfig::is_dumping_dynamic_archive(), "sanity");
return false;
} else if (bottom->is_instance_klass()) {
return SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(bottom));
return false;
}
ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) {
address obj = ref->obj();
- if (MetaspaceShared::is_in_shared_metaspace(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;
+ 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::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;
log_info(cds)("Relocating embedded pointers in core regions ... ");
relocate_embedded_pointers(&_rw_src_objs);
relocate_embedded_pointers(&_ro_src_objs);
}
+ #define ADD_COUNT(x) \
+ x += 1; \
+ x ## _a += aotlinked; \
+ x ## _i += inited;
+
+ #define DECLARE_INSTANCE_KLASS_COUNTER(x) \
+ int x = 0; \
+ int x ## _a = 0; \
+ int x ## _i = 0;
+
void ArchiveBuilder::make_klasses_shareable() {
- int num_instance_klasses = 0;
- int num_boot_klasses = 0;
- int num_platform_klasses = 0;
- int num_app_klasses = 0;
- int num_hidden_klasses = 0;
- int num_unlinked_klasses = 0;
- int num_unregistered_klasses = 0;
+ DECLARE_INSTANCE_KLASS_COUNTER(num_instance_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_boot_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_vm_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_platform_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_app_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_hidden_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_unlinked_klasses);
+ DECLARE_INSTANCE_KLASS_COUNTER(num_unregistered_klasses);
int num_obj_array_klasses = 0;
int num_type_array_klasses = 0;
+ int boot_unlinked = 0;
+ int platform_unlinked = 0;
+ int app_unlinked = 0;
+ int unreg_unlinked = 0;
+
for (int i = 0; i < klasses()->length(); i++) {
// Some of the code in ConstantPool::remove_unshareable_info() requires the classes
// to be in linked state, so it must be call here before the next loop, which returns
// all classes to unlinked state.
Klass* k = get_buffered_addr(klasses()->at(i));
}
for (int i = 0; i < klasses()->length(); i++) {
const char* type;
const char* unlinked = "";
+ const char* kind = "";
const char* hidden = "";
const char* generated = "";
+ const char* aotlinked_msg = "";
+ const char* inited_msg = "";
Klass* k = get_buffered_addr(klasses()->at(i));
k->remove_java_mirror();
if (k->is_objArray_klass()) {
// InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
// on their array classes.
num_type_array_klasses ++;
type = "array";
k->remove_unshareable_info();
} else {
assert(k->is_instance_klass(), " must be");
- num_instance_klasses ++;
InstanceKlass* ik = InstanceKlass::cast(k);
- if (ik->is_shared_boot_class()) {
+ InstanceKlass* src_ik = get_source_addr(ik);
+ int aotlinked = AOTClassLinker::is_candidate(src_ik);
+ int inited = ik->has_preinitialized_mirror();
+ ADD_COUNT(num_instance_klasses);
+ if (CDSConfig::is_dumping_dynamic_archive()) {
+ // For static dump, class loader type are already set.
+ ik->assign_class_loader_type();
+ }
+ if (ik->is_hidden()) {
+ oop loader = k->class_loader();
+ if (loader == nullptr) {
+ type = "boot";
+ ADD_COUNT(num_boot_klasses);
+ } else if (loader == SystemDictionary::java_platform_loader()) {
+ type = "plat";
+ ADD_COUNT(num_platform_klasses);
+ } else if (loader == SystemDictionary::java_system_loader()) {
+ type = "app";
+ ADD_COUNT(num_app_klasses);
+ } else {
+ type = "bad";
+ assert(0, "shouldn't happen");
+ }
+ } else if (ik->is_shared_boot_class()) {
type = "boot";
- num_boot_klasses ++;
+ ADD_COUNT(num_boot_klasses);
} else if (ik->is_shared_platform_class()) {
type = "plat";
- num_platform_klasses ++;
+ ADD_COUNT(num_platform_klasses);
} else if (ik->is_shared_app_class()) {
type = "app";
- num_app_klasses ++;
+ ADD_COUNT(num_app_klasses);
} else {
assert(ik->is_shared_unregistered_class(), "must be");
type = "unreg";
- num_unregistered_klasses ++;
+ ADD_COUNT(num_unregistered_klasses);
+ }
+
+ if (AOTClassLinker::is_vm_class(src_ik)) {
+ ADD_COUNT(num_vm_klasses);
}
if (!ik->is_linked()) {
- num_unlinked_klasses ++;
- unlinked = " ** unlinked";
+ ADD_COUNT(num_unlinked_klasses);
+ unlinked = " unlinked";
+ if (ik->is_shared_boot_class()) {
+ boot_unlinked ++;
+ } else if (ik->is_shared_platform_class()) {
+ platform_unlinked ++;
+ } else if (ik->is_shared_app_class()) {
+ app_unlinked ++;
+ } else {
+ unreg_unlinked ++;
+ }
+ }
+
+ if (ik->is_interface()) {
+ kind = " interface";
+ } else if (src_ik->java_super() == vmClasses::Enum_klass()) {
+ kind = " enum";
}
if (ik->is_hidden()) {
- num_hidden_klasses ++;
- hidden = " ** hidden";
+ ADD_COUNT(num_hidden_klasses);
+ hidden = " hidden";
}
if (ik->is_generated_shared_class()) {
- generated = " ** generated";
+ generated = " generated";
+ }
+ if (aotlinked) {
+ aotlinked_msg = " aot-linked";
}
+ if (inited) {
+ inited_msg = " inited";
+ }
+
MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
ik->remove_unshareable_info();
}
if (log_is_enabled(Debug, cds, class)) {
ResourceMark rm;
- log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s%s", i,
+ log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s%s%s%s%s", i,
p2i(to_requested(k)), type, k->external_name(),
- hidden, unlinked, generated);
+ kind, hidden, unlinked, generated, aotlinked_msg, inited_msg);
}
}
+ #define STATS_FORMAT "= %5d, aot-linked = %5d, inited = %5d"
+ #define STATS_PARAMS(x) num_ ## x, num_ ## x ## _a, num_ ## x ## _i
+
log_info(cds)("Number of classes %d", num_instance_klasses + num_obj_array_klasses + num_type_array_klasses);
- log_info(cds)(" instance classes = %5d", num_instance_klasses);
- log_info(cds)(" boot = %5d", num_boot_klasses);
- log_info(cds)(" app = %5d", num_app_klasses);
- log_info(cds)(" platform = %5d", num_platform_klasses);
- log_info(cds)(" unregistered = %5d", num_unregistered_klasses);
- log_info(cds)(" (hidden) = %5d", num_hidden_klasses);
- log_info(cds)(" (unlinked) = %5d", num_unlinked_klasses);
+ log_info(cds)(" instance classes " STATS_FORMAT, STATS_PARAMS(instance_klasses));
+ log_info(cds)(" boot " STATS_FORMAT, STATS_PARAMS(boot_klasses));
+ log_info(cds)(" vm " STATS_FORMAT, STATS_PARAMS(vm_klasses));
+ log_info(cds)(" platform " STATS_FORMAT, STATS_PARAMS(platform_klasses));
+ log_info(cds)(" app " STATS_FORMAT, STATS_PARAMS(app_klasses));
+ log_info(cds)(" unregistered " STATS_FORMAT, STATS_PARAMS(unregistered_klasses));
+ log_info(cds)(" (hidden) " STATS_FORMAT, STATS_PARAMS(hidden_klasses));
+ log_info(cds)(" (unlinked) " STATS_FORMAT ", boot = %d, plat = %d, app = %d, unreg = %d",
+ STATS_PARAMS(unlinked_klasses),
+ boot_unlinked, platform_unlinked,
+ app_unlinked, unreg_unlinked);
log_info(cds)(" obj array classes = %5d", num_obj_array_klasses);
log_info(cds)(" type array classes = %5d", num_type_array_klasses);
log_info(cds)(" symbols = %5d", _symbols->length());
+ #undef STATS_FORMAT
+ #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);
+ FinalImageRecipes::serialize(soc, false);
+ TrainingData::serialize_training_data(soc);
}
uintx ArchiveBuilder::buffer_to_offset(address p) const {
address requested_p = to_requested(p);
assert(requested_p >= _requested_static_archive_bottom, "must be");
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();
+ }
+
#if INCLUDE_CDS_JAVA_HEAP
narrowKlass ArchiveBuilder::get_requested_narrow_klass(Klass* k) {
assert(CDSConfig::is_dumping_heap(), "sanity");
k = get_buffered_klass(k);
Klass* requested_k = to_requested(k);
}
};
void ArchiveBuilder::relocate_to_requested() {
- ro_region()->pack();
+ 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;
}
} else {
st.print_cr(" - fields (" SIZE_FORMAT " words):", source_oop->size());
ArchivedFieldPrinter print_field(heap_info, &st, source_oop, buffered_addr);
InstanceKlass::cast(source_klass)->print_nonstatic_fields(&print_field);
+
+ if (java_lang_Class::is_instance(source_oop)) {
+ st.print(" - signature: ");
+ if (java_lang_Class::is_primitive(source_oop)) {
+ st.print("primitive ??");
+ } else {
+ java_lang_Class::print_signature(source_oop, &st);
+ }
+ st.cr();
+ }
}
}
}
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_with_requested_addr_cr(&st, HeapShared::pending_roots()->at(i));
+ print_oop_with_requested_addr_cr(&st, HeapShared::pending_roots()->at(i).resolve());
}
}
}
// The output looks like this. The first number is the requested address. The second number is
}
if (source_oop->is_array()) {
int array_len = arrayOop(source_oop)->length();
st->print_cr("%s length: %d", source_oop->klass()->external_name(), array_len);
} else {
- st->print_cr("%s", source_oop->klass()->external_name());
+ st->print("%s", source_oop->klass()->external_name());
+ if (java_lang_invoke_MethodType::is_instance(source_oop)) {
+ st->print(" ");
+ java_lang_invoke_MethodType::print_signature(source_oop, st);
+ }
+ st->cr();
}
}
}
#endif // INCLUDE_CDS_JAVA_HEAP
// 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=*/true);
// Split pointer map into read-write and read-only bitmaps
- ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap);
+ 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(), heap_info,
+ 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);
}
_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 >