/*
* The local descriptor is the same as the descriptor from the abstract
* method in the interface.
*/
String localDescriptor = interfaceMethod.getDescriptor();
Method localMethod = new Method(mangledName, localDescriptor);
/*
* We also use the first argument to know which type to statically
* dispatch to.
*/
Type implementingType = Type.getType("L"
+ implementingMethod.getArgumentTypes()[0].getInternalName() + "$;");
// Maybe create the method. This is marked final as a sanity check
MethodVisitor mv = visitMethodNoRewrite(Opcodes.ACC_PUBLIC
| Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC, localMethod.getName(),
localMethod.getDescriptor(), null, null);
if (mv != null) {
mv.visitCode();
/*
* It just so happens that the stack and local variable sizes are the
* same, but they're kept distinct to aid in clarity should the dispatch
* logic change.
*/
int var = 0;
int size = 0;
for (Type t : implementingMethod.getArgumentTypes()) {
size += t.getSize();
mv.visitVarInsn(t.getOpcode(Opcodes.ILOAD), var);
var += t.getSize();
}
// Make sure there's enough room for the return value
size = Math.max(size, implementingMethod.getReturnType().getSize());
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
implementingType.getInternalName(), implementingMethod.getName(),
implementingMethod.getDescriptor());
mv.visitInsn(localMethod.getReturnType().getOpcode(Opcodes.IRETURN));
mv.visitMaxs(size, var);
mv.visitEnd();
}
}