[9] RFR (M): 8139595: MethodHandles::remove_dependent_nmethod is not MT safe
Coleen Phillimore
coleen.phillimore at oracle.com
Wed Nov 11 20:20:34 UTC 2015
I still like the refactoring. I don't have further comments but I
didn't study what the DependencyContext does, so hopefully your other
reviewers looked at that.
Coleen
On 11/11/15 10:43 AM, Vladimir Ivanov wrote:
> Coleen, John, thanks for the feedback!
>
> Updated version:
> http://cr.openjdk.java.net/~vlivanov/8139595/webrev.03/
>
> * Added InstanceKlass::dependencies()
>
> * Removed the fields from vmStructs since they aren't used in SA
> (tmtools tests passed).
>
> * Added missing includes in dependencyContext.hpp. Previous version
> built fine (even w/o precompiled headers), but I think it worked due
> to header inclusion order.
>
> * Added verification of CallSite oop validity across DependencyContext
> lifetime.
>
> Though previous comments were focused on dependency management code
> refactoring, I'd like to hear opinions about the fix itself -
> dependency management changes for j.l.i.CallSites to avoid
> modifications during concurrent traversals by GC threads.
>
> Quote from the original request:
> "The fix I propose is to avoid purging of CallSiteContext contexts at
> all during GC, but remove stale entries during dependency list updates
> which happen under CodeCache lock (see safe_to_purge() check in
> methodHandles.cpp). It happens outside of safepoints and it guarantees
> exclusive access to the list. It is performed during
> j.l.i.CallSite.target updates, CallSite.target inlining, j.l.Class
> unloading, etc. Such approach allows to avoid unbounded memory
> consumption growth, only some delay (till next dependency list update)
> in memory deallocation."
>
> Best regards,
> Vladimir Ivanov
>
> On 11/10/15 5:37 AM, John Rose wrote:
>> I think this expression occurs too many times:
>> DependencyContext dep_context(&_dep_context);
>>
>> It would look better if factored into an access method:
>> inline DependencyContext InstanceKlass::dependencies() {
>> DependencyContext dep_context(&_dep_context);
>> return dep_context;
>> }
>>
>> That way the raw machine word InstanceKlass::_dep_context can be
>> isolated.
>> CallSiteContext::vmdependencies already does the corresponding move
>> for CallSite.
>> (I understand that you don't want to make ik.hpp depend on dc.hpp.
>> Just put forward declarations of Deps and IK::deps in ik.hpp.)
>>
>> Mild suggestion: Add a constructor parameter to capture the base oop
>> (of the callsite, or null for the IK).
>> Use it only in debug mode to check for GC changes. Or sample a
>> global GC or safepoint count.
>> The point is that the lifetime of the Deps object should not extend
>> beyond the next safepoint.
>>
>> I agree with Coleen: This is a good refactor.
>>
>> Reviewed.
>>
>> — John
>>
>> On Nov 6, 2015, at 5:03 AM, Vladimir Ivanov
>> <vladimir.x.ivanov at oracle.com> wrote:
>>>
>>> Thanks, Coleen!
>>>
>>> Updated version:
>>> http://cr.openjdk.java.net/~vlivanov/8139595/webrev.02/
>>>
>>>> I think DependencyContext is big enough to be a new file, and not be
>>>> added to instanceKlass.hpp. There are too many unrelated things in
>>>> instanceKlass.
>>> Agree. Moved it to src/share/vm/code/dependencyContext.[ch]pp
>>>
>>>> The hidden bit stuff is ok in InstanceKlass. Does
>>>> has_unloaded_dependent accessed concurrently like
>>>> _is_marked_dependent?
>>> Good point. DependencyContext::remove_dependent_nmethod should set
>>> has_stale_entries in a thread safe manner (added Atomic::xchg_ptr
>>> call).
>>> It is not needed when the flag is cleared.
>>>
>>>> It would be nice to move _is_marked_dependent
>>>> field also to encapsulate it but that would ruin your bit packing.
>>> There's a spare bit to use, but I think _is_marked_dependent is
>>> specific to InstanceKlass and should remain there. It doesn't have
>>> any meaning for CallSite dependencies.
>>>
>>>> Also, since you have changes to vmStructs, do you have duplicate
>>>> changes
>>>> to make to the serviceability agent code? Are there duplicate changes
>>>> for the jvmci code?
>>> I haven't found any mentions of _has_unloaded_dependent or
>>> _dependencies fields in SA or JVMCI code. Do you think it is an
>>> overlook on SA side and I should add it?
>>>
>>> Best regards,
>>> Vladimir Ivanov
>>>
>>>>
>>>> Thanks,
>>>> Coleen
>>>>
>>>> On 11/5/15 1:54 PM, Vladimir Ivanov wrote:
>>>>> Updated version:
>>>>> http://cr.openjdk.java.net/~vlivanov/8139595/webrev.01/
>>>>>
>>>>> In addition to name polishing and encapsulating purging logic in
>>>>> {add|remove}_dependent_nmethod methods, I got rid of
>>>>> DependencyContext::wipe() method and added "friend class
>>>>> TestDependencyContext" declaration (noticed such practice in other
>>>>> cases when tests need access to tested class internals).
>>>>>
>>>>> Best regards,
>>>>> Vladimir Ivanov
>>>>>
>>>>> On 11/5/15 7:46 PM, Aleksey Shipilev wrote:
>>>>>> On 11/05/2015 04:54 PM, Vladimir Ivanov wrote:
>>>>>>> Regarding internal purging, add_dependent_methods doesn't
>>>>>>> iterate over
>>>>>>> the whole list, but looks for the relevant entry. It means that
>>>>>>> "purge"
>>>>>>> flag should force full iteration. I think that keeping them
>>>>>>> separately
>>>>>>> (add_dependent_methods() vs purge()) looks cleaner.
>>>>>>
>>>>>> I think it is better to encapsulate the "piggybacking" behavior
>>>>>> within
>>>>>> the DependencyContext itself, because that seems to be a
>>>>>> general/expected feature of DependencyContext class. It is weird
>>>>>> to ask
>>>>>> class users to spell it out specifically.
>>>>>>
>>>>>>
>>>>>>> I could add "purge" flag and move the following code into
>>>>>>> add_dependent_methods:
>>>>>>> void DependencyContext::add_dependent_nmethod(nmethod* nm, bool
>>>>>>> do_purge
>>>>>>> = false) {
>>>>>>> ...
>>>>>>> if (has_unloaded_dependent() && do_purge) {
>>>>>>> purge();
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>> Is it what you are suggesting?
>>>>>>
>>>>>> Yes.
>>>>>>
>>>>>>
>>>>>>>> * DependencyContext now has three methods: purge(), clear(),
>>>>>>>> wipe(). I
>>>>>>>> have trouble understanding which method does what!
>>>>>>
>>>>>>> There are basically 2 operations needed:
>>>>>>> * purge(): only remove stale entries; no additional work is
>>>>>>> performed;
>>>>>>
>>>>>> Oh. Should probably mention "stale" in the name. See e.g. Java-ish:
>>>>>> WeakHashMap.expungeStaleEntries()
>>>>>> ThreadLocal.expungeStaleEntries()
>>>>>> WeakCache.expungeStaleEntries()
>>>>>>
>>>>>>
>>>>>>> wipe() is only for unit-testing purposes (see
>>>>>>> TestNmethodBucket): it
>>>>>>> just deallocates all nmethodBucket entries without touching
>>>>>>> nmethods. It
>>>>>>> is necessary since nmethod pointers are faked by the test.
>>>>>>
>>>>>> Okay. Is there a convention how you should name the test-related
>>>>>> methods
>>>>>> like these? I would expect something like
>>>>>> debug_deallocate_buckets().
>>>>>>
>>>>>> Thanks,
>>>>>> -Aleksey
>>>>>>
>>>>>>
>>>>
>>
More information about the hotspot-dev
mailing list