* semantics of the dispatches that would make a common implementation far
* more awkward than the duplication of code.
*/
for (Map.Entry<String, Method> entry : toImplement(stubIntr).entrySet()) {
String mangledName = entry.getKey();
Method method = entry.getValue();
String descriptor = "("
+ method.getDescriptor().substring(
1 + method.getArgumentTypes()[0].getDescriptor().length());
String localName = method.getName().substring(0,
method.getName().length() - 1);
Method toCall = new Method(localName, descriptor);
// Must not be final
MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC
| Opcodes.ACC_SYNTHETIC, mangledName, descriptor, 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.
*
* These start at 1 because we need to load "this" onto the stack
*/
int var = 1;
int size = 1;
// load this
mv.visitVarInsn(Opcodes.ALOAD, 0);
// then the rest of the arguments
for (Type t : toCall.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, toCall.getReturnType().getSize());
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, currentTypeName,
toCall.getName(), toCall.getDescriptor());
mv.visitInsn(toCall.getReturnType().getOpcode(Opcodes.IRETURN));
mv.visitMaxs(size, var);
mv.visitEnd();
}
}
}