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;
|
_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,12 +453,10 @@ 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 != NULL) {
|
|
||||||
if (k->local_interfaces()->length() != _interfaces->length()) {
|
if (k->local_interfaces()->length() != _interfaces->length()) {
|
||||||
print_specified_interfaces();
|
print_specified_interfaces();
|
||||||
print_actual_interfaces(k);
|
print_actual_interfaces(k);
|
||||||
@ -420,7 +473,6 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
|||||||
// This tells JVM_FindLoadedClass to not find this class.
|
// This tells JVM_FindLoadedClass to not find this class.
|
||||||
k->set_shared_classpath_index(UNREGISTERED_INDEX);
|
k->set_shared_classpath_index(UNREGISTERED_INDEX);
|
||||||
k->clear_shared_class_loader_type();
|
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,17 +602,15 @@ 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)) {
|
||||||
|
// array classes are not supported in class list.
|
||||||
|
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
||||||
|
}
|
||||||
|
|
||||||
JavaValue result(T_OBJECT);
|
JavaValue result(T_OBJECT);
|
||||||
if (non_array) {
|
// Call java_system_loader().loadClass() directly, which will
|
||||||
// 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
|
// delegate to the correct loader (boot, platform or app) depending on
|
||||||
// the class name.
|
// the package name.
|
||||||
|
|
||||||
Handle s = java_lang_String::create_from_symbol(class_name_symbol, CHECK_NULL);
|
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 '.'
|
// ClassLoader.loadClass() wants external class name format, i.e., convert '/' chars to '.'
|
||||||
@ -580,10 +624,7 @@ Klass* ClassListParser::load_current_class(TRAPS) {
|
|||||||
vmSymbols::string_class_signature(),
|
vmSymbols::string_class_signature(),
|
||||||
ext_class_name,
|
ext_class_name,
|
||||||
CHECK_NULL);
|
CHECK_NULL);
|
||||||
} else {
|
|
||||||
// array classes are not supported in class list.
|
|
||||||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
|
||||||
}
|
|
||||||
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);
|
||||||
|
@ -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; }
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
THREAD);
|
CHECK_NULL);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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,67 +613,91 @@ 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);
|
||||||
char class_list_path_str[JVM_MAXPATHLEN];
|
preload_and_dump_impl(THREAD);
|
||||||
// Preload classes to be shared.
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
const char* class_list_path;
|
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) {
|
if (SharedClassListFile == NULL) {
|
||||||
// Construct the path to the class list (in jre/lib)
|
// Construct the path to the class list (in jre/lib)
|
||||||
// Walk up two directories from the location of the VM and
|
// Walk up two directories from the location of the VM and
|
||||||
// optionally tack on "lib" (depending on platform)
|
// optionally tack on "lib" (depending on platform)
|
||||||
os::jvm_path(class_list_path_str, sizeof(class_list_path_str));
|
os::jvm_path(default_classlist, sizeof(default_classlist));
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
char *end = strrchr(class_list_path_str, *os::file_separator());
|
char *end = strrchr(default_classlist, *os::file_separator());
|
||||||
if (end != NULL) *end = '\0';
|
if (end != NULL) *end = '\0';
|
||||||
}
|
}
|
||||||
int class_list_path_len = (int)strlen(class_list_path_str);
|
int classlist_path_len = (int)strlen(default_classlist);
|
||||||
if (class_list_path_len >= 3) {
|
if (classlist_path_len >= 3) {
|
||||||
if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) {
|
if (strcmp(default_classlist + classlist_path_len - 3, "lib") != 0) {
|
||||||
if (class_list_path_len < JVM_MAXPATHLEN - 4) {
|
if (classlist_path_len < JVM_MAXPATHLEN - 4) {
|
||||||
jio_snprintf(class_list_path_str + class_list_path_len,
|
jio_snprintf(default_classlist + classlist_path_len,
|
||||||
sizeof(class_list_path_str) - class_list_path_len,
|
sizeof(default_classlist) - classlist_path_len,
|
||||||
"%slib", os::file_separator());
|
"%slib", os::file_separator());
|
||||||
class_list_path_len += 4;
|
classlist_path_len += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (class_list_path_len < JVM_MAXPATHLEN - 10) {
|
if (classlist_path_len < JVM_MAXPATHLEN - 10) {
|
||||||
jio_snprintf(class_list_path_str + class_list_path_len,
|
jio_snprintf(default_classlist + classlist_path_len,
|
||||||
sizeof(class_list_path_str) - class_list_path_len,
|
sizeof(default_classlist) - classlist_path_len,
|
||||||
"%sclasslist", os::file_separator());
|
"%sclasslist", os::file_separator());
|
||||||
}
|
}
|
||||||
class_list_path = class_list_path_str;
|
classlist_path = default_classlist;
|
||||||
} else {
|
} else {
|
||||||
class_list_path = SharedClassListFile;
|
classlist_path = SharedClassListFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info(cds)("Loading classes to share ...");
|
log_info(cds)("Loading classes to share ...");
|
||||||
_has_error_classes = false;
|
_has_error_classes = false;
|
||||||
int class_count = preload_classes(class_list_path, THREAD);
|
int class_count = parse_classlist(classlist_path, CHECK);
|
||||||
if (ExtraSharedClassListFile) {
|
if (ExtraSharedClassListFile) {
|
||||||
class_count += preload_classes(ExtraSharedClassListFile, THREAD);
|
class_count += parse_classlist(ExtraSharedClassListFile, CHECK);
|
||||||
}
|
}
|
||||||
log_info(cds)("Loading classes to share: 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);
|
||||||
|
|
||||||
|
log_info(cds)("Loading classes to share: done.");
|
||||||
log_info(cds)("Shared spaces: preloaded %d classes", class_count);
|
log_info(cds)("Shared spaces: preloaded %d classes", class_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetaspaceShared::preload_and_dump_impl(TRAPS) {
|
||||||
|
preload_classes(CHECK);
|
||||||
|
|
||||||
if (SharedArchiveConfigFile) {
|
if (SharedArchiveConfigFile) {
|
||||||
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
|
||||||
read_extra_data(SharedArchiveConfigFile, THREAD);
|
read_extra_data(THREAD, SharedArchiveConfigFile);
|
||||||
log_info(cds)("Reading extra data: done.");
|
log_info(cds)("Reading extra data: done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
if (LambdaFormInvokers::lambdaform_lines() != NULL) {
|
||||||
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
log_info(cds)("Regenerate MethodHandle Holder classes...");
|
||||||
LambdaFormInvokers::regenerate_holder_classes(THREAD);
|
LambdaFormInvokers::regenerate_holder_classes(CHECK);
|
||||||
log_info(cds)("Regenerate MethodHandle Holder classes done.");
|
log_info(cds)("Regenerate MethodHandle Holder classes done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapShared::init_for_dumping(THREAD);
|
HeapShared::init_for_dumping(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
|
// Rewrite and link classes
|
||||||
log_info(cds)("Rewriting and linking classes ...");
|
log_info(cds)("Rewriting and linking classes ...");
|
||||||
|
|
||||||
@ -687,64 +710,24 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
|
|||||||
|
|
||||||
#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()) {
|
// Returns true if the class's status has changed.
|
||||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
bool MetaspaceShared::try_link_class(Thread* current, InstanceKlass* ik) {
|
||||||
|
ExceptionMark em(current);
|
||||||
// Link the class to cause the bytecodes to be rewritten and the
|
Thread* THREAD = current; // For exception macros.
|
||||||
// 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
|
|
||||||
bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
|
|
||||||
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)) {
|
||||||
|
@ -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,
|
|
||||||
|
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);
|
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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user