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 13:04:17 GMT
On Mon, Jan 5, 2009 at 7:52 PM, Pavel Pervov <pmcfirst@gmail.com> wrote:
> Xiao-Feng,
>
> The spec does not prohibit (and thus just allows) methods (either
> class or object) to be invoked when circular class initializaiton
> occurs. The behaviour of such methods is as such that static and
> object fields are initially initialized to default (zero) values and
> then assigned other values during class initialization up to the point
> when circular initialization occurs, and then class or object methods
> execute without some fields be initialized to "correct" values. It is
> rather programmatic error or expected program behaviour than some spec
> inconsistency.


Thanks, Pavel.

I have some questions:

1. How do you explain this statement in VM spec?
" A class or interface type T will be initialized immediately before
one of the following occurs:
    * T is a class and a static method of T is invoked."

2. As to the semantics you described above, is that defined in any
spec or that's your understanding?

3. If to have a NULL value is expected for Child.ROOT in the test
case, can we simply leave it to be NULL without having: "ROOT =
Parent.createChild()"?

If the program can not get the expected result with
Parent.createChild(), I don't understand why we know a NULL is
expected. :)  I would say it is a program bug because it behaves not
as the program dictates.

In my understanding, class initialization process is virtually atomic
semantically. User should not see the intermediate values of a class
under initialization...

Thanks,
xiaofeng

> WBR,
>    Pavel.
>
> On Mon, Jan 5, 2009 at 12:06 PM, Xiao-Feng Li <xiaofeng.li@gmail.com> wrote:
>> Yes, we should commit if it passes the pre-commit tests and it makes
>> EUT3.5 proceed.
>>
>> Btw, we still don't know the expected behavior when a static method is
>> invoked before its class is initialized. It looks like all the JVMs
>> just invoke it as usual.
>>
>> Thanks,
>> xiaofeng
>>
>> On Mon, Jan 5, 2009 at 4:54 PM, chunrong lai <chunronglai@gmail.com> wrote:
>>> Thanks.
>>>
>>> We still can not make EUT3.5 work. But we have different log/stackTrace this
>>> time. I will post the new log to HARMONY-6062.
>>>
>>> I think the code needs to be committed, if it does not break the precommit
>>> tests, since it fixes the issue in HARMONY-6020. Opinions?
>>>
>>> chunrong
>>> Managed Runtime Technology Center, Intel
>>> On Mon, Jan 5, 2009 at 4:48 PM, Xiao-Feng Li <xiaofeng.li@gmail.com> wrote:
>>>
>>>> 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
>>>>
>>>
>>
>>
>>
>> --
>> Xiao-Feng Li
>> Managed Runtime Technology Center, Intel
>>
>



-- 
Managed Runtime Technology Center, Intel

Mime
View raw message