RFR: 8249451: Unconditional exceptions clearing logic in compiler code should honor Async Exceptions
David Holmes
david.holmes at oracle.com
Mon Aug 10 02:03:35 UTC 2020
Hi Jamsheed,
On 6/08/2020 10:07 pm, Jamsheed C M wrote:
> Hi all,
>
> JBS: https://bugs.openjdk.java.net/browse/JDK-8249451
>
> webrev: http://cr.openjdk.java.net/~jcm/8249451/webrev.00/
Thanks for tackling this messy issue. Overall I like the use of TRAPS to
more clearly document which methods can return with an exception
pending. I think there are some problems with the proposed changes. I'll
start with those comments and then move on to more general comments.
src/hotspot/share/utilities/exceptions.cpp
src/hotspot/share/utilities/exceptions.hpp
I don't think the changes here are correct or safe in general.
First, adding the new macro and function to only clear non-async
exceptions is fine itself. But naming wise the fact only non-async
exceptions are cleared should be evident, and there is no "check"
involved (in the sense of the existing CHECK_ macros) so I suggest:
s/CHECK_CLEAR_PENDING_EXCEPTION/CLEAR_PENDING_NONASYNC_EXCEPTIONS/
s/check_clear_pending_exception/clear_pending_nonasync_exceptions/
But changing the existing CHECK_AND_CLEAR macros to now leave async
exceptions pending seems potentially dangerous as calling code may not
be prepared for there to now be a pending exception. For example the use
in thread.cpp:
JDK_Version::set_runtime_name(get_java_runtime_name(THREAD));
JDK_Version::set_runtime_version(get_java_runtime_version(THREAD));
get_java_runtime_name() is currently guaranteed to clear all exceptions,
so all the other code is known to be safe to call. But that would no
longer be true. That said, this is VM initialization code and an async
exception is impossible at this stage.
I think I would rather see CHECK_AND_CLEAR left as-is, and an actual
CHECK_AND_CLEAR_NONASYNC introduced for those users of CHECK_AND_CLEAR
that can encounter async exceptions and which should not clear them.
+ if (!_pending_exception->is_a(SystemDictionary::ThreadDeath_klass()) &&
+ _pending_exception->klass() !=
SystemDictionary::InternalError_klass()) {
Flagging all InternalErrors as async exceptions is probably also not
correct. I don't see a good solution to this at the moment. I think we
would need to introduce a new subclass of InternalError for the unsafe
access error case**. Now it may be that all the other InternalError
usages are "impossible" in the context of where the new macros are to be
used, but that is very difficult to establish or assert.
** Or perhaps we could inject a field that allows the VM to identify
instances related to unsafe access errors ... Ideally of course these
unsafe access errors would be distinct from the async exception
mechanism - something I would still like to pursue.
---
General comments ...
There is a general change from "JavaThread* thread" to "Thread* THREAD"
(or TRAPS) to allow the use of the CHECK macros. This is unfortunate
because the fact the thread is restricted to being a JavaThread is no
longer evident in the method signatures. That is a flaw with the
TRAPS/CHECK mechanism unfortunately :( . But as the methods no longer
take a JavaThread* arg, they should assert that
THREAD->is_Java_thread(). I will also look at an RFE to have
as_JavaThread() to avoid the need for separate assertion checks before
casting from "Thread*" to "JavaThread*".
Note there's no need to use CHECK when the enclosing method is going to
return immediately after the call that contains the CHECK. It just adds
unnecessary checking of the exception state. The use of TRAPS shows that
the methods may return with an exception pending. I've flagged all such
occurrences I spotted below.
---
+ // Only metaspace OOM is expected. no Java code executed.
Nit: s/no/No
src/hotspot/share/compiler/compilationPolicy.cpp
410 method_invocation_event(method, CHECK_NULL);
489 CompileBroker::compile_method(m, InvocationEntryBci,
comp_level, m, hot_count, CompileTask::Reason_InvocationCount, CHECK);
Nit: there's no need to use CHECK here.
---
src/hotspot/share/compiler/tieredThresholdPolicy.cpp
504 method_invocation_event(method, inlinee, comp_level, nm,
CHECK_NULL);
570 compile(mh, bci, CompLevel_simple, CHECK);
581 compile(mh, bci, CompLevel_simple, CHECK);
595 CompileBroker::compile_method(mh, bci, level, mh, hot_count,
CompileTask::Reason_Tiered, CHECK);
1062 compile(mh, InvocationEntryBci, next_level, CHECK);
Nit: there's no need to use CHECK here.
814 void TieredThresholdPolicy::create_mdo(const methodHandle& mh,
Thread* THREAD) {
Thank you for correcting this misuse of the THREAD name on a JavaThread*
type.
---
src/hotspot/share/interpreter/linkResolver.cpp
128 CompilationPolicy::compile_if_required(selected_method, CHECK);
Nit: there's no need to use CHECK here.
---
src/hotspot/share/jvmci/compilerRuntime.cpp
260 CompilationPolicy::policy()->event(emh, mh,
InvocationEntryBci, InvocationEntryBci, CompLevel_aot, cm, CHECK);
280 nmethod* osr_nm = CompilationPolicy::policy()->event(emh, mh,
branch_bci, target_bci, CompLevel_aot, cm, CHECK);
Nit: there's no need to use CHECK here.
---
src/hotspot/share/jvmci/jvmciRuntime.cpp
102 // Donot clear probable async exceptions.
typo: s/Donot/Do not/
---
src/hotspot/share/runtime/deoptimization.cpp
1686 void Deoptimization::load_class_by_index(const constantPoolHandle&
constant_pool, int index) {
This method should be declared with TRAPS now.
1693 // Donot clear probable Async Exceptions.
typo: s/Donot/Do not/
> testing : mach1-5(links in jbs)
There is very little existing testing that will actually test the key
changes you have made here. You will need to do direct fault-injection
testing anywhere you now allow async exceptions to remain, to see if the
calling code can tolerate that. It will be difficult to test thoroughly.
Thanks again for tackling this difficult problem!
David
-----
>
> While working on JDK-8246381 it was noticed that compilation request
> path clears all exceptions(including async) and doesn't propagate[1].
>
> Fix: patch restores the propagation behavior for the probable async
> exceptions.
>
> Compilation request path propagate exception as in [2]. MDO and
> MethodCounter doesn't expect any exception other than metaspace
> OOM(added comments).
>
> Deoptimization path doesn't clear probable async exceptions and take
> unpack_exception path for non uncommontraps.
>
> Added java_lang_InternalError to well known classes.
>
> Request for review.
>
> Best Regards,
>
> Jamsheed
>
> [1] w.r.t changes done for JDK-7131259
>
> [2]
>
> (a)
> -----> c1_Runtime1.cpp/interpreterRuntime.cpp/compilerRuntime.cpp
> |
> ----- compilationPolicy.cpp/tieredThresholdPolicy.cpp
> |
> ------ compileBroker.cpp
>
> (b)
> Xcomp versions
> ------> compilationPolicy.cpp
> |
> ------> compileBroker.cpp
>
> (c)
>
> Direct call to compile_method in compileBroker.cpp
>
> JVMCI bootstrap, whitebox, replayCompile.
>
>
More information about the hotspot-compiler-dev
mailing list