Xiao-Feng Li wrote:
On Mon, Jan 5, 2009 at 5:12 AM, Ian Rogers <[email protected]> wrote:
2009/1/4 Nathan Beyer <[email protected]>

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
ch...@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.

Reply via email to