RFR: 8213209: [REDO] Allow Klass::_subklass and _next_sibling to have unloaded classes
dean.long at oracle.com
dean.long at oracle.com
Tue Nov 27 06:11:38 UTC 2018
Looks OK to me too. The lazy initialization of _has_subklass probably
isn't needed anymore, but it does seem to be an improvement.
dl
On 11/19/18 4:52 AM, Erik Österlund wrote:
> Hi Coleen,
>
> Thanks for the review.
>
> Full webrev:
> http://cr.openjdk.java.net/~eosterlund/8213209/webrev.01/
>
> Incremental webrev:
> http://cr.openjdk.java.net/~eosterlund/8213209/webrev.00_01/
>
> On 2018-11-16 22:08, coleen.phillimore at oracle.com wrote:
>>
>> Erik, thank you for taking this change and making it lock-free.
>>
>> On 11/16/18 1:12 PM, Erik Österlund wrote:
>>> Hi,
>>>
>>> This is a redo of Coleen's earlier patch to clean weak metadata
>>> links using the Compile_lock.
>>>
>>> We noticed the proposed solution could cause deadlocks. At least one
>>> of the reasons for that is that the Compile_lock was taken during
>>> printing and verification in safepoints. And the Compile_lock is
>>> sometimes held while issuing safepoints. The latter problem also
>>> forces us to take the Compile_lock before joining the suspendible
>>> thread set, to avoid another deadlock situation. But that is really
>>> nasty for other reasons. And there have been a few more problems as
>>> well.
>>>
>>> So in this case, we think it is both safer, less error prone, and
>>> better performing (although less important) to perform this cleaning
>>> in a lock-free fashion rather than trying to dodge all the issues
>>> related to the locking protocol.
>>>
>>> Inserts still require a lock. Therefore, we are dealing with
>>> lock-free reads, and lock-free cleaning. The lock-free cleaning is
>>> interacting with multiple lock-free readers and a single writer.
>>>
>>> The single inserter always helps with cleaning the subclass list
>>> head before prepending new nodes to the chain. That allows an
>>> invariant that the siblings link is never inserted pointing at a
>>> Klass that is unloading, which simplifies things a lot. The head is
>>> inserted in a classic load + CAS in a loop.
>>>
>>> Readers require load_acquire when reading the head, due to competing
>>> inserts putting new Klass pointers there. The siblings, however,
>>> only need relaxed consistency, because they are linked to data
>>> strictly older than the head, which has already been acquired.
>>>
>>> Unlinked entries are all inserted into a purge list, because freeing
>>> them immediately is not safe. A global handshake operation is
>>> performed, and after that ClassLoaderDataGraph::purge() will go
>>> through the list and delete the entries safely.
>>
>> I don't see the purge list in your change, and it's not needed since
>> this is unlinking in place. I think this is your other change you're
>> thinking of.
>
> Yes you are right, of course. It's the unloading list and not a
> separate purge list...
>
>> Should the Compile_lock be removed in ciInstanceKlass.cpp
>> ciInstanceKlass* ciInstanceKlass::implementor() {
>>
>> and in jvmciCompilerToVM.cpp
>> C2V_VMENTRY(jobject, getImplementor, (JNIEnv *, jobject, jobject
>> jvmci_type))
>>
>> The former does a bit more than calling implementor(). Or do you
>> want to leave these locks to be conservative?
>
> While I think your analysis is correct, I would indeed like to leave
> them in this RFE to be conservative.
>
>> JVMCIKlassHandle handle(THREAD);
>> {
>> // Need Compile_lock around implementor()
>> MutexLocker locker(Compile_lock);
>> handle = iklass->implementor();
>> }
>>
>>
>> http://cr.openjdk.java.net/~eosterlund/8213209/webrev.00/src/hotspot/share/oops/instanceKlass.cpp.udiff.html
>>
>>
>> nof_implementors() has an assert_locked_or_safepoint(Compile_lock);
>> which it no longer needs. You'll hit this from printing because
>> you've removed the locking here:
>>
>> 3093 if (is_interface()) {
>> 3094 MutexLocker ml(Compile_lock);
>> 3095 st->print_cr(BULLET"nof implementors: %d",
>> nof_implementors());
>> 3096 if (nof_implementors() == 1) {
>> 3097 st->print_cr(BULLET"implementor: ");
>> 3098 st->print(" ");
>> 3099 implementor()->print_value_on(st);
>> 3100 st->cr();
>> 3101 }
>>
>>
>> We don't test printing very well.
>>
>
> Ahh yes - good catch. I removed the assert as it is no longer required.
>
>> http://cr.openjdk.java.net/~eosterlund/8213209/webrev.00/src/hotspot/share/utilities/vmError.cpp.udiff.html
>>
>>
>> This file is unchanged except a line removed.
>
> I put it back the way it was before.
>
>> This change looks good. I've run through the tests with it and
>> didn't find any problems that doomed my earlier version.
>
> Thank you for running additional tests on this patch!
>
> Thanks,
> /Erik
>
>> Thanks!!
>> Coleen
>>>
>>> Webrev:
>>> http://cr.openjdk.java.net/~eosterlund/8213209/webrev.00/
>>>
>>> Bug:
>>> https://bugs.openjdk.java.net/browse/JDK-8213209
>>>
>>> Thanks,
>>> /Erik
>>
>
More information about the hotspot-dev
mailing list