8261480: MetaspaceShared::preload_and_dump should check exceptions
Reviewed-by: dholmes, ccheung
This commit is contained in:
parent
81ba5784ba
commit
2b93ae0019
@ -92,6 +92,61 @@ ClassListParser::~ClassListParser() {
|
||||
_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() {
|
||||
for (;;) {
|
||||
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) {
|
||||
log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
|
||||
_class_name, _source);
|
||||
return NULL;
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
}
|
||||
|
||||
InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
|
||||
|
||||
if (k != NULL) {
|
||||
if (k->local_interfaces()->length() != _interfaces->length()) {
|
||||
print_specified_interfaces();
|
||||
print_actual_interfaces(k);
|
||||
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();
|
||||
if (k->local_interfaces()->length() != _interfaces->length()) {
|
||||
print_specified_interfaces();
|
||||
print_actual_interfaces(k);
|
||||
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();
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
@ -442,10 +494,8 @@ void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int
|
||||
} else if (tag == JVM_CONSTANT_MethodHandle) {
|
||||
cii->add_ref_kind(pool->method_handle_ref_kind_at(arg));
|
||||
int callee_index = pool->method_handle_klass_index_at(arg);
|
||||
Klass* callee = pool->klass_at(callee_index, THREAD);
|
||||
if (callee != NULL) {
|
||||
cii->add_item(callee->name()->as_C_string());
|
||||
}
|
||||
Klass* callee = pool->klass_at(callee_index, CHECK);
|
||||
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_signature_ref_at(arg)->as_C_string());
|
||||
} 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) {
|
||||
ResourceMark rm(THREAD);
|
||||
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();
|
||||
int indy_info_offset = 1;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
ResourceMark rm(THREAD);
|
||||
ResourceMark rm(current);
|
||||
char* ex_msg = (char*)"";
|
||||
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
|
||||
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) {
|
||||
Handle class_loader(THREAD, SystemDictionary::java_system_loader());
|
||||
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
|
||||
if (klass != NULL && klass->is_instance_klass()) {
|
||||
Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, CHECK);
|
||||
if (klass->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
if (SystemDictionaryShared::has_class_failed_verification(ik)) {
|
||||
// don't attempt to resolve indy on classes that has previously failed verification
|
||||
MetaspaceShared::try_link_class(THREAD, ik);
|
||||
if (!ik->is_linked()) {
|
||||
// Verification of ik has failed
|
||||
return;
|
||||
}
|
||||
MetaspaceShared::try_link_class(ik, CHECK);
|
||||
|
||||
ConstantPool* cp = ik->constants();
|
||||
ConstantPoolCache* cpcache = cp->cache();
|
||||
@ -538,15 +591,8 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
Klass* ClassListParser::load_current_class(TRAPS) {
|
||||
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
|
||||
|
||||
if (_indy_items->length() > 0) {
|
||||
resolve_indy(class_name_symbol, CHECK_NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Klass* klass = NULL;
|
||||
Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPS) {
|
||||
Klass* klass;
|
||||
if (!is_loading_from_source()) {
|
||||
// Load classes for the boot/platform/app loaders only.
|
||||
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");
|
||||
}
|
||||
|
||||
bool non_array = !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 {
|
||||
if (Signature::is_array(class_name_symbol)) {
|
||||
// array classes are not supported in class list.
|
||||
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");
|
||||
oop obj = result.get_oop();
|
||||
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
|
||||
// class list file.
|
||||
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);
|
||||
int id = this->id();
|
||||
SystemDictionaryShared::update_shared_entry(ik, id);
|
||||
|
@ -116,8 +116,11 @@ class ClassListParser : public StackObj {
|
||||
void print_actual_interfaces(InstanceKlass *ik);
|
||||
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);
|
||||
bool parse_one_line();
|
||||
Klass* load_current_class(Symbol* class_name_symbol, TRAPS);
|
||||
|
||||
public:
|
||||
ClassListParser(const char* file);
|
||||
~ClassListParser();
|
||||
@ -129,7 +132,7 @@ public:
|
||||
return _instance;
|
||||
}
|
||||
|
||||
bool parse_one_line();
|
||||
int parse(TRAPS);
|
||||
void split_tokens_by_whitespace(int offset);
|
||||
int split_at_tag_from_line();
|
||||
bool parse_at_tags();
|
||||
@ -169,8 +172,6 @@ public:
|
||||
return _class_name;
|
||||
}
|
||||
|
||||
Klass* load_current_class(TRAPS);
|
||||
|
||||
bool is_loading_from_source();
|
||||
|
||||
bool lambda_form_line() { return _lambda_form_line; }
|
||||
|
@ -1268,14 +1268,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
name,
|
||||
loader_data,
|
||||
cl_info,
|
||||
THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (DumpSharedSpaces) {
|
||||
log_error(cds)("Preload Error: Failed to load %s", class_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHECK_NULL);
|
||||
result->set_classpath_index(classpath_index);
|
||||
return result;
|
||||
}
|
||||
|
@ -260,17 +260,17 @@ InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS)
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
ResourceMark rm(THREAD);
|
||||
const char* class_name = name->as_C_string();
|
||||
|
||||
const char* file_name = file_name_for_class_name(class_name,
|
||||
name->utf8_length());
|
||||
assert(file_name != NULL, "invariant");
|
||||
|
||||
// Lookup stream for parsing .class file
|
||||
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) {
|
||||
return NULL;
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
}
|
||||
|
||||
{
|
||||
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
|
||||
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);
|
||||
}
|
||||
|
||||
if (NULL == stream) {
|
||||
log_warning(cds)("Preload Warning: Cannot find %s", class_name);
|
||||
if (stream == NULL) {
|
||||
// open_stream could return NULL even when no exception has be thrown (JDK-8263632).
|
||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(stream != NULL, "invariant");
|
||||
stream->set_verify(true);
|
||||
|
||||
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
Handle protection_domain;
|
||||
ClassLoadInfo cl_info(protection_domain);
|
||||
|
||||
InstanceKlass* result = KlassFactory::create_from_stream(stream,
|
||||
name,
|
||||
loader_data,
|
||||
cl_info,
|
||||
THREAD);
|
||||
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
log_error(cds)("Preload Error: Failed to load %s", class_name);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
InstanceKlass* k = KlassFactory::create_from_stream(stream,
|
||||
name,
|
||||
loader_data,
|
||||
cl_info,
|
||||
CHECK_NULL);
|
||||
return k;
|
||||
}
|
||||
|
||||
struct CachedClassPathEntry {
|
||||
@ -310,7 +303,7 @@ struct CachedClassPathEntry {
|
||||
|
||||
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.
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
if (cached_path_entries == NULL) {
|
||||
@ -336,7 +329,10 @@ ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path
|
||||
}
|
||||
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) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ private:
|
||||
static bool _has_platform_classes;
|
||||
|
||||
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:
|
||||
static void process_jar_manifest(ClassPathEntry* entry, bool check_for_duplicates, TRAPS);
|
||||
|
@ -143,7 +143,7 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {
|
||||
SystemDictionary::add_to_hierarchy(result);
|
||||
}
|
||||
// new class not linked yet.
|
||||
MetaspaceShared::try_link_class(result, THREAD);
|
||||
MetaspaceShared::try_link_class(THREAD, result);
|
||||
assert(!HAS_PENDING_EXCEPTION, "Invariant");
|
||||
|
||||
// exclude the existing class from dump
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,6 @@ public:
|
||||
class ArchiveUtils {
|
||||
public:
|
||||
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
|
||||
|
@ -168,7 +168,7 @@ void HeapShared::reset_archived_object_states(TRAPS) {
|
||||
log_debug(cds)("Resetting platform loader");
|
||||
reset_states(SystemDictionary::java_platform_loader(), CHECK);
|
||||
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;
|
||||
@ -360,7 +360,6 @@ void HeapShared::copy_closed_archive_heap_objects(
|
||||
GrowableArray<MemRegion> * closed_archive) {
|
||||
assert(is_heap_object_archiving_allowed(), "Cannot archive java heap objects");
|
||||
|
||||
Thread* THREAD = Thread::current();
|
||||
G1CollectedHeap::heap()->begin_archive_alloc_range();
|
||||
|
||||
// Archive interned string objects
|
||||
@ -1244,25 +1243,17 @@ public:
|
||||
};
|
||||
|
||||
void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
|
||||
int num, Thread* THREAD) {
|
||||
int num, TRAPS) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
ArchivableStaticFieldInfo* info = &fields[i];
|
||||
TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name);
|
||||
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
|
||||
|
||||
Klass* k = SystemDictionary::resolve_or_null(klass_name, THREAD);
|
||||
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");
|
||||
}
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK);
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
assert(InstanceKlass::cast(ik)->is_shared_boot_class(),
|
||||
"Only support boot classes");
|
||||
ik->initialize(THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "exception in initialize");
|
||||
ik->initialize(CHECK);
|
||||
|
||||
ArchivableStaticFieldFinder finder(ik, field_name);
|
||||
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");
|
||||
_dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
|
||||
init_subgraph_entry_fields(closed_archive_subgraph_entry_fields,
|
||||
num_closed_archive_subgraph_entry_fields,
|
||||
THREAD);
|
||||
CHECK);
|
||||
init_subgraph_entry_fields(open_archive_subgraph_entry_fields,
|
||||
num_open_archive_subgraph_entry_fields,
|
||||
THREAD);
|
||||
CHECK);
|
||||
if (MetaspaceShared::use_full_module_graph()) {
|
||||
init_subgraph_entry_fields(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()) {
|
||||
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
|
||||
init_subgraph_entry_fields(THREAD);
|
||||
init_subgraph_entry_fields(CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,8 +222,9 @@ private:
|
||||
static KlassSubGraphInfo* init_subgraph_info(Klass *k, bool is_full_module_graph);
|
||||
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[],
|
||||
int num, Thread* THREAD);
|
||||
int num, TRAPS);
|
||||
|
||||
// Used by decode_from_archive
|
||||
static address _narrow_oop_base;
|
||||
@ -399,8 +400,7 @@ private:
|
||||
static void patch_archived_heap_embedded_pointers(MemRegion mem, address oopmap,
|
||||
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_subgraph_entry_fields(Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN;
|
||||
static void init_for_dumping(TRAPS) 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;
|
||||
};
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/archiveBuilder.hpp"
|
||||
#include "memory/cppVtables.hpp"
|
||||
#include "memory/dumpAllocStats.hpp"
|
||||
@ -65,7 +66,6 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/timerTrace.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "runtime/vmOperations.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
@ -236,7 +236,7 @@ void MetaspaceShared::post_initialize(TRAPS) {
|
||||
static GrowableArrayCHeap<OopHandle, mtClassShared>* _extra_interned_strings = 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_symbols = new GrowableArrayCHeap<Symbol*, mtClassShared>(1000);
|
||||
|
||||
@ -246,7 +246,7 @@ void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
|
||||
while (reader.remain() > 0) {
|
||||
int utf8_length;
|
||||
int prefix_type = reader.scan_prefix(&utf8_length);
|
||||
ResourceMark rm(THREAD);
|
||||
ResourceMark rm(current);
|
||||
if (utf8_length == 0x7fffffff) {
|
||||
// buf_len will overflown 32-bit value.
|
||||
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));
|
||||
} else{
|
||||
assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity");
|
||||
ExceptionMark em(current);
|
||||
Thread* THREAD = current; // For exception macros.
|
||||
oop str = StringTable::intern(utf8_buffer, THREAD);
|
||||
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
@ -452,8 +454,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
Metaspace::freeze();
|
||||
DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
|
||||
|
||||
Thread* THREAD = VMThread::vm_thread();
|
||||
|
||||
FileMapInfo::check_nonempty_dir_in_shared_path_table();
|
||||
|
||||
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
|
||||
// cpcache to be created. Class verification is done according
|
||||
// to -Xverify setting.
|
||||
bool res = MetaspaceShared::try_link_class(ik, THREAD);
|
||||
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
|
||||
bool res = MetaspaceShared::try_link_class(THREAD, ik);
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
// 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
|
||||
// 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;
|
||||
}
|
||||
@ -580,7 +579,7 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
|
||||
if (klass->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
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
|
||||
// file.
|
||||
void MetaspaceShared::preload_and_dump(TRAPS) {
|
||||
{ TraceTime timer("Dump Shared Spaces", TRACETIME_LOG(Info, startuptime));
|
||||
ResourceMark rm(THREAD);
|
||||
char class_list_path_str[JVM_MAXPATHLEN];
|
||||
// Preload classes to be shared.
|
||||
const char* class_list_path;
|
||||
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(class_list_path_str, sizeof(class_list_path_str));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
char *end = strrchr(class_list_path_str, *os::file_separator());
|
||||
if (end != NULL) *end = '\0';
|
||||
}
|
||||
int class_list_path_len = (int)strlen(class_list_path_str);
|
||||
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,
|
||||
sizeof(class_list_path_str) - class_list_path_len,
|
||||
"%slib", os::file_separator());
|
||||
class_list_path_len += 4;
|
||||
}
|
||||
ResourceMark rm(THREAD);
|
||||
preload_and_dump_impl(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (PENDING_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));
|
||||
} else {
|
||||
log_error(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");
|
||||
}
|
||||
} else {
|
||||
// On success, the VM_PopulateDumpSharedSpace op should have
|
||||
// exited the VM.
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void MetaspaceShared::preload_classes(TRAPS) {
|
||||
char default_classlist[JVM_MAXPATHLEN];
|
||||
const char* classlist_path;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
log_info(cds)("Loading classes to share ...");
|
||||
_has_error_classes = false;
|
||||
int class_count = preload_classes(class_list_path, THREAD);
|
||||
if (ExtraSharedClassListFile) {
|
||||
class_count += preload_classes(ExtraSharedClassListFile, THREAD);
|
||||
if (classlist_path_len < JVM_MAXPATHLEN - 10) {
|
||||
jio_snprintf(default_classlist + classlist_path_len,
|
||||
sizeof(default_classlist) - classlist_path_len,
|
||||
"%sclasslist", os::file_separator());
|
||||
}
|
||||
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) {
|
||||
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
||||
read_extra_data(SharedArchiveConfigFile, THREAD);
|
||||
log_info(cds)("Reading extra data: done.");
|
||||
}
|
||||
// Exercise the manifest processing code to ensure classes used by CDS at runtime
|
||||
// are always archived
|
||||
const char* dummy = "Manifest-Version: 1.0\n";
|
||||
SystemDictionaryShared::create_jar_manifest(dummy, strlen(dummy), CHECK);
|
||||
|
||||
if (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
||||
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
||||
LambdaFormInvokers::regenerate_holder_classes(THREAD);
|
||||
log_info(cds)("Regenerate MethodHandle Holder classes done.");
|
||||
}
|
||||
log_info(cds)("Loading classes to share: done.");
|
||||
log_info(cds)("Shared spaces: preloaded %d classes", class_count);
|
||||
}
|
||||
|
||||
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
|
||||
SystemDictionaryShared::create_jar_manifest("Manifest-Version: 1.0\n", strlen("Manifest-Version: 1.0\n"), THREAD);
|
||||
// Rewrite and link classes
|
||||
log_info(cds)("Rewriting and linking classes ...");
|
||||
if (SharedArchiveConfigFile) {
|
||||
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
||||
read_extra_data(THREAD, SharedArchiveConfigFile);
|
||||
log_info(cds)("Reading extra data: done.");
|
||||
}
|
||||
|
||||
// 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 (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
||||
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
||||
LambdaFormInvokers::regenerate_holder_classes(CHECK);
|
||||
log_info(cds)("Regenerate MethodHandle Holder 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 (use_full_module_graph()) {
|
||||
HeapShared::reset_archived_object_states(THREAD);
|
||||
}
|
||||
if (use_full_module_graph()) {
|
||||
HeapShared::reset_archived_object_states(CHECK);
|
||||
}
|
||||
#endif
|
||||
|
||||
VM_PopulateDumpSharedSpace op;
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
VM_PopulateDumpSharedSpace op;
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
|
||||
|
||||
int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) {
|
||||
ClassListParser parser(class_list_path);
|
||||
int class_count = 0;
|
||||
|
||||
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;
|
||||
int MetaspaceShared::parse_classlist(const char* classlist_path, TRAPS) {
|
||||
ClassListParser parser(classlist_path);
|
||||
return parser.parse(THREAD); // returns the number of classes loaded.
|
||||
}
|
||||
|
||||
// Returns true if the class's status has changed
|
||||
bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
|
||||
// Returns true if the class's status has changed.
|
||||
bool MetaspaceShared::try_link_class(Thread* current, InstanceKlass* ik) {
|
||||
ExceptionMark em(current);
|
||||
Thread* THREAD = current; // For exception macros.
|
||||
Arguments::assert_is_dumping_archive();
|
||||
if (ik->is_loaded() && !ik->is_linked() &&
|
||||
!SystemDictionaryShared::has_class_failed_verification(ik)) {
|
||||
|
@ -78,9 +78,15 @@ class MetaspaceShared : AllStatic {
|
||||
|
||||
static void prepare_for_dumping() 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() {
|
||||
return (Symbol*)_symbol_rs.base();
|
||||
}
|
||||
@ -127,7 +133,7 @@ class MetaspaceShared : AllStatic {
|
||||
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 bool link_class_for_cds(InstanceKlass* ik, TRAPS) 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; }
|
||||
|
||||
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_dynamic_archive();
|
||||
// use_requested_addr: If true (default), attempt to map at the address the
|
||||
|
@ -68,7 +68,7 @@ public class ExceptionDuringDumpAtObjectsInitPhase {
|
||||
"-Xmx32m",
|
||||
"-Dtest.with.exception=true",
|
||||
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");
|
||||
|
||||
// 2. Test with OOM
|
||||
|
Loading…
x
Reference in New Issue
Block a user