harmony-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Xiao-Feng Li" <xiaofeng...@gmail.com>
Subject Re: [class loading] what's the expected behavior when a static method is invoked before its class is initialized?
Date Mon, 05 Jan 2009 08:48:22 GMT
Please try with EUT3.5 before committing... :)

Thanks,
xiaofeng

On Mon, Jan 5, 2009 at 4:34 PM, chunrong lai <chunronglai@gmail.com> wrote:
> Thanks for the discussion.
> Now it makes sense to me that the initializeClass from newarray operation
>
> //OPCODE_ANEWARRAY
> static void *rth_newarray_withresolve(Class_Handle klass, unsigned cp_idx,
> unsigned arraySize) {
>    ASSERT_THROW_AREA;
>    //resolve and init object class
>    Class* objClass = resolveClass(klass, cp_idx, false);
>    initializeClass(objClass);    //should be removed
>    assert(!objClass->is_primitive());
>
> can be removed.
> After removing it I see the HARMONY-6020 and other test cases I built can
> pass with same behavior with RI. I am going to commit it. For you have more
> feedbacks please let me know.
>
> chunrong
> Managed Runtime Technology Center, Intel
> On Mon, Jan 5, 2009 at 2:19 PM, Regis <xu.regis@gmail.com> wrote:
>
>>
>>
>> Xiao-Feng Li wrote:
>>
>>> On Mon, Jan 5, 2009 at 5:12 AM, Ian Rogers <rogers.email@gmail.com>
>>> wrote:
>>>
>>>> 2009/1/4 Nathan Beyer <ndbeyer@apache.org>
>>>>
>>>> Could any of the IBM folks on the list get some advice from some class
>>>>> loader experts?
>>>>>
>>>>> -Nathan
>>>>>
>>>>>  Hi Nathan,
>>>>
>>>> from reading the description I can describe how Jikes RVM avoids this
>>>> problem (I'm not an IBM VME expert and I've not run the test case to
>>>> check
>>>> that Jikes RVM passes it). In Jikes RVM we have two variants of all
>>>> calls,
>>>> ones to unresolved methods and ones to resolved methods. Unresolved calls
>>>> are to classes whose initializer hasn't yet been run. If two threads are
>>>> calling a static method the first will resolve it and in the process
>>>> acquire
>>>> a lock, the second thread must wait for the lock before it can attempt to
>>>> resolve the method (at which point it will discover the method was
>>>> resolved
>>>> by the other thread and leave early). Checking for classes being resolved
>>>> litters all of the class loader code, and we're slightly proactive in
>>>> resolving in the case of reflected methods so that we needn't check for
>>>> resolution when performing reflected method invocation (which is now
>>>> pretty
>>>> much unnecessary since [1] where we generate bytecodes at runtime to
>>>> perform
>>>> reflection). An aside, I wrote a paper where I use the class loader as a
>>>> test case for optimizations based on stationary/immutable fields
>>>> specified
>>>> via constraints [2], this work specialized the class loader to handle the
>>>> resolved case as a class is normally accessed when it is resolved
>>>> (figures
>>>> in the paper).
>>>>
>>>
>>> Thanks for the explanation.
>>>
>>> Let me try to explain the problem we are meeting:
>>>
>>> 1. A thread invokes a static method createChild of a class Parent. It
>>> causes class Parent be initialized.
>>>
>>> 2. In Parent's initialization, it creates an array of class Child. It
>>> leads to class Child be initialized.
>>>
>> if add following code to Child
>>    static {
>>        System.err.println("init Child");
>>    }
>> the output on RI is:
>> null
>> init Child
>> null
>>
>> It seems create array of class Child doesn't lead to class Child be
>> initialized
>>
>> if change childCache from array to instance:
>>
>>    private static final Child childCache = new Child();
>>
>>    public static Child createChild(){
>>        return childCache;
>>    }
>> the output on RI is:
>> init Child
>> Child@affc70
>> null
>>
>> It seems when initialize Child, Parent.createChild() is called, and read
>> the value of childCache, it's not initialized, so null is returned (it's
>> already in initialize process, so just return null?).
>>
>>
>>> 3. In Child's initialization, it invokes Parent.createChild() to
>>> initialize a static field ROOT. This leads to re-entrance of Parent
>>> initialization.
>>>
>>> 4. The thread finds Parent is under initialization by itself, it quits
>>> the initialization process and invokes Parent.createChild().
>>>
>>> 5. This invocation should not be permitted by the VM spec, and we
>>> don't know how to deal with it. It can't wait for the initialization
>>> process finished, because it is in the path of the initialization. It
>>> has to do something to proceed with the initialization.
>>>
>>> Below is the code of the micro test. Chunrong, please correct me if my
>>> understanding is inaccurate.
>>>
>>> So my suggestion is to ignore the static method invocation for the
>>> class under initialization...
>>>
>>>
>>> public class Main {
>>>    public static void main(String[] args) {
>>>        Child c = Parent.createChild();
>>>        System.err.println(c);
>>>        System.err.println(Child.ROOT);
>>>    }
>>> }
>>>
>>> class Parent {
>>>    private static final Child[] childCache = new Child[5];
>>>
>>>    public static Child createChild(){
>>>        return childCache[0];
>>>    }
>>> }
>>>
>>> class Child {
>>>    public static final Child ROOT = Parent.createChild();
>>> }
>>>
>>> Thanks,
>>> xiaofeng
>>>
>>> Regards,
>>>> Ian Rogers
>>>>
>>>> [1]
>>>>
>>>> http://icooolps.loria.fr/icooolps2008/Papers/ICOOOLPS2008_paper08_Rogers_Zhao_Watson_final.pdf
>>>> [2] http://portal.acm.org/citation.cfm?id=1411746
>>>>
>>>>
>>>
>>>
>>>
>> --
>> Best Regards,
>> Regis.
>>
>



-- 
Managed Runtime Technology Center, Intel

Mime
View raw message