Am 05.03.2015 11:09, schrieb Peter Levart:
On 03/05/2015 04:09 AM, Jochen Theodorou wrote:
[...]
public class Foo {
  public Foo(String s, Integer i){}
  public Foo(Integer s, Object o){}
}

public class Bar extends Foo {
  public Bar(def a, def b) {
     super(a,b) // call with runtime types here
  }
}

I cannot express super(a,b) using method handles
[...]
Here's an idea. Let Groovy compile Foo to the following Java equivalent:

public class Foo {
     public Foo(Onject p1, Object p2) {
         super();
         invokedynamic _init(p1, p2);
     }

     private void _init(String s, Integer i) {
         // the body of constructor for (String, Integer)
     }

     private void _init(Integer s, Object o) {
         // the body of constructor for (Integer, Object)
     }
}

ok, sorry that I did not mention this contraint... Bar is in Groovy, Foo is written in Java. Meaning we have no control over Foo. Take for example BigDecimal instead of Foo.

[...]
So what we might need (also for other purposes like de-serialization) is
a special kind of private void instance initialization methods that are
treated specially by verifier and javac. The rules for such methods
could be as follows:

- they are treated like constructors regarding assignment to final
instance fields
- they can not be called from normal code except from constructors of
the same class that calls: super constructor followed by a call to one
of those special initialization methods. For example:

public class Bar extends Foo {

     private final int val;

     public Bar(String s, int val) {
         super(s);
         // call to special @init method can only appear immediately
after call to super constructor (verifier checked)
         initVal(val); // ...together they have the effect of calling
any this(...) constructor

         // ...so this is not allowed by javac
         this.val = 42;
     }

     @init private void initVal(int val) {
         this.val = val; // allowed and required (like in constructor)
     }

     public void normalMethod() {
         initVal(42); // not allowed by javac or verifier
     }
...

Those special @init methods could be invoked using reflection with
overridden access checks (setAccessible(true)) and looked up as method
handles using privileged Lookup only.

hmm... might be an idea worth of investigation. I don't know if it can be done, because of the verifier. The biggest problem in the current logic is that you basically do an invokespecial with a kind of class reference loaded by an aload 0. But this is not a normal "this", like you normally have. The sole purpose of it (afaik) is to call the super constructor. Any other call on this will cause problems. Your idea would, if we don't want to change the verifier, thus require an initialized class instance on the stack... which we won't get before calling super. But calling super is basically what we want to do.

Btw, besides the special logic for final assignment... not all versions enforce that in the JVM. Reflection and Unsafe are often ways around that. But there is also the special logic for final fields and concurrent publication in the current memory model to consider here. I would not want to loose that.

There is of course that internal deserialization logic Java has to create a "blank" instance. Maybe that could be used to have a kind of "valid" object to make calls on... But I am really not sure about the implications of that.

In the end I really wonder if it is possible to implement these kinds of things without a change to the Verifier. If the Verifier can be tweaked a bit, then there should be a solution

bye blackdrag


--
Jochen "blackdrag" Theodorou - Groovy Project Tech Lead
blog: http://blackdragsview.blogspot.com/
german groovy discussion newsgroup: de.comp.lang.misc
For Groovy programming sources visit http://groovy-lang.org

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to