-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8261480: MetaspaceShared::preload_and_dump should check exceptions #2925
8261480: MetaspaceShared::preload_and_dump should check exceptions #2925
Conversation
👋 Welcome back iklam! A progress list of the required criteria for merging this PR into |
Webrevs
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Ioi,
I started making comments below but then realized that I have a fundamental problem with this work - you are making the VMThread throw exceptions at dump time and the VMThread should not be throwing exceptions. The VMThread can't execute Java code and so it can only get away with creating a handful of exception types that the VM can construct directly without calling java code. This is somewhat of an abberration - the VMThread should not be creating exceptions and ideally would not have the mechanics to even throw or catch them (the fields would be in JavaThread not Thread). So while we have to deal with this aberration already I do not want to see the VMThread actually creating and "throwing" exceptions at dump time, only to eventually call vm_exit. So this change takes things in the wrong direction for me - the dumping code should not be using TRAPS in general and should be returning NULL up the call chain, or else calling vm_exit as appropriate.
Cheers,
David
// 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Including some information about the exception would be useful - it might not be what we think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same as the current behavior -- all exceptions encountered during parsing of the classlist are printed as "Cannot find ...". Many of the test cases depend on this message.
I want to limit the size of this PR and stick to non-functional changes only. I plan to improve the message in do this in a separate RFE: JDK-8263469 "CDS log should print specific reasons for loading failures"
@@ -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()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that the right exception to use here? I'm not clear of the context for encountering this. What does regular classloading do in such a case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above. This will be improved in JDK-8263469.
@@ -471,10 +523,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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should current be a JavaThread here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently all the current
parameters will come from the THREAD/TRAPS of its caller, like
int ClassListParser::parse(TRAPS) {
...
resolve_indy(THREAD, class_name_symbol);
I could change the caller to use THREAD->as_JavaThread(), but I think that's too much ceremony. It's better to change to JavaThread*
after THREAD/TRAPS are changed to JavaThread
(JDK-8252685)
Klass* callee = pool->klass_at(callee_index, CHECK); | ||
if (callee != NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICS callee can never be NULL if no exception was thrown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
THREAD->as_Java_thread()->get_thread_stat()->perf_timers_addr(), | ||
PerfClassTraceTime::CLASS_LOAD); | ||
stream = e->open_stream(file_name, CHECK_NULL); | ||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again not obvious this is the right exception to throw. It is also not very informative as to what the actual problem was - isn't it the "source:" that was not found here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be improved in JDK-8263469.
log_warning(cds)("Preload Warning: Cannot find %s", class_name); | ||
stream = e->open_stream(file_name, CHECK_NULL); | ||
if (stream == NULL) { | ||
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be improved in JDK-8263469.
return KlassFactory::create_from_stream(stream, | ||
name, | ||
loader_data, | ||
cl_info, | ||
THREAD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd prefer to see a local introduced and then CHECK used rather than THREAD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is our perennial problem: CHECK cannot be used on a return
statement :-(
See JDK-8064811 (Use THREAD instead of CHECK_NULL in return statements)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InstanceKlass* k = KlassFactory::create_from_stream(stream, name, loader_data, cl_info, CHECK);
return k;
@@ -310,7 +295,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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is executed by the vmThread at dump time then I'd prefer to see current called vmThread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is executed only in the main Java thread.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given we are actually dealing with the VMThread which can't (or shouldn't!) actually throw exceptions I'm concerned about this chunk of code. I don't think we have a good idiom for these cases where the VMThread calls potentially exception throwing code in a way that should never throw an exception. Ideally all the exception-related fields would be in JavaThread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All code changed by this patch executes in the main Java thread.
Mailing list message from David Holmes on hotspot-runtime-dev: On 16/03/2021 2:54 pm, David Holmes wrote:
Mea culpa. Ioi pointed out to me that while the code is for dumping it Thanks, |
Mailing list message from David Holmes on hotspot-runtime-dev: Hi Ioi, All responses about future enhancements noted. A couple of specific On 17/03/2021 11:06 am, Ioi Lam wrote:
Okay I will take care of that one.
Yes but my point is that rather than simply replace CHECK with THREAD I RetType ret = foo(CHECK); rather than: return foo(THREAD);
Noted.
Noted. I will re-examine. Thanks, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Ioi,
It is a bit hard to keep track of the refactorings, but this seems okay.
Thanks,
David
return KlassFactory::create_from_stream(stream, | ||
name, | ||
loader_data, | ||
cl_info, | ||
THREAD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InstanceKlass* k = KlassFactory::create_from_stream(stream, name, loader_data, cl_info, CHECK);
return k;
@iklam This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 2 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the ➡️ To integrate this PR with the above commit message to the |
Mailing list message from Ioi Lam on hotspot-runtime-dev: On 3/16/21 6:34 PM, David Holmes wrote:
Fixed. Thanks |
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), | ||
THREAD->as_Java_thread()->get_thread_stat()->perf_timers_addr(), | ||
PerfClassTraceTime::CLASS_LOAD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was the above removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review. It was removed by mistake and I restore it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. One comment below.
Thanks,
Calvin
…preload-and-dump-should-check-exceptions
Thanks @dholmes-ora and @calvinccheung for the review. |
@iklam Since your change was applied there have been 5 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit 2b93ae0. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
MetaspaceShared::preload_and_dump()
, as well as many of the functions that it calls, have extensive use ofTHREAD
when calling functions that can potentially throw exceptions. Many of these call sites explicitly check for failure status, or assume that the caller would terminate the VM if an exception were to happen. This makes the code hard to understand and potentially unsafe.I have make 3 types of changes:
MetaspaceShared::preload_and_dump()
, where it handles any uncaught exceptions and explicitly terminates the VM.TRAPS
function can never throw, replace theTRAPS
declaration withThread* current
THREAD
immediately followed byHAS_PENDING_EXCEPTION
->CLEAR_PENDING_EXCEPTION
to make the code easy to understand. HandleMark is used to assert that no exception escapes.(See
MetaspaceShared::try_link_class
for an example of 2 and 3).Tested with tiers 1-4.
Progress
Issue
Reviewers
Download
To checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/2925/head:pull/2925
$ git checkout pull/2925
To update a local copy of the PR:
$ git checkout pull/2925
$ git pull https://git.openjdk.java.net/jdk pull/2925/head