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