RFR: 8249451: Unconditional exceptions clearing logic in compiler code should honor Async Exceptions
Jamsheed C M
jamsheed.c.m at oracle.com
Mon Aug 24 05:36:51 UTC 2020
Hi David,
Thank you for the review and feedback. Agree on all of them. I will
rework and get back.
On 10/08/2020 07:33, David Holmes wrote:
> 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/
>
Ok
> 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()) {
>
Ok
> 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.
>
Ok
> ---
>
> 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*".
>
Ok
> 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.
>
Ok
> ---
>
> + // 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/
>
>
Ok
>> 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.
>
Ok
> Thanks again for tackling this difficult problem!
Best regards,
Jamsheed
>
> 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