RFR(S) 8231125 Improve testing of parallel loading of shared classes by the boot class loader
Ioi Lam
ioi.lam at oracle.com
Thu Sep 19 21:42:03 UTC 2019
On 9/19/19 8:14 AM, coleen.phillimore at oracle.com wrote:
>
>
> On 9/18/19 11:30 PM, Ioi Lam wrote:
>>
>>
>> On 9/18/19 6:47 PM, coleen.phillimore at oracle.com wrote:
>>>
>>> I have to say that the 01 assert matched better what I thought it
>>> should assert, ie. that boot class loaders cannot get to that code
>>> in parallel.
>>>
>>> The mirror has a bunch of other logic with sharing that just
>>> complicates this basic premise. Also, by asserting in the code that
>>> takes out the lock, it doesn't make it clear that two threads with
>>> the bootloader cannot execute that code in parallel.
>>>
>>
>> But the problem with version 01 is two threads could both come to the
>> assert at the same time, and both see that the class loader is not
>> set, and then both would proceed to restore the class.
>
> I think the assert should show that two threads cannot call
> load_shared_class() at the same time, because the second thread is
> waiting on the SystemDictionary_lock because it finds the class in the
> Placeholder table being loaded by a different thread.
>
Hi Coleen,
I moved the assert to the top of load_shared_class(). I can't assert
(ik->class_loader_data() == 0) for non-boot classes, so I added a new
method ik->is_unshareable_info_restored().
http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v04/
I will file separate bugs to: (1) eliminate the if (ik != NULL) at the
top of load_shared_class(). No one should call this function with a NULL
klass. (2) remove the lock before calling restore_unshareable_info. It
shouldn't be necessary.
Thanks
- Ioi
> Coleen
>>
>> Anyway, maybe we should not put the assert in load_shared_class.
>> Instead, move the assert to Klass::restore_unsharable_info():
>>
>> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v03/
>>
>>
>> I also fixed the spacing in the "for" loops in the other test file as
>> requested by David.
>>
>> Thanks
>> - Ioi
>>
>>> I like 01 better (except the test fixes are good).
>>> thanks,
>>> Coleen
>>>
>>> On 9/18/19 2:23 AM, Ioi Lam wrote:
>>>>
>>>>
>>>> On 9/17/19 6:27 PM, David Holmes wrote:
>>>>> Hi Ioi,
>>>>>
>>>>> On 18/09/2019 7:24 am, coleen.phillimore at oracle.com wrote:
>>>>>> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v01/src/hotspot/share/classfile/systemDictionary.cpp.udiff.html
>>>>>>
>>>>>>
>>>>>> Can you add a line something like.
>>>>>>
>>>>>> + if (class_loader() == NULL) {
>>>>>> + // See case 3 in SystemDictionary::resolve_instance_class_or_null
>>>>>> + // multiple threads wait on the SystemDictionary_lock if
>>>>>> the boot loader class is in the placeholder table, so only
>>>>>> + // one thread loads the class.
>>>>>> + assert(ik->class_loader_data() == NULL, "boot loader classes
>>>>>> are not loaded in parallel");
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Even with Coleen's suggested comment I still don't see what this
>>>>> code has to do with loading in parallel? AFAICS all you are
>>>>> asserting is that if the class is to be loaded by the boot-loader
>>>>> then the class should have been dumped by the boot-loader - no?
>>>>>
>>>> Hi David,
>>>>
>>>> When we were analyzing a recent random crash that might be caused
>>>> by race condition during class loading, we looked at this call to
>>>> restore_unshareable_info() in SystemDictionary::load_shared_class()
>>>>
>>>> ClassLoaderData* loader_data =
>>>> ClassLoaderData::class_loader_data(class_loader());
>>>> {
>>>> HandleMark hm(THREAD);
>>>> Handle lockObject = compute_loader_lock_object(class_loader,
>>>> THREAD);
>>>> check_loader_lock_contention(lockObject, THREAD);
>>>> ObjectLocker ol(lockObject, THREAD, true);
>>>> // prohibited package check assumes all classes loaded from
>>>> archive call
>>>> // restore_unshareable_info which calls ik->set_package()
>>>> ik->restore_unshareable_info(loader_data, protection_domain,
>>>> CHECK_NULL);
>>>> }
>>>>
>>>> Because all the crash seemed to be with shared classes loaded by
>>>> the boot loader, we suspect that two threads competing to load the
>>>> same class may arrive here simultaneously, and we will end up
>>>> calling ik->restore_unshareable_info() twice, with harmful side
>>>> effects.
>>>>
>>>> Upon further investigation, we found that this is not the case. But
>>>> it will be good to have an assert to check for this -- that we
>>>> won't call ik->restore_unshareable_info() more than once.
>>>>
>>>> I realized that I put the assert at the wrong place, and asserted
>>>> on the wrong field (non-boot classes will enter load_shared_class()
>>>> with ik->class_loader_data() != NULL). So I changed the assert to
>>>> be on the java_mirror. That way, the assert works for shared
>>>> classes for all loaders.
>>>>
>>>> assert(!ik->is_java_mirror_restored(), "don't load the same
>>>> shared class twice");
>>>> ik->restore_unshareable_info(loader_data, protection_domain,
>>>> CHECK_NULL);
>>>> assert(ik->is_java_mirror_restored() ||
>>>> !SystemDictionary::Class_klass_loaded(), "must be");
>>>>
>>>> Here's an updated webrev, which also contains fixes you suggested
>>>> below.
>>>>
>>>> Thanks
>>>> - Ioi
>>>>
>>>>> The test seems okay - the proof is in the running :)
>>>>>
>>>>> One style nit:
>>>>>
>>>>> ! for (int i=0; i<APP_LOOPS; i++) {
>>>>>
>>>>> spaces around binary operators please. This seems to impact all
>>>>> for loops.
>>>>>
>>>>> Also:
>>>>>
>>>>> 175 { // Avoid logging in this block so the threads
>>>>> can proceeds without
>>>>>
>>>>> s/proceeds/proceed/
>>>>>
>>>>> Thanks,
>>>>> David
>>>>> -----
>>>>>
>>>>>> I wonder if the ObjectLocker is really needed for non-bootclass
>>>>>> loaders below this code, since it appears to not be needed for
>>>>>> boot class loaders.
>>>>>>
>>>>>> The test changes look good. I think you're supposed to have @bug
>>>>>> tags in them.
>>>>>>
>>>>>> Thanks for going through this code looking for races!
>>>>>> Coleen
>>>>>>
>>>>>>
>>>>>> On 9/17/19 1:10 PM, Ioi Lam wrote:
>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8231125
>>>>>>> http://cr.openjdk.java.net/~iklam/jdk14/8231125-shared-boot-class-parallel-test.v01/
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> [1] Modified ParallelLoadTest.java to also test the loading of
>>>>>>> shared classes
>>>>>>> into the boot loader.
>>>>>>> [2] Modified ParallelLoad.java to minimize the initial time lag
>>>>>>> when the 4 parallel
>>>>>>> threads compete to load the same class.
>>>>>>> [3] Added an assert in the JVM to verify that for a shared
>>>>>>> classes loaded
>>>>>>> the boot class loader, SystemDictionary::load_shared_class
>>>>>>> is not called
>>>>>>> multiple times.
>>>>>>>
>>>>>>
>>>>
>>>
>>
>
More information about the hotspot-runtime-dev
mailing list