What can we improve in JSR292 for Java 9?

Peter Levart peter.levart at gmail.com
Thu Mar 5 10:09:55 UTC 2015


On 03/05/2015 04:09 AM, Jochen Theodorou wrote:
> Am 04.03.2015 23:50, schrieb Charles Oliver Nutter:
>> On Thu, Feb 26, 2015 at 4:27 AM, Jochen Theodorou <blackdrag at gmx.org> 
>> wrote:
>>> my biggest request: allow the call of a super constructor (like
>>> super(foo,bar)) using MethodHandles an have it understood by the JVM 
>>> like a
>>> normal super constructor call... same for this(...)
>>
>> Just so I understand...the problem is that unless you can get a Lookup
>> that can do the super call from Java (i.e. from within a subclass),
>> you can't get a handle that can do the super call, right? And you
>> can't do that because the method bodies might not be emitted into a
>> natural subclass of the super class?
>
> Not fully right. Sorry for the possibly false flag with the 
> permissions from the runtime. I am in a natural subclass. Take this 
> pseudoexample:
>
> 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, even if I did know 
> the types at compiletime (in which case I would not need invokedynamic 
> anyway). Sure, there is 
> http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html#findSpecial%28java.lang.Class,%20java.lang.String,%20java.lang.invoke.MethodType,%20java.lang.Class%29 
> but this is for calling methods in a invokespecial like manner, <init> 
> is excluded here as stated in the comment. The comment refers to 
> findConsructor for calls to constructors, and indeed we have 
> invokeSpecial calls there as well, but those are for what in Java is 
> "new", and are different from calls to a super constructor. See also 
> http://mail.openjdk.java.net/pipermail/mlvm-dev/2012-June/004650.html 
> from almost 3 years ago here on the list. Remi gives here a good 
> reason why it probably cannot be done easily... in that or an even 
> older thread someone (I think John) was talking about security.
>
> bye Jochen
>

Hi Jochen,

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)
     }
}


... a set of overloaded Groovy constructors with same arity could be 
emmited as:

- a single constructor with Object typed arguments chaining to a super 
constructor with Object typed arguments using plain invokespecial
- one private void _init method with declared types of arguments per 
Groovy constructor containing code of related Groovy constructor
- an invokedynamic call in the single emitted constructor used for 
dispatching to appropriate _init method based on runtime types of arguments

Only one thing would not work as expected in this setting: final fields 
could not be set in _init methods as verifier doesn't allow that.

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.


Regards, Peter



More information about the mlvm-dev mailing list