3

I would like to generate follwing method with bytebuddy stackmanipulation.

public void test() {
     this.process(() -> {
          System.out.println("Im lambda call");
     }
}

if such code would be compiled with javac it would produce:

  1. private method in the "this" type called lambda$test$0 without any arguments
  2. within the method test there would be invoke dynamic instruction
  3. invoke dynamic instruction in the test method to invoke the lambda

If i had just ASM i could do something like this

            methodVisitor.visitVarInsn(ALOAD, 0);
            methodVisitor.visitInvokeDynamicInsn("run", "(LmyTest/Test;)Ljava/lang/Runnable;", new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false), new Object[]{Type.getType("()V"), new Handle(Opcodes.H_INVOKESPECIAL, "myTest/Test", "lambda$test$0", "()V", false), Type.getType("()V")});
            methodVisitor.visitMethodInsn(INVOKEVIRTUAL, process ....)

 

How would i do this with just bytebuddy? Im using bytebuddy as its abstraction over opcodes is just much more pleasant to write than raw asm.

Let`s assume that the content of Runnable (method call of lambda$test$0) has already been generated

            MethodDescription.InDefinedShape targetCall = thisType.getDeclaredMethods().filter(named("lambda$test$0")).getOnly();
            InvokeDynamic methodRef = InvokeDynamic.lambda(targetCall, new TypeDescription.ForLoadedType(Runnable.class)).withoutArguments();


        StackManipulation.Size size = new StackManipulation.Compound(
            stackManipulations...
            methodRef... ??
        ).apply(mv, ctx);

This is where i dont know what to do. How can i get StackManipulation from InvokeDynamic?

user2749903
  • 1,275
  • 1
  • 10
  • 20
  • Any reason to use Byte Buddy? Just as an alternative to ASM? The Cojen/Maker framework is just as low-level, except without the mess. It should support your test, although no LambdaMetafactory examples are currently provided. – boneill Aug 13 '21 at 15:45

1 Answers1

3

To create a stack manipulation for a dynamic method invocation, instead of InvokeDynamic (a more high level Implementation), use

MethodInvocation.invoke(targetCall).dynamic("run",
  Collections.singletonList(thisType),
  TypeDescription.ForLoadedType.of(Runnable.class),
  Collections.emptyList());

You can chain this StackManipulation with the rest of your code.

In this case, ASM might however not be the worst option, it is a rather good byte code emitter and Byte Buddy does therefore not attempt to reimplement it. If it is the least amount of code, you can wrap it in a stack manipulation and implement the method using it, too, if this is an option you consider.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192