benf.org :  other :  cfr :  Java 8 Lambdas

Separate article on lambda serialisation is here

The lambda functionality in java 8 is very well documented - I found the following to be more than enough!

Brian Goetz's excellent article on lambda translation design for java 8.
Invokedynamic instruction
Bootstrap Methods attribute.
LambdaMetaFactory documentation.
Lambda implementation changed in an incompatible way after beta 103!

As of 0_11 CFR is able to decompile lambda expressions... as of 0_27, post beta103 lambdas.

please note - when desugaring lambdas, CFR relies on your JRE, i.e. if you're trying to desugar a call to Consumer::andThen, and you've got Java 7 - CFR will not be able to desugar it!

What's particularly interesting (to me!) is that before I dug into this, I was expecting lambdas to simply be yet more syntactic sugar around anonymous inner classes - indeed Idea 12 'hides' anonymous inners behind lambda syntax, which is quite funny...

CFR treatment

Original code

public class LambdaTest2 {

    Integer invoker(int arg, UnaryFunction<Integer, Integer> fn) {
        return fn.invoke(arg);
    }

    public int test(int y) {
        return invoker(3, x -> x + y + 1);
    }

}

CFR 0_11 decompilation, with --decodelambdas false

There are a couple of things of interest here, which mean that un-desugared, we can't treat this as real java:

public class LambdaTest2
{

    public LambdaTest2(){
    }

    Integer invoker(int arg, UnaryFunction<Integer, Integer> fn){
        return fn.invoke(Integer.valueOf(arg));
    }

    public int test(int y){
        return this.invoker(3, (UnaryFunction)LambdaMetafactory.metaFactory(null, null, null, 
            invoke(X ), lambda$2(int Integer ), ConstantUTF8[(Ljava/lang/Integer;)Ljava/lang/Integer;])(y)).intValue();
    }

    private static /* synthetic */ Integer lambda$2(int v0, Integer v1){
        return Integer.valueOf((v1.intValue() + v0 + 1));
    }

}

CFR 0_11 decompilation with lambda desugaring

As of 0_11, I haven't figured out if it's possible to determine the names which were given to the lambda arguments, so I'm making up names for them...

public class LambdaTest2
{

    public LambdaTest2(){
    }

    Integer invoker(int arg, UnaryFunction<Integer, Integer> fn){
        return fn.invoke(Integer.valueOf(arg));
    }

    public int test(int y){
        return this.invoker(3, arg_0 -> Integer.valueOf((arg_0.intValue() + y + 1))).intValue();
    }

}

Appendix - Bytecode

public class org.benf.cfr.tests.LambdaTest2 {
  public org.benf.cfr.tests.LambdaTest2();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  java.lang.Integer invoker(int, org.benf.cfr.reader.util.functors.UnaryFunction);
    Code:
       0: aload_2       
       1: iload_1       
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: invokeinterface #3,  2            // InterfaceMethod org/benf/cfr/reader/util/functors/UnaryFunction.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
      10: checkcast     #4                  // class java/lang/Integer
      13: areturn       

  public int test(int);
    Code:
       0: aload_0       
       1: iconst_3      
       2: iload_1       
       3: invokedynamic #5,  0              // InvokeDynamic #0:lambda$:(I)Lorg/benf/cfr/reader/util/functors/UnaryFunction;
       8: invokevirtual #6                  // Method invoker:(ILorg/benf/cfr/reader/util/functors/UnaryFunction;)Ljava/lang/Integer;
      11: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
      14: ireturn       

  private static java.lang.Integer lambda$2(int, java.lang.Integer);
    Code:
       0: aload_1       
       1: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
       4: iload_0       
       5: iadd          
       6: iconst_1      
       7: iadd          
       8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: areturn       
}


Last updated 08/2013