RFR: 8038468: java/lang/instrument/ParallelTransformerLoader.sh fails with ClassCircularityError
serguei.spitsyn at oracle.com
serguei.spitsyn at oracle.com
Mon Oct 27 18:00:36 UTC 2014
Ok.
Thanks, Dan!
Serguei
On 10/27/14 7:05 AM, Daniel D. Daugherty wrote:
> > The test case was added by Dan.
> > We may want to ask him to clarify the test case purpose.
> > (added Dan to the to-list)
>
> Here's the changeset that added the test:
>
> $ hg log -v -r bca8bf23ac59
> test/java/lang/instrument/ParallelTransformerLoader.sh
> changeset: 132:bca8bf23ac59
> user: dcubed
> date: Mon Mar 24 15:05:09 2008 -0700
> files: test/java/lang/instrument/ParallelTransformerLoader.sh
> test/java/lang/instrument/ParallelTransformerLoaderAgent.java
> test/java/lang/instrument/ParallelTransformerLoaderApp.java
> test/java/lang/instrument/TestClass1.java
> test/java/lang/instrument/TestClass2.java
> test/java/lang/instrument/TestClass3.java
> description:
> 5088398: 3/2 java.lang.instrument TCK test deadlock (test11)
> Summary: Add regression test for single-threaded bootstrap classloader.
> Reviewed-by: sspitsyn
>
>
> Based on my e-mail archive for this bug and from the bug report itself,
> it looks like we got this test from Wily Labs. The original bug was a
> deadlock that stopped being reproducible after:
>
> Karen fixed the bootstrap class loader to work in parallel via:
>
> 4997893 4/5 Investigate allowing bootstrap loader to work in parallel
>
> with that fix in place the deadlock no longer reproduces.
> I'm planning to use this bug as the vehicle for getting
> the test program into the INSTRUMENT_REGRESSION test suite.
>
> *** (#2 of 2): 2008-02-29 18:20:17 GMT+00:00 daniel.daugherty at sun.com
>
>
> A careful reading of JDK-5088398 might reveal the intentions of this
> test...
>
> Dan
>
>
> On 10/24/14 5:57 PM, serguei.spitsyn at oracle.com wrote:
>> Yumin,
>>
>> On 10/24/14 4:08 PM, Yumin Qi wrote:
>>> Serguei,
>>>
>>> Thanks for your comments.
>>> This test happens intermittently, but now it can repeat with 8/9.
>>> Loading TestClass1 in main thread while loading TestClass2 in
>>> TestThread in parallel. They both will call transform since
>>> TestClass[1-3] are loaded via agent. When loading TestClass2, it
>>> will call loading TestClass3 in TestThread.
>>> Note in the main thread, for loop:
>>>
>>> for (int i = 0; i < kNumIterations; i++)
>>> {
>>> // load some classes from multiple threads
>>> (this thread and one other)
>>> Thread testThread = new TestThread(2);
>>> testThread.start();
>>> loadClasses(1);
>>>
>>> // log that it completed and reset for the
>>> next iteration
>>> testThread.join();
>>> System.out.print(".");
>>> ParallelTransformerLoaderAgent.generateNewClassLoader();
>>> }
>>>
>>> The loader got renewed after testThread.join(). So both threads are
>>> using the exact same class loader.
>>
>> You are right, thanks.
>> It means that all three classes (TesClass1, TestClass2 and TestClass3)
>> are loaded by the same class loader in each iteration.
>>
>> However, I see more cases when the TestClass3 gets loaded.
>> It happens in a CFLH event when any other class (not TestClass*) in
>> the system is loaded.
>> The class loading thread can be any, not only "main" or "TestClass"
>> thread.
>> I suspect this test case mostly targets class loading that happens on
>> other threads.
>> It is because of the lines:
>> // In 160_03 and older, transform() is called
>> // with the "system_loader_lock" held and that
>> // prevents the bootstrap class loaded from
>> // running in parallel. If we add a slight sleep
>> // delay here when the transform() call is not
>> // main or TestThread, then the deadlock in
>> // 160_03 and older is much more reproducible.
>> if (!tName.equals("main") &&
>> !tName.equals("TestThread")) {
>> System.out.println("Thread '" + tName +
>> "' has called transform()");
>> try {
>> Thread.sleep(500);
>> } catch (InterruptedException ie) {
>> }
>> }
>>
>> What about the following?
>>
>> In the ParallelTransformerLoaderAgent.java make this change:
>> if (!tName.equals("main"))
>> => if (tName.equals("TestThread"))
>>
>> Does such updated test still failing?
>>
>>> After create a new class loader, next loop will use the loader. This
>>> is why quite often on the stack trace we can see it resolves
>>> JarLoader$2.
>>>
>>> I am not quite understand the test case either. Loading TestClass3
>>> inside transform using the same classloader will cause call to
>>> transform again and form a circle. Nonetheless, if we see TestClass2
>>> already loaded, the loop will end but that still is a risk.
>>
>> In fact, I don't like that the test loads the class TestClass3 at the
>> TestClass3 CFLH event.
>> However, it is interesting to know why we did not see (is it the
>> case?) this issue before.
>> Also, it is interesting why the test stops failing with you fix
>> (replacing loader with SystemClassLoader).
>>
>> The test case was added by Dan.
>> We may want to ask him to clarify the test case purpose.
>> (added Dan to the to-list)
>>
>> Thanks,
>> Serguei
>>
>>>
>>> Thanks
>>> Yumin
>>>
>>> On 10/24/2014 1:20 PM, serguei.spitsyn at oracle.com wrote:
>>>> Hi Yumin,
>>>>
>>>> Below is some analysis to make sure I understand the test scenario
>>>> correctly.
>>>>
>>>> The ParallelTransformerLoaderApp.main() executes a 1000 iteration loop.
>>>> At each iteration it does:
>>>> - creates and starts a new TestThread
>>>> - loads TestClass1 with the current class loader:
>>>> ParallelTransformerLoaderAgent.getClassLoader()
>>>> - changes the current class loader with new one:
>>>> ParallelTransformerLoaderAgent.generateNewClassLoader()
>>>>
>>>> The TestThread loads the TestClass2 concurrently with the main thread.
>>>>
>>>> At the CFLH events, the ParallelTransformerLoaderAgent does the
>>>> class retransformation.
>>>> If the thread loading the class is not "main", it loads the class
>>>> TestClass3
>>>> with the current class loader
>>>> ParallelTransformerLoaderAgent.getClassLoader().
>>>>
>>>> Sometimes, the TestClass2 and TestClass3 are loaded by the same
>>>> class loader recursively.
>>>> It happens if the class loader has not been changed between loading
>>>> TestClass2 and TestClass3 classes.
>>>>
>>>> I'm not convinced yet the test is incorrect.
>>>> And it is not clear why do we get a ClassCircularityError.
>>>>
>>>> Please, let me know if the above understanding is wrong.
>>>> I also see the reply from David and share his concerns.
>>>>
>>>> It is not clear if this failure is a regression.
>>>> Did we observe this issue before?
>>>> If - NOT then when and why had this failure started to appear?
>>>>
>>>> Unfortunately, it is impossible to look at the test run history at
>>>> the moment.
>>>> The Aurora is at a maintenance.
>>>>
>>>> Thanks,
>>>> Serguei
>>>>
>>>> On 10/13/14 3:58 PM, Yumin Qi wrote:
>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8038468
>>>>> webrev:*http://cr.openjdk.java.net/~minqi/8038468/webrev00/
>>>>>
>>>>> the bug marked as confidential so post the webrev internally.
>>>>>
>>>>> Problem: The test case tries to load a class from the same jar via
>>>>> agent in the middle of loading another class from the jar via same
>>>>> class loader in same thread. The call happens in transform which
>>>>> is a rare case --- in middle of loading class, loading another
>>>>> class. The result is a CircularityError. When first class is in
>>>>> loading, in vm we put JarLoader$2 on place holder table, then we
>>>>> start the defineClass, which calls transform, begins loading the
>>>>> second class so go along the same routine for loading JarLoader$2
>>>>> first, found it already in placeholder table. A CircularityError
>>>>> is thrown.
>>>>> Fix: The test case should not call loading class with same class
>>>>> loader in same thread from same jar in 'transform' method. I
>>>>> modify it loading with system class loader and we expect see
>>>>> ClassNotFoundException. Detail see bug comments.
>>>>>
>>>>> Thanks
>>>>> Yumin *
>>>>
>>>
>>
>
More information about the jdk9-dev
mailing list