I use ASM 4 to generate some classes on the fly. Everything went well until I received the code for handling exceptions. The generated bytecode is at the bottom. Here is the error I get:
java.lang.VerifyError: Instruction type does not match stack map in method some.eval.ToEvaluate$0.apply()Ljava/lang/Object; at offset 44 at java.lang.Class.getDeclaredConstructors0(Native Method) at java.lang.Class.privateGetDeclaredConstructors(Class.java:2404) at java.lang.Class.getConstructor0(Class.java:2714) at java.lang.Class.newInstance0(Class.java:343) at java.lang.Class.newInstance(Class.java:325) ...
Here's the bytecode:
// Compiled from com/pkg/some/Source.java (version 1.7 : 51.0, super bit) public class some.eval.ToEvaluate$0 extends com.pkg.lang.Lambda0 { // Method descriptor
I used ASMifier to start with this:
public static Object trycatch(Object test, Lambda1 handler) { Object v; try { v = test; } catch (Throwable e) { v = handler.apply(e); } return v; }
but then I had to change it to make it general. Here is the code that the try / catch part generates:
int varOffset = context.getVarOffset(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); Label l3 = new Label(); Label l4 = new Label(); Label l5 = new Label(); // mv.visitLocalVariable("v", "Ljava/lang/Object;", null, l1, l2, 2); // 2 == varOffset + 0 context.push(1, new VarInfo(varOffset, "v1", l1, l2, false, "java/lang/Object")); // mv.visitLocalVariable("v", "Ljava/lang/Object;", null, l3, l5, 2); // 2 == varOffset + 0 context.push(1, new VarInfo(varOffset, "v2", l3, l5, false, "java/lang/Object")); // mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l4, l3, 3); // 3 == varOffset+1 context.push(1, new VarInfo(varOffset + 1, "e", l4, l3, false, "java/lang/Throwable")); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); mv.visitLabel(l0); mv.visitLineNumber(50, l0); args[0].visit(context, mv); // mv.visitVarInsn(ALOAD, 0); // execute block mv.visitVarInsn(ASTORE, varOffset); // store v, the result mv.visitLabel(l1); mv.visitJumpInsn(GOTO, l3); mv.visitLabel(l2); mv.visitLineNumber(51, l2); // mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); mv.visitVarInsn(ASTORE, varOffset + 1); // e mv.visitLabel(l4); mv.visitLineNumber(52, l4); args[1].visit(context, mv); // mv.visitVarInsn(ALOAD, 1); // catch block mv.visitVarInsn(ALOAD, varOffset + 1); // e mv.visitMethodInsn(INVOKEVIRTUAL, "com/pkg/lang/Lambda1", "apply", "(Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitVarInsn(ASTORE, varOffset); // store v, the result mv.visitLabel(l3); mv.visitLineNumber(54, l3); // mv.visitFrame(F_APPEND, 1, new Object[] { "java/lang/Object" }, 0, null); mv.visitVarInsn(ALOAD, varOffset); // load v, the result // mv.visitInsn(ARETURN); mv.visitLabel(l5); // mv.visitLocalVariable("test", "Ljava/lang/Object;", null, l0, l5, 0); // mv.visitLocalVariable("handler", "Lcom/pkg/lang/Lambda1;", null, l0, l5, 1);