Lambda and JSR 292 method handle
Rémi Forax
forax at univ-mlv.fr
Thu Dec 17 08:03:46 PST 2009
Le 17/12/2009 16:43, Peter Levart a écrit :
> I haven read the JSR 292 spec, so please bear with me if I talk rubbish...
>
> Ok, so in your example, the lambda was a function, so the MethodHandle is refering to a static method.
>
> In case the lambda was a closure that just referenced instance fields/methods, the MethodHandle I presume could be refering to an instance method of that instance.
>
yes, you have a ldc virtual lambda$1(int)int.
> But what about the case where lambda was a closure closing over some local variables. I expect you would have to create a special class and instance holding all this state and refer from MethodHandle to the instance method of that class.
You don't need a class. There is a special operation named insertArguments
that allow to specify the first arguments of a method handle in order to
create
another method handle. This operation is commonly called currying.
http://download.java.net/jdk7/docs/api/java/dyn/MethodHandles.html#insertArgument%28java.dyn.MethodHandle,%20int,%20java.lang.Object%29
Let's take an example:
class A {
public static void main(String[] args) {
#int(void) f = #() ( args.length );
f();
}
}
is translated to:
class A {
public static void main(String[] args) {
ldc static lambda$1(String)int
iconst_0
anewarray java/lang/Object
dup
iconst_0
aload 0 // load args
invokestatic MethodHandles.insertArguments(java/dyn/MethodHandle,Object[])java/dyn/MethodHandle
astore 1
aload 1
aconst_2
invokevirtual MethodHandle.invokeLambda()
pop
}
private static int lambda$1(String[] args) {
return args.length;
}
}
the method lambda$1 takes a String[] as parameter and in the main,
args is inserted as first argument.
Rémi
> Still this would eleminate megamorphic call sites because no interfaces would be involved and the generated class/method could be final to enable JIT inlining.
>
> Peter
>
> On Thursday 17 December 2009 15:23:55 Rémi Forax wrote:
>
>> The function model creates one function by lambda.
>>
>> class A {
>> public static void main(String[] args) {
>> #int(int) f = #(int x) (x+x);
>> f(2);
>> }
>> }
>>
>> is translated to:
>>
>> class A {
>> public static void main(String[] args) {
>> ldc static lambda$1(int)int // (1)
>> astore 1 // (2)
>> aload 1
>> aconst_2
>> invokevirtual A.invokeLambda(int)int // (3)
>> pop
>> }
>>
>> private static int lambda$1(int x) {
>> return x+x;
>> }
>> }
>>
>> I've written the body of the main in bytecode because there is non
>> equivalent in Java.
>> First, the JSR 292 define a new constant pool constant (see [2])
>> that allow to reference a function (here a static method) using opcode ldc.
>> So instantiating a lambda is just a ldc (1).
>> At runtime, this object is a java.dyn.MethodHandle, so it can be stored
>> as an object (2).
>> To call the lambda, the VM allows to call a magic method (3) named
>> invokeLambda (name may changed).
>> At runtime, the VM checks that the method handle type is compatible with
>> the type of invokeLambda
>> and call the function pointer stored in the method handle.
>>
>> Because a method handle knows its runtime type, it's possible to
>> implement instanceof and
>> cast on a function type.
>> Function type that are parametrized have the same constraint that
>> parameterized type, i.e
>> cast are unsafe.
>>
>> If function type are translated to method handle, megamorphic call site
>> problem can be solved because
>> JIT can recognize the pattern (a method that takes a method handle) and
>> do an aggressive inlining of
>> such method.
>>
>>
>> In summary, JSR 292 method handles was introduced by JSR 292 expert
>> group because it solves
>> common problems encounters when dealing with function pointer encoded
>> using interfaces.
>> It will be stupid to don't eating our own dog food.
>>
>> Rémi
>>
>>
More information about the lambda-dev
mailing list