*/
// we simply want to load the corresponding identifier
// and then forward it to the dispatcher
@Override
public void overrideMethod(ClassMethod method, Method superclassMethod) {
CodeAttribute ca = method.getCodeAttribute();
// first we need to check the constructed field
ca.aload(0);
ca.getfield(getClassName(), CONSTRUCTED_GUARD, "Z");
// if the object has not been constructed yet invoke the superclass version of the method
BranchEnd end = ca.ifne();
ca.aload(0);
ca.loadMethodParameters();
ca.invokespecial(getSuperClassName(), method.getName(), method.getDescriptor());
ca.returnInstruction();
// normal invocation path begins here
ca.branchEnd(end);
ca.aload(0);
ca.getfield(getClassName(), INVOCATION_HANDLER_FIELD, InvocationHandler.class);
ca.aload(0);
loadMethodIdentifier(superclassMethod, method);
// now we need to stick the parameters into an array, boxing if nessesary
String[] params = method.getParameters();
ca.iconst(params.length);
ca.anewarray("java/lang/Object");
int loadPosition = 1;
for (int i = 0; i < params.length; ++i) {
ca.dup();
ca.iconst(i);
String type = params[i];
if (type.length() == 1) { // primitive
char typeChar = type.charAt(0);
switch (typeChar) {
case 'I':
ca.iload(loadPosition);
Boxing.boxInt(ca);
break;
case 'S':
ca.iload(loadPosition);
Boxing.boxShort(ca);
break;
case 'B':
ca.iload(loadPosition);
Boxing.boxByte(ca);
break;
case 'Z':
ca.iload(loadPosition);
Boxing.boxBoolean(ca);
break;
case 'C':
ca.iload(loadPosition);
Boxing.boxChar(ca);
break;
case 'D':
ca.dload(loadPosition);
Boxing.boxDouble(ca);
loadPosition++;
break;
case 'J':
ca.lload(loadPosition);
Boxing.boxLong(ca);
loadPosition++;
break;
case 'F':
ca.fload(loadPosition);
Boxing.boxFloat(ca);
break;
default:
throw new RuntimeException("Unknown primitive type descriptor: " + typeChar);
}
} else {
ca.aload(loadPosition);
}
ca.aastore();
loadPosition++;
}
ca.invokeinterface(InvocationHandler.class.getName(), "invoke",
"(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
if (superclassMethod.getReturnType() != void.class) {
if (superclassMethod.getReturnType().isPrimitive()) {
Boxing.unbox(ca, method.getReturnType());
} else {
ca.checkcast(superclassMethod.getReturnType().getName());
}
}
ca.returnInstruction();
}