RFR (S) 8074292: nsk/jdb/kill/kill001: generateOopMap.cpp assert(bb->is_reachable()) failed
coleen.phillimore at oracle.com
coleen.phillimore at oracle.com
Thu Apr 16 02:40:13 UTC 2020
On 4/15/20 1:28 AM, David Holmes wrote:
> On 14/04/2020 10:36 pm, coleen.phillimore at oracle.com wrote:
>> On 4/13/20 10:49 PM, David Holmes wrote:
>>> Hi Coleen,
>>>
>>> On 14/04/2020 12:34 am, coleen.phillimore at oracle.com wrote:
>>>> Summary: Do not install async exceptions at_safepoint for each
>>>> bytecode.
>>>
>>> I'm still not certain that we have to go this far to solve this
>>> problem, but it does sound like a relatively simple solution
>>> provided there are no unintended consequences.
>>>
>>>> See CR for a lot more details. This change calls a new
>>>> InterpreterRuntime::at_safepoint_async_safe() which installs the
>>>> async exception in the interpreter at backward branches and
>>>> returns. This uses safepoint polling code in the interpreter for
>>>> each platform. These changes (cross) compile on platforms that
>>>> Oracle doesn't support but I don't know if they work.
>>>>
>>>> I'm not convinced the platform specific changes are necessary,
>>>> because calls to the runtime from many bytecodes will install the
>>>> async exception, so it's essentially installed "enough" for this
>>>> deprecated feature. I tested the changes with *and* without the
>>>> platform specific changes with no failure, which included the jdb,
>>>> jdi and jvmti serviceability tests.
>>>
>>> I don't understand what you mean here. If the whole basis of this
>>> fix is "don't install async exceptions other than at backward
>>> branches and returns" then how is that implemented without the
>>> changes in the interpreter code?
>>>
>>> If this can be fixed just by adjusting the actual monitor code then
>>> I would much prefer that. It took me a while to get my head around
>>> the dispatch changes in interpreter code and even then I don't see
>>> how those changes only impact backward branches and returns ??
>>
>> You have to read the comments in the bug again. There *is* special
>> code to not install the async exception in the monitorexit code. That
>> is not enough to prevent this bug. You can also read the old bug
>> report you linked to this one.
>
> I know there is some special handling in monitorexit already, I was
> referring to additional special handling around the monitorexit to
> disable whatever piece of code is currently installing the async
> exception.
David pointed out to me offline that the bytecode after monitorexit was
not part of the exception region (see bug comments for details).
I'm withdrawing this RFR.
Coleen
>
>> The interpreter code dispatch_next passes "true" if it's a backwards
>> branch, that's how it can tell.
>
> Okay - I see dispatch_next is passed generate_poll=true for returns
> but I can't see where backward branches come into play. Your changes
> cause the at_safepoint_async_safe to be called in that case, whereas
> any other code paths that lead to at_safepoint no longer install the
> async exception. So things are a bit clearer in that regard.
>
>> My point was that there are enough code paths that install async
>> exceptions *other than monitorenter and monitorexit* that maybe it's
>> not necessary to install them at backwards branches and returns. I
>> suppose someone could construct a test case to show otherwise.
>
> Yes I understood that was the query, but without knowing exactly where
> those code paths are it is hard to comment on whether there is
> adequate coverage. Even with installing on backward branches there is
> a risk that small loops can be unrolled and so lose the check (indeed
> that is what "counted loops" in the JIT does) and thus we rely on
> these other code paths anyway.
>
>>>> This change also makes InterpreterRuntime::monitorexit a JRT_LEAF
>>>> bytecode. The code to check for exceptions is outside the runtime
>>>> call. I ran the JCK vm and lang tests on this change with no failure.
>>>>
>>>> Tested with tier1-6.
>>>>
>>>> open webrev at
>>>> http://cr.openjdk.java.net/~coleenp/2020/8074292.01/webrev
>>>> bug link https://bugs.openjdk.java.net/browse/JDK-8074292
>>>
>>> ./cpu/x86/interp_masm_x86.cpp
>>>
>>> It took me a long time to figure out how the new logic worked
>>> compared to the old logic. Even then I'm unclear about the effective
>>> recursive dispatch path: dispatch_base(generate_poll=true) ->
>>> dispatch_via -> dispatch_base(generate_poll=false) - does it work
>>> okay with VerifyActivationFrameSize? It seems a rather convoluted
>>> way to effectively just execute:
>>>
>>> 858 lea(rscratch1, ExternalAddress((address)table));
>>> 859 jmp(Address(rscratch1, rbx, Address::times_8));
>>
>> I could test it with VerifyActivationFrameSize. Or I could just add
>> the two instructions per platform. I mostly copied the code in
>> generate_safept_entry_for. It might be better to just copy the
>> instructions.
>>
>>>
>>> ---
>>>
>>> src/hotspot/share/interpreter/interpreterRuntime.cpp
>>>
>>> How were you able to drop this code:
>>>
>>> 791 if (elem == NULL || h_obj()->is_unlocked()) {
>>> 792 THROW(vmSymbols::java_lang_IllegalMonitorStateException());
>>> 793 }
>>>
>>> ?
>>> and this:
>>
>> The caller throws the exception for these cases.
>
> Sorry but I don't see that in the caller e.g.
> InterpreterMacroAssembler::unlock_object. Further you are not allowing
> for elem to be NULL which will lead to a crash when you dereference it.
>
>>>
>>> 798 #ifdef ASSERT
>>> 799 thread->last_frame().interpreter_frame_verify_monitor(elem);
>>> 800 #endif
>>>
>>
>> This seemed redundant.
>
> Possibly, but I assume the pairing in monitorenter and monitorexit
> around the actual monitor operation is to ensure that the stack frame
> info is not unexpectedly messed up. Maybe it is redundant to call
> before and after, but then maybe the same is true in monitorenter.
>
> David
> -----
>
>> Coleen
>>> ?
>>>
>>> Thanks,
>>> David
>>>
>>>> Thanks,
>>>> Coleen
>>>>
>>
More information about the serviceability-dev
mailing list