RFR: 8234426: Sweeper should not CompiledIC::set_to_clean with ICStubs for is_unloading() nmethods

Erik Österlund erik.osterlund at oracle.com
Mon Dec 2 17:01:54 UTC 2019


Hi Stefan,

Thank you for the review. Your analysis is exactly right!

Thanks,
/Erik

On 2019-12-02 15:45, Stefan Karlsson wrote:
> Hi Erik,
>
> After discussing this with Erik, I think this looks good. Just to 
> recapture some of my questions and thoughts:
>
> The nmethod can be in three interesting states when the sweeper 
> executes this code:
> 1) is_alive && !is_unloading
> 2) is_alive && is_unloading
> 3) !is_alive && is_unloading
>
> The transition from (2) to (3) happens when the GC is unloading the 
> nmethod concurrently while the sweeper is processing the nmethod. It's 
> only interesting to bring up state (3), because this is the reason why 
> we can't assert that the nmethod is_alive.
>
> The interesting transition happens between (1) and (2), and this 
> transition is well-synchronized between the GC and sweeper by means of 
> the synchronization protocol in nmethod::is_unloading.
>
> In (1) all oops are good and the nmethod is guaranteed to not be 
> unloaded.
> In (2) at least one of the oops are bad and the nmethod is on its way 
> to become unloaded
>
> The sweeper communicates that it's processing an nmethod by exposing 
> it to the root set of the threads. We are OK with exposing (1) 
> nmethods, but we must make sure we never expose (2) nmethods.
>
> The only time the sweeper-processed nmethod is exposed to the root set 
> of the threads is when we safepoint. The only path that can safepoint 
> in set_to_clean(bool in_use) is when we're using ICStubs. However, we 
> don't need to use ICStubs when an nmethod is not "in use". 
> is_unloading nmethods (2) are not "in use", otherwise they would have 
> been found by root scanning and/or entry barriers and would have 
> stayed !is_unloading. Therefore the code was changed to 
> set_to_clean(!is_unloading()).
>
> Thanks,
> StefanK
>
> On 2019-11-22 11:49, erik.osterlund at oracle.com wrote:
>> Hi,
>>
>> When the sweeper processes an nmethod, it will clean inline caches if 
>> it is_alive().
>> Today, the cleaning will utilize transitional states (using ICStubs) 
>> if the nmethod is_alive(),
>> which is always true for the sweeper. If it runs out of ICStubs, it 
>> might have to safepoint
>> to refill them. When it does, the currently processed nmethod might 
>> be is_unloading().
>> That is not a problem for the GC per se (safepoint operation fusing 
>> with mark end), but it
>> is a problem for heap walkers that get confused that an nmethod 
>> reachable from a thread is unloading
>> and hence has dead oops in it. This sweeper nmethod is the *only* 
>> nmethod that violates an
>> invariant that nmethods reachable from threads (Thread::nmethods_do) 
>> are not unloading.
>>
>> By simply changing the condition to not use ICStubs when the nmethod 
>> is_unloading(), we
>> get this neat invariant, and code gets less confused about this.
>>
>> Bug:
>> https://bugs.openjdk.java.net/browse/JDK-8234426
>>
>> Webrev:
>> http://cr.openjdk.java.net/~eosterlund/8234426/webrev.00/
>>
>> Thanks,
>> /Erik
>



More information about the hotspot-dev mailing list