8261480: MetaspaceShared::preload_and_dump should check exceptions

Reviewed-by: dholmes, ccheung
This commit is contained in:
Ioi Lam 2021-03-18 04:15:58 +00:00
parent 81ba5784ba
commit 2b93ae0019
13 changed files with 263 additions and 262 deletions

View File

@ -92,6 +92,61 @@ ClassListParser::~ClassListParser() {
_instance = NULL; _instance = NULL;
} }
int ClassListParser::parse(TRAPS) {
int class_count = 0;
while (parse_one_line()) {
if (lambda_form_line()) {
// The current line is "@lambda-form-invoker ...". It has been recorded in LambdaFormInvokers,
// and will be processed later.
continue;
}
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
if (_indy_items->length() > 0) {
// The current line is "@lambda-proxy class_name". Load the proxy class.
resolve_indy(THREAD, class_name_symbol);
class_count++;
continue;
}
Klass* klass = load_current_class(class_name_symbol, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
// If we have run out of memory, don't try to load the rest of the classes in
// the classlist. Throw an exception, which will terminate the dumping process.
return 0; // THROW
}
// We might have an invalid class name or an bad class. Warn about it
// and keep going to the next line.
CLEAR_PENDING_EXCEPTION;
log_warning(cds)("Preload Warning: Cannot find %s", _class_name);
continue;
}
assert(klass != NULL, "sanity");
if (log_is_enabled(Trace, cds)) {
ResourceMark rm(THREAD);
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
}
if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);
// Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created. The linking is done as soon as classes
// are loaded in order that the related data structures (klass and
// cpCache) are located together.
MetaspaceShared::try_link_class(THREAD, ik);
}
class_count++;
}
return class_count;
}
bool ClassListParser::parse_one_line() { bool ClassListParser::parse_one_line() {
for (;;) { for (;;) {
if (fgets(_line, sizeof(_line), _file) == NULL) { if (fgets(_line, sizeof(_line), _file) == NULL) {
@ -398,30 +453,27 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
if (strncmp(_class_name, "java/", 5) == 0) { if (strncmp(_class_name, "java/", 5) == 0) {
log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s", log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
_class_name, _source); _class_name, _source);
return NULL; THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
} }
InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL); InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
if (k->local_interfaces()->length() != _interfaces->length()) {
if (k != NULL) { print_specified_interfaces();
if (k->local_interfaces()->length() != _interfaces->length()) { print_actual_interfaces(k);
print_specified_interfaces(); error("The number of interfaces (%d) specified in class list does not match the class file (%d)",
print_actual_interfaces(k); _interfaces->length(), k->local_interfaces()->length());
error("The number of interfaces (%d) specified in class list does not match the class file (%d)",
_interfaces->length(), k->local_interfaces()->length());
}
bool added = SystemDictionaryShared::add_unregistered_class(k, CHECK_NULL);
if (!added) {
// We allow only a single unregistered class for each unique name.
error("Duplicated class %s", _class_name);
}
// This tells JVM_FindLoadedClass to not find this class.
k->set_shared_classpath_index(UNREGISTERED_INDEX);
k->clear_shared_class_loader_type();
} }
bool added = SystemDictionaryShared::add_unregistered_class(k, CHECK_NULL);
if (!added) {
// We allow only a single unregistered class for each unique name.
error("Duplicated class %s", _class_name);
}
// This tells JVM_FindLoadedClass to not find this class.
k->set_shared_classpath_index(UNREGISTERED_INDEX);
k->clear_shared_class_loader_type();
return k; return k;
} }
@ -442,10 +494,8 @@ void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int
} else if (tag == JVM_CONSTANT_MethodHandle) { } else if (tag == JVM_CONSTANT_MethodHandle) {
cii->add_ref_kind(pool->method_handle_ref_kind_at(arg)); cii->add_ref_kind(pool->method_handle_ref_kind_at(arg));
int callee_index = pool->method_handle_klass_index_at(arg); int callee_index = pool->method_handle_klass_index_at(arg);
Klass* callee = pool->klass_at(callee_index, THREAD); Klass* callee = pool->klass_at(callee_index, CHECK);
if (callee != NULL) { cii->add_item(callee->name()->as_C_string());
cii->add_item(callee->name()->as_C_string());
}
cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string()); cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string());
cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string()); cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string());
} else { } else {
@ -458,7 +508,7 @@ void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int
bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) { bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
CDSIndyInfo cii; CDSIndyInfo cii;
populate_cds_indy_info(pool, cp_index, &cii, THREAD); populate_cds_indy_info(pool, cp_index, &cii, CHECK_0);
GrowableArray<const char*>* items = cii.items(); GrowableArray<const char*>* items = cii.items();
int indy_info_offset = 1; int indy_info_offset = 1;
if (_indy_items->length() - indy_info_offset != items->length()) { if (_indy_items->length() - indy_info_offset != items->length()) {
@ -471,10 +521,13 @@ bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_inde
} }
return true; return true;
} }
void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) {
void ClassListParser::resolve_indy(Thread* current, Symbol* class_name_symbol) {
ExceptionMark em(current);
Thread* THREAD = current; // For exception macros.
ClassListParser::resolve_indy_impl(class_name_symbol, THREAD); ClassListParser::resolve_indy_impl(class_name_symbol, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
ResourceMark rm(THREAD); ResourceMark rm(current);
char* ex_msg = (char*)""; char* ex_msg = (char*)"";
oop message = java_lang_Throwable::message(PENDING_EXCEPTION); oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
if (message != NULL) { if (message != NULL) {
@ -491,14 +544,14 @@ void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) {
void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {
Handle class_loader(THREAD, SystemDictionary::java_system_loader()); Handle class_loader(THREAD, SystemDictionary::java_system_loader());
Handle protection_domain; Handle protection_domain;
Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, CHECK); // FIXME should really be just a lookup Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, CHECK);
if (klass != NULL && klass->is_instance_klass()) { if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass); InstanceKlass* ik = InstanceKlass::cast(klass);
if (SystemDictionaryShared::has_class_failed_verification(ik)) { MetaspaceShared::try_link_class(THREAD, ik);
// don't attempt to resolve indy on classes that has previously failed verification if (!ik->is_linked()) {
// Verification of ik has failed
return; return;
} }
MetaspaceShared::try_link_class(ik, CHECK);
ConstantPool* cp = ik->constants(); ConstantPool* cp = ik->constants();
ConstantPoolCache* cpcache = cp->cache(); ConstantPoolCache* cpcache = cp->cache();
@ -538,15 +591,8 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {
} }
} }
Klass* ClassListParser::load_current_class(TRAPS) { Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPS) {
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name); Klass* klass;
if (_indy_items->length() > 0) {
resolve_indy(class_name_symbol, CHECK_NULL);
return NULL;
}
Klass* klass = NULL;
if (!is_loading_from_source()) { if (!is_loading_from_source()) {
// Load classes for the boot/platform/app loaders only. // Load classes for the boot/platform/app loaders only.
if (is_super_specified()) { if (is_super_specified()) {
@ -556,34 +602,29 @@ Klass* ClassListParser::load_current_class(TRAPS) {
error("If source location is not specified, interface(s) must not be specified"); error("If source location is not specified, interface(s) must not be specified");
} }
bool non_array = !Signature::is_array(class_name_symbol); if (Signature::is_array(class_name_symbol)) {
JavaValue result(T_OBJECT);
if (non_array) {
// At this point, we are executing in the context of the boot loader. We
// cannot call Class.forName because that is context dependent and
// would load only classes for the boot loader.
//
// Instead, let's call java_system_loader().loadClass() directly, which will
// delegate to the correct loader (boot, platform or app) depending on
// the class name.
Handle s = java_lang_String::create_from_symbol(class_name_symbol, CHECK_NULL);
// ClassLoader.loadClass() wants external class name format, i.e., convert '/' chars to '.'
Handle ext_class_name = java_lang_String::externalize_classname(s, CHECK_NULL);
Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
JavaCalls::call_virtual(&result,
loader, //SystemDictionary::java_system_loader(),
vmClasses::ClassLoader_klass(),
vmSymbols::loadClass_name(),
vmSymbols::string_class_signature(),
ext_class_name,
CHECK_NULL);
} else {
// array classes are not supported in class list. // array classes are not supported in class list.
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
} }
JavaValue result(T_OBJECT);
// Call java_system_loader().loadClass() directly, which will
// delegate to the correct loader (boot, platform or app) depending on
// the package name.
Handle s = java_lang_String::create_from_symbol(class_name_symbol, CHECK_NULL);
// ClassLoader.loadClass() wants external class name format, i.e., convert '/' chars to '.'
Handle ext_class_name = java_lang_String::externalize_classname(s, CHECK_NULL);
Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
JavaCalls::call_virtual(&result,
loader, //SystemDictionary::java_system_loader(),
vmClasses::ClassLoader_klass(),
vmSymbols::loadClass_name(),
vmSymbols::string_class_signature(),
ext_class_name,
CHECK_NULL);
assert(result.get_type() == T_OBJECT, "just checking"); assert(result.get_type() == T_OBJECT, "just checking");
oop obj = result.get_oop(); oop obj = result.get_oop();
assert(obj != NULL, "jdk.internal.loader.BuiltinClassLoader::loadClass never returns null"); assert(obj != NULL, "jdk.internal.loader.BuiltinClassLoader::loadClass never returns null");
@ -592,12 +633,12 @@ Klass* ClassListParser::load_current_class(TRAPS) {
// If "source:" tag is specified, all super class and super interfaces must be specified in the // If "source:" tag is specified, all super class and super interfaces must be specified in the
// class list file. // class list file.
klass = load_class_from_source(class_name_symbol, CHECK_NULL); klass = load_class_from_source(class_name_symbol, CHECK_NULL);
if (HAS_PENDING_EXCEPTION) {
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
}
} }
if (klass != NULL && klass->is_instance_klass() && is_id_specified()) { assert(klass != NULL, "exception should have been thrown");
assert(klass->is_instance_klass(), "array classes should have been filtered out");
if (is_id_specified()) {
InstanceKlass* ik = InstanceKlass::cast(klass); InstanceKlass* ik = InstanceKlass::cast(klass);
int id = this->id(); int id = this->id();
SystemDictionaryShared::update_shared_entry(ik, id); SystemDictionaryShared::update_shared_entry(ik, id);

View File

@ -116,8 +116,11 @@ class ClassListParser : public StackObj {
void print_actual_interfaces(InstanceKlass *ik); void print_actual_interfaces(InstanceKlass *ik);
bool is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS); bool is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS);
void resolve_indy(Symbol* class_name_symbol, TRAPS); void resolve_indy(Thread* current, Symbol* class_name_symbol);
void resolve_indy_impl(Symbol* class_name_symbol, TRAPS); void resolve_indy_impl(Symbol* class_name_symbol, TRAPS);
bool parse_one_line();
Klass* load_current_class(Symbol* class_name_symbol, TRAPS);
public: public:
ClassListParser(const char* file); ClassListParser(const char* file);
~ClassListParser(); ~ClassListParser();
@ -129,7 +132,7 @@ public:
return _instance; return _instance;
} }
bool parse_one_line(); int parse(TRAPS);
void split_tokens_by_whitespace(int offset); void split_tokens_by_whitespace(int offset);
int split_at_tag_from_line(); int split_at_tag_from_line();
bool parse_at_tags(); bool parse_at_tags();
@ -169,8 +172,6 @@ public:
return _class_name; return _class_name;
} }
Klass* load_current_class(TRAPS);
bool is_loading_from_source(); bool is_loading_from_source();
bool lambda_form_line() { return _lambda_form_line; } bool lambda_form_line() { return _lambda_form_line; }

View File

@ -1268,14 +1268,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
name, name,
loader_data, loader_data,
cl_info, cl_info,
THREAD); CHECK_NULL);
if (HAS_PENDING_EXCEPTION) {
if (DumpSharedSpaces) {
log_error(cds)("Preload Error: Failed to load %s", class_name);
}
return NULL;
}
result->set_classpath_index(classpath_index); result->set_classpath_index(classpath_index);
return result; return result;
} }

View File

@ -260,17 +260,17 @@ InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS)
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
const char* class_name = name->as_C_string(); const char* class_name = name->as_C_string();
const char* file_name = file_name_for_class_name(class_name, const char* file_name = file_name_for_class_name(class_name,
name->utf8_length()); name->utf8_length());
assert(file_name != NULL, "invariant"); assert(file_name != NULL, "invariant");
// Lookup stream for parsing .class file // Lookup stream for parsing .class file
ClassFileStream* stream = NULL; ClassFileStream* stream = NULL;
ClassPathEntry* e = find_classpath_entry_from_cache(path, CHECK_NULL); ClassPathEntry* e = find_classpath_entry_from_cache(THREAD, path);
if (e == NULL) { if (e == NULL) {
return NULL; THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
} }
{ {
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
THREAD->as_Java_thread()->get_thread_stat()->perf_timers_addr(), THREAD->as_Java_thread()->get_thread_stat()->perf_timers_addr(),
@ -278,29 +278,22 @@ InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS)
stream = e->open_stream(file_name, CHECK_NULL); stream = e->open_stream(file_name, CHECK_NULL);
} }
if (NULL == stream) { if (stream == NULL) {
log_warning(cds)("Preload Warning: Cannot find %s", class_name); // open_stream could return NULL even when no exception has be thrown (JDK-8263632).
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
return NULL; return NULL;
} }
assert(stream != NULL, "invariant");
stream->set_verify(true); stream->set_verify(true);
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain; Handle protection_domain;
ClassLoadInfo cl_info(protection_domain); ClassLoadInfo cl_info(protection_domain);
InstanceKlass* k = KlassFactory::create_from_stream(stream,
InstanceKlass* result = KlassFactory::create_from_stream(stream, name,
name, loader_data,
loader_data, cl_info,
cl_info, CHECK_NULL);
THREAD); return k;
if (HAS_PENDING_EXCEPTION) {
log_error(cds)("Preload Error: Failed to load %s", class_name);
return NULL;
}
return result;
} }
struct CachedClassPathEntry { struct CachedClassPathEntry {
@ -310,7 +303,7 @@ struct CachedClassPathEntry {
static GrowableArray<CachedClassPathEntry>* cached_path_entries = NULL; static GrowableArray<CachedClassPathEntry>* cached_path_entries = NULL;
ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path, TRAPS) { ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(Thread* current, const char* path) {
// This is called from dump time so it's single threaded and there's no need for a lock. // This is called from dump time so it's single threaded and there's no need for a lock.
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
if (cached_path_entries == NULL) { if (cached_path_entries == NULL) {
@ -336,7 +329,10 @@ ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path
} }
ClassPathEntry* new_entry = NULL; ClassPathEntry* new_entry = NULL;
new_entry = create_class_path_entry(path, &st, false, false, false, CHECK_NULL); ExceptionMark em(current);
Thread* THREAD = current; // For exception macros.
new_entry = create_class_path_entry(path, &st, /*throw_exception=*/false,
false, false, CATCH); // will never throw
if (new_entry == NULL) { if (new_entry == NULL) {
return NULL; return NULL;
} }

View File

@ -58,7 +58,7 @@ private:
static bool _has_platform_classes; static bool _has_platform_classes;
static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS); static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS);
static ClassPathEntry* find_classpath_entry_from_cache(const char* path, TRAPS); static ClassPathEntry* find_classpath_entry_from_cache(Thread* current, const char* path);
public: public:
static void process_jar_manifest(ClassPathEntry* entry, bool check_for_duplicates, TRAPS); static void process_jar_manifest(ClassPathEntry* entry, bool check_for_duplicates, TRAPS);

View File

@ -143,7 +143,7 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {
SystemDictionary::add_to_hierarchy(result); SystemDictionary::add_to_hierarchy(result);
} }
// new class not linked yet. // new class not linked yet.
MetaspaceShared::try_link_class(result, THREAD); MetaspaceShared::try_link_class(THREAD, result);
assert(!HAS_PENDING_EXCEPTION, "Invariant"); assert(!HAS_PENDING_EXCEPTION, "Invariant");
// exclude the existing class from dump // exclude the existing class from dump

View File

@ -348,12 +348,3 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
} }
} }
} }
void ArchiveUtils::check_for_oom(oop exception) {
assert(exception != nullptr, "Sanity check");
if (exception->is_a(vmClasses::OutOfMemoryError_klass())) {
vm_direct_exit(-1,
err_msg("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
SIZE_FORMAT "M", MaxHeapSize/M));
}
}

View File

@ -225,7 +225,6 @@ public:
class ArchiveUtils { class ArchiveUtils {
public: public:
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN; static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
static void check_for_oom(oop exception) NOT_CDS_RETURN;
}; };
#endif // SHARE_MEMORY_ARCHIVEUTILS_HPP #endif // SHARE_MEMORY_ARCHIVEUTILS_HPP

View File

@ -168,7 +168,7 @@ void HeapShared::reset_archived_object_states(TRAPS) {
log_debug(cds)("Resetting platform loader"); log_debug(cds)("Resetting platform loader");
reset_states(SystemDictionary::java_platform_loader(), CHECK); reset_states(SystemDictionary::java_platform_loader(), CHECK);
log_debug(cds)("Resetting system loader"); log_debug(cds)("Resetting system loader");
reset_states(SystemDictionary::java_system_loader(), THREAD); reset_states(SystemDictionary::java_system_loader(), CHECK);
} }
HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL; HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL;
@ -360,7 +360,6 @@ void HeapShared::copy_closed_archive_heap_objects(
GrowableArray<MemRegion> * closed_archive) { GrowableArray<MemRegion> * closed_archive) {
assert(is_heap_object_archiving_allowed(), "Cannot archive java heap objects"); assert(is_heap_object_archiving_allowed(), "Cannot archive java heap objects");
Thread* THREAD = Thread::current();
G1CollectedHeap::heap()->begin_archive_alloc_range(); G1CollectedHeap::heap()->begin_archive_alloc_range();
// Archive interned string objects // Archive interned string objects
@ -1244,25 +1243,17 @@ public:
}; };
void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
int num, Thread* THREAD) { int num, TRAPS) {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
ArchivableStaticFieldInfo* info = &fields[i]; ArchivableStaticFieldInfo* info = &fields[i];
TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name); TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name);
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name); TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
Klass* k = SystemDictionary::resolve_or_null(klass_name, THREAD); Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm(THREAD);
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
log_info(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
vm_direct_exit(-1, "VM exits due to exception, use -Xlog:cds,exceptions=trace for detail");
}
InstanceKlass* ik = InstanceKlass::cast(k); InstanceKlass* ik = InstanceKlass::cast(k);
assert(InstanceKlass::cast(ik)->is_shared_boot_class(), assert(InstanceKlass::cast(ik)->is_shared_boot_class(),
"Only support boot classes"); "Only support boot classes");
ik->initialize(THREAD); ik->initialize(CHECK);
guarantee(!HAS_PENDING_EXCEPTION, "exception in initialize");
ArchivableStaticFieldFinder finder(ik, field_name); ArchivableStaticFieldFinder finder(ik, field_name);
ik->do_local_static_fields(&finder); ik->do_local_static_fields(&finder);
@ -1273,26 +1264,26 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
} }
} }
void HeapShared::init_subgraph_entry_fields(Thread* THREAD) { void HeapShared::init_subgraph_entry_fields(TRAPS) {
assert(is_heap_object_archiving_allowed(), "Sanity check"); assert(is_heap_object_archiving_allowed(), "Sanity check");
_dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable(); _dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
init_subgraph_entry_fields(closed_archive_subgraph_entry_fields, init_subgraph_entry_fields(closed_archive_subgraph_entry_fields,
num_closed_archive_subgraph_entry_fields, num_closed_archive_subgraph_entry_fields,
THREAD); CHECK);
init_subgraph_entry_fields(open_archive_subgraph_entry_fields, init_subgraph_entry_fields(open_archive_subgraph_entry_fields,
num_open_archive_subgraph_entry_fields, num_open_archive_subgraph_entry_fields,
THREAD); CHECK);
if (MetaspaceShared::use_full_module_graph()) { if (MetaspaceShared::use_full_module_graph()) {
init_subgraph_entry_fields(fmg_open_archive_subgraph_entry_fields, init_subgraph_entry_fields(fmg_open_archive_subgraph_entry_fields,
num_fmg_open_archive_subgraph_entry_fields, num_fmg_open_archive_subgraph_entry_fields,
THREAD); CHECK);
} }
} }
void HeapShared::init_for_dumping(Thread* THREAD) { void HeapShared::init_for_dumping(TRAPS) {
if (is_heap_object_archiving_allowed()) { if (is_heap_object_archiving_allowed()) {
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings(); _dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
init_subgraph_entry_fields(THREAD); init_subgraph_entry_fields(CHECK);
} }
} }

View File

@ -222,8 +222,9 @@ private:
static KlassSubGraphInfo* init_subgraph_info(Klass *k, bool is_full_module_graph); static KlassSubGraphInfo* init_subgraph_info(Klass *k, bool is_full_module_graph);
static KlassSubGraphInfo* get_subgraph_info(Klass *k); static KlassSubGraphInfo* get_subgraph_info(Klass *k);
static void init_subgraph_entry_fields(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
int num, Thread* THREAD); int num, TRAPS);
// Used by decode_from_archive // Used by decode_from_archive
static address _narrow_oop_base; static address _narrow_oop_base;
@ -399,8 +400,7 @@ private:
static void patch_archived_heap_embedded_pointers(MemRegion mem, address oopmap, static void patch_archived_heap_embedded_pointers(MemRegion mem, address oopmap,
size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN; size_t oopmap_in_bits) NOT_CDS_JAVA_HEAP_RETURN;
static void init_for_dumping(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN; static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void init_subgraph_entry_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN; static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_subgraph_info_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_subgraph_info_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
}; };

View File

@ -44,6 +44,7 @@
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logMessage.hpp" #include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
#include "memory/archiveBuilder.hpp" #include "memory/archiveBuilder.hpp"
#include "memory/cppVtables.hpp" #include "memory/cppVtables.hpp"
#include "memory/dumpAllocStats.hpp" #include "memory/dumpAllocStats.hpp"
@ -65,7 +66,6 @@
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "runtime/safepointVerifiers.hpp" #include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp" #include "runtime/vmOperations.hpp"
#include "utilities/align.hpp" #include "utilities/align.hpp"
@ -236,7 +236,7 @@ void MetaspaceShared::post_initialize(TRAPS) {
static GrowableArrayCHeap<OopHandle, mtClassShared>* _extra_interned_strings = NULL; static GrowableArrayCHeap<OopHandle, mtClassShared>* _extra_interned_strings = NULL;
static GrowableArrayCHeap<Symbol*, mtClassShared>* _extra_symbols = NULL; static GrowableArrayCHeap<Symbol*, mtClassShared>* _extra_symbols = NULL;
void MetaspaceShared::read_extra_data(const char* filename, TRAPS) { void MetaspaceShared::read_extra_data(Thread* current, const char* filename) {
_extra_interned_strings = new GrowableArrayCHeap<OopHandle, mtClassShared>(10000); _extra_interned_strings = new GrowableArrayCHeap<OopHandle, mtClassShared>(10000);
_extra_symbols = new GrowableArrayCHeap<Symbol*, mtClassShared>(1000); _extra_symbols = new GrowableArrayCHeap<Symbol*, mtClassShared>(1000);
@ -246,7 +246,7 @@ void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
while (reader.remain() > 0) { while (reader.remain() > 0) {
int utf8_length; int utf8_length;
int prefix_type = reader.scan_prefix(&utf8_length); int prefix_type = reader.scan_prefix(&utf8_length);
ResourceMark rm(THREAD); ResourceMark rm(current);
if (utf8_length == 0x7fffffff) { if (utf8_length == 0x7fffffff) {
// buf_len will overflown 32-bit value. // buf_len will overflown 32-bit value.
vm_exit_during_initialization(err_msg("string length too large: %d", utf8_length)); vm_exit_during_initialization(err_msg("string length too large: %d", utf8_length));
@ -260,6 +260,8 @@ void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
_extra_symbols->append(SymbolTable::new_permanent_symbol(utf8_buffer)); _extra_symbols->append(SymbolTable::new_permanent_symbol(utf8_buffer));
} else{ } else{
assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity"); assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity");
ExceptionMark em(current);
Thread* THREAD = current; // For exception macros.
oop str = StringTable::intern(utf8_buffer, THREAD); oop str = StringTable::intern(utf8_buffer, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
@ -452,8 +454,6 @@ void VM_PopulateDumpSharedSpace::doit() {
Metaspace::freeze(); Metaspace::freeze();
DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
Thread* THREAD = VMThread::vm_thread();
FileMapInfo::check_nonempty_dir_in_shared_path_table(); FileMapInfo::check_nonempty_dir_in_shared_path_table();
NOT_PRODUCT(SystemDictionary::verify();) NOT_PRODUCT(SystemDictionary::verify();)
@ -552,14 +552,13 @@ bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) {
// Link the class to cause the bytecodes to be rewritten and the // Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created. Class verification is done according // cpcache to be created. Class verification is done according
// to -Xverify setting. // to -Xverify setting.
bool res = MetaspaceShared::try_link_class(ik, THREAD); bool res = MetaspaceShared::try_link_class(THREAD, ik);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
if (DumpSharedSpaces) { if (DumpSharedSpaces) {
// The following function is used to resolve all Strings in the statically // The following function is used to resolve all Strings in the statically
// dumped classes to archive all the Strings. The archive heap is not supported // dumped classes to archive all the Strings. The archive heap is not supported
// for the dynamic archive. // for the dynamic archive.
ik->constants()->resolve_class_constants(THREAD); ik->constants()->resolve_class_constants(CHECK_0); // may throw OOM when interning strings.
} }
return res; return res;
} }
@ -580,7 +579,7 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
if (klass->is_instance_klass()) { if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass); InstanceKlass* ik = InstanceKlass::cast(klass);
if (linking_required(ik)) { if (linking_required(ik)) {
has_linked |= link_class_for_cds(ik, THREAD); has_linked |= link_class_for_cds(ik, CHECK);
} }
} }
} }
@ -614,137 +613,121 @@ void MetaspaceShared::prepare_for_dumping() {
// Preload classes from a list, populate the shared spaces and dump to a // Preload classes from a list, populate the shared spaces and dump to a
// file. // file.
void MetaspaceShared::preload_and_dump(TRAPS) { void MetaspaceShared::preload_and_dump(TRAPS) {
{ TraceTime timer("Dump Shared Spaces", TRACETIME_LOG(Info, startuptime)); ResourceMark rm(THREAD);
ResourceMark rm(THREAD); preload_and_dump_impl(THREAD);
char class_list_path_str[JVM_MAXPATHLEN]; if (HAS_PENDING_EXCEPTION) {
// Preload classes to be shared. if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
const char* class_list_path; vm_direct_exit(-1, err_msg("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
if (SharedClassListFile == NULL) { SIZE_FORMAT "M", MaxHeapSize/M));
// Construct the path to the class list (in jre/lib) } else {
// Walk up two directories from the location of the VM and log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
// optionally tack on "lib" (depending on platform) java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
os::jvm_path(class_list_path_str, sizeof(class_list_path_str)); vm_direct_exit(-1, "VM exits due to exception, use -Xlog:cds,exceptions=trace for detail");
for (int i = 0; i < 3; i++) { }
char *end = strrchr(class_list_path_str, *os::file_separator()); } else {
if (end != NULL) *end = '\0'; // On success, the VM_PopulateDumpSharedSpace op should have
} // exited the VM.
int class_list_path_len = (int)strlen(class_list_path_str); ShouldNotReachHere();
if (class_list_path_len >= 3) { }
if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) { }
if (class_list_path_len < JVM_MAXPATHLEN - 4) {
jio_snprintf(class_list_path_str + class_list_path_len, void MetaspaceShared::preload_classes(TRAPS) {
sizeof(class_list_path_str) - class_list_path_len, char default_classlist[JVM_MAXPATHLEN];
"%slib", os::file_separator()); const char* classlist_path;
class_list_path_len += 4;
} if (SharedClassListFile == NULL) {
// Construct the path to the class list (in jre/lib)
// Walk up two directories from the location of the VM and
// optionally tack on "lib" (depending on platform)
os::jvm_path(default_classlist, sizeof(default_classlist));
for (int i = 0; i < 3; i++) {
char *end = strrchr(default_classlist, *os::file_separator());
if (end != NULL) *end = '\0';
}
int classlist_path_len = (int)strlen(default_classlist);
if (classlist_path_len >= 3) {
if (strcmp(default_classlist + classlist_path_len - 3, "lib") != 0) {
if (classlist_path_len < JVM_MAXPATHLEN - 4) {
jio_snprintf(default_classlist + classlist_path_len,
sizeof(default_classlist) - classlist_path_len,
"%slib", os::file_separator());
classlist_path_len += 4;
} }
} }
if (class_list_path_len < JVM_MAXPATHLEN - 10) {
jio_snprintf(class_list_path_str + class_list_path_len,
sizeof(class_list_path_str) - class_list_path_len,
"%sclasslist", os::file_separator());
}
class_list_path = class_list_path_str;
} else {
class_list_path = SharedClassListFile;
} }
if (classlist_path_len < JVM_MAXPATHLEN - 10) {
log_info(cds)("Loading classes to share ..."); jio_snprintf(default_classlist + classlist_path_len,
_has_error_classes = false; sizeof(default_classlist) - classlist_path_len,
int class_count = preload_classes(class_list_path, THREAD); "%sclasslist", os::file_separator());
if (ExtraSharedClassListFile) {
class_count += preload_classes(ExtraSharedClassListFile, THREAD);
} }
log_info(cds)("Loading classes to share: done."); classlist_path = default_classlist;
} else {
classlist_path = SharedClassListFile;
}
log_info(cds)("Shared spaces: preloaded %d classes", class_count); log_info(cds)("Loading classes to share ...");
_has_error_classes = false;
int class_count = parse_classlist(classlist_path, CHECK);
if (ExtraSharedClassListFile) {
class_count += parse_classlist(ExtraSharedClassListFile, CHECK);
}
if (SharedArchiveConfigFile) { // Exercise the manifest processing code to ensure classes used by CDS at runtime
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile); // are always archived
read_extra_data(SharedArchiveConfigFile, THREAD); const char* dummy = "Manifest-Version: 1.0\n";
log_info(cds)("Reading extra data: done."); SystemDictionaryShared::create_jar_manifest(dummy, strlen(dummy), CHECK);
}
if (LambdaFormInvokers::lambdaform_lines() != NULL) { log_info(cds)("Loading classes to share: done.");
log_info(cds)("Regenerate MethodHandle Holder classes..."); log_info(cds)("Shared spaces: preloaded %d classes", class_count);
LambdaFormInvokers::regenerate_holder_classes(THREAD); }
log_info(cds)("Regenerate MethodHandle Holder classes done.");
}
HeapShared::init_for_dumping(THREAD); void MetaspaceShared::preload_and_dump_impl(TRAPS) {
preload_classes(CHECK);
// exercise the manifest processing code to ensure classes used by CDS are always archived if (SharedArchiveConfigFile) {
SystemDictionaryShared::create_jar_manifest("Manifest-Version: 1.0\n", strlen("Manifest-Version: 1.0\n"), THREAD); log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
// Rewrite and link classes read_extra_data(THREAD, SharedArchiveConfigFile);
log_info(cds)("Rewriting and linking classes ..."); log_info(cds)("Reading extra data: done.");
}
// Link any classes which got missed. This would happen if we have loaded classes that if (LambdaFormInvokers::lambdaform_lines() != NULL) {
// were not explicitly specified in the classlist. E.g., if an interface implemented by class K log_info(cds)("Regenerate MethodHandle Holder classes...");
// fails verification, all other interfaces that were not specified in the classlist but LambdaFormInvokers::regenerate_holder_classes(CHECK);
// are implemented by K are not verified. log_info(cds)("Regenerate MethodHandle Holder classes done.");
link_and_cleanup_shared_classes(CATCH); }
log_info(cds)("Rewriting and linking classes: done");
HeapShared::init_for_dumping(CHECK);
// Rewrite and link classes
log_info(cds)("Rewriting and linking classes ...");
// Link any classes which got missed. This would happen if we have loaded classes that
// were not explicitly specified in the classlist. E.g., if an interface implemented by class K
// fails verification, all other interfaces that were not specified in the classlist but
// are implemented by K are not verified.
link_and_cleanup_shared_classes(CATCH);
log_info(cds)("Rewriting and linking classes: done");
#if INCLUDE_CDS_JAVA_HEAP #if INCLUDE_CDS_JAVA_HEAP
if (use_full_module_graph()) { if (use_full_module_graph()) {
HeapShared::reset_archived_object_states(THREAD); HeapShared::reset_archived_object_states(CHECK);
} }
#endif #endif
VM_PopulateDumpSharedSpace op; VM_PopulateDumpSharedSpace op;
VMThread::execute(&op); VMThread::execute(&op);
}
} }
int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) { int MetaspaceShared::parse_classlist(const char* classlist_path, TRAPS) {
ClassListParser parser(class_list_path); ClassListParser parser(classlist_path);
int class_count = 0; return parser.parse(THREAD); // returns the number of classes loaded.
while (parser.parse_one_line()) {
if (parser.lambda_form_line()) {
continue;
}
Klass* klass = parser.load_current_class(THREAD);
if (HAS_PENDING_EXCEPTION) {
if (klass == NULL) {
Symbol* exception_klass_name = PENDING_EXCEPTION->klass()->name();
if (exception_klass_name == vmSymbols::java_lang_ClassNotFoundException() ||
exception_klass_name == vmSymbols::java_lang_UnsupportedClassVersionError()) {
// print a warning only when the class is not found or has a version that's too old.
// Todo: the CDS test cases expect "Cannot find" in the log, but we should consider
// distinguishing the different failure modes.
log_warning(cds)("Preload Warning: Cannot find %s", parser.current_class_name());
}
}
CLEAR_PENDING_EXCEPTION;
}
if (klass != NULL) {
if (log_is_enabled(Trace, cds)) {
ResourceMark rm(THREAD);
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
}
if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);
// Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created. The linking is done as soon as classes
// are loaded in order that the related data structures (klass and
// cpCache) are located together.
try_link_class(ik, THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
}
class_count++;
}
}
return class_count;
} }
// Returns true if the class's status has changed // Returns true if the class's status has changed.
bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { bool MetaspaceShared::try_link_class(Thread* current, InstanceKlass* ik) {
ExceptionMark em(current);
Thread* THREAD = current; // For exception macros.
Arguments::assert_is_dumping_archive(); Arguments::assert_is_dumping_archive();
if (ik->is_loaded() && !ik->is_linked() && if (ik->is_loaded() && !ik->is_linked() &&
!SystemDictionaryShared::has_class_failed_verification(ik)) { !SystemDictionaryShared::has_class_failed_verification(ik)) {

View File

@ -78,9 +78,15 @@ class MetaspaceShared : AllStatic {
static void prepare_for_dumping() NOT_CDS_RETURN; static void prepare_for_dumping() NOT_CDS_RETURN;
static void preload_and_dump(TRAPS) NOT_CDS_RETURN; static void preload_and_dump(TRAPS) NOT_CDS_RETURN;
static int preload_classes(const char * class_list_path,
TRAPS) NOT_CDS_RETURN_(0);
private:
static void preload_and_dump_impl(TRAPS) NOT_CDS_RETURN;
static void preload_classes(TRAPS) NOT_CDS_RETURN;
static int parse_classlist(const char * classlist_path,
TRAPS) NOT_CDS_RETURN_(0);
public:
static Symbol* symbol_rs_base() { static Symbol* symbol_rs_base() {
return (Symbol*)_symbol_rs.base(); return (Symbol*)_symbol_rs.base();
} }
@ -127,7 +133,7 @@ class MetaspaceShared : AllStatic {
NOT_CDS(return false); NOT_CDS(return false);
} }
static bool try_link_class(InstanceKlass* ik, TRAPS); static bool try_link_class(Thread* current, InstanceKlass* ik);
static void link_and_cleanup_shared_classes(TRAPS) NOT_CDS_RETURN; static void link_and_cleanup_shared_classes(TRAPS) NOT_CDS_RETURN;
static bool link_class_for_cds(InstanceKlass* ik, TRAPS) NOT_CDS_RETURN_(false); static bool link_class_for_cds(InstanceKlass* ik, TRAPS) NOT_CDS_RETURN_(false);
static bool linking_required(InstanceKlass* ik) NOT_CDS_RETURN_(false); static bool linking_required(InstanceKlass* ik) NOT_CDS_RETURN_(false);
@ -176,7 +182,7 @@ class MetaspaceShared : AllStatic {
static void disable_full_module_graph() { _use_full_module_graph = false; } static void disable_full_module_graph() { _use_full_module_graph = false; }
private: private:
static void read_extra_data(const char* filename, TRAPS) NOT_CDS_RETURN; static void read_extra_data(Thread* current, const char* filename) NOT_CDS_RETURN;
static FileMapInfo* open_static_archive(); static FileMapInfo* open_static_archive();
static FileMapInfo* open_dynamic_archive(); static FileMapInfo* open_dynamic_archive();
// use_requested_addr: If true (default), attempt to map at the address the // use_requested_addr: If true (default), attempt to map at the address the

View File

@ -68,7 +68,7 @@ public class ExceptionDuringDumpAtObjectsInitPhase {
"-Xmx32m", "-Xmx32m",
"-Dtest.with.exception=true", "-Dtest.with.exception=true",
gcLog).shouldNotHaveExitValue(0) gcLog).shouldNotHaveExitValue(0)
.shouldContain("Preload Error: Failed to load jdk/internal/math/FDBigInteger") .shouldContain("Preload Warning: Cannot find jdk/internal/math/FDBigInteger")
.shouldContain("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); .shouldContain("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail");
// 2. Test with OOM // 2. Test with OOM