copyMethodAttributes(mInfo, nInfo);
// set the sync bit on the proxy if it was set on the method
nInfo.setAccessFlags(0 | AccessFlag.PUBLIC | AccessFlag.STATIC);
Bytecode proxyBytecode = new Bytecode(proxy.getConstPool());
int paramOffset = 0;
// if this is not a static method then we need to load the instance
// onto the stack
if (!staticMethod) {
proxyBytecode.addAload(0);
paramOffset = 1;
}
// stick the method number in the const pool then load it onto the
// stack
int scind = proxy.getConstPool().addIntegerInfo(methodNumber);
proxyBytecode.addLdc(scind);
String[] types = DescriptorUtils.descriptorStringToParameterArray(mInfo.getDescriptor());
// create a new array the same size as the parameter array
int index = proxyBytecode.getConstPool().addIntegerInfo(types.length);
proxyBytecode.addLdc(index);
// create new array to use to pass our parameters
proxyBytecode.addAnewarray("java.lang.Object");
int locals = types.length + paramOffset;
for (int i = 0; i < types.length; ++i) {
// duplicate the array reference on the stack
proxyBytecode.add(Opcode.DUP);
// load the array index into the stack
index = proxyBytecode.getConstPool().addIntegerInfo(i);
proxyBytecode.addLdc(index);
char tp = types[i].charAt(0);
if (tp != 'L' && tp != '[') {
// we have a primitive type
switch (tp) {
case 'J':
proxyBytecode.addLload(i + paramOffset);
locals++;
break;
case 'D':
proxyBytecode.addDload(i + paramOffset);
locals++;
break;
case 'F':
proxyBytecode.addFload(i + paramOffset);
break;
default:
proxyBytecode.addIload(i + paramOffset);
}
// lets box it
Boxing.box(proxyBytecode, tp);
} else {
proxyBytecode.addAload(i + paramOffset); // load parameter i onto
// the stack
}
proxyBytecode.add(Opcode.AASTORE);// store the value in the array
}
// invoke the added static method
if (staticMethod) {
proxyBytecode.addInvokestatic(className, Constants.ADDED_STATIC_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
} else if (isInterface) {
proxyBytecode.addInvokeinterface(className, Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;", 3);
} else {
proxyBytecode.addInvokevirtual(className, Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
}
// cast it to the appropriate type and return it
ManipulationUtils.MethodReturnRewriter.addReturnProxyMethod(mInfo.getDescriptor(), proxyBytecode);
CodeAttribute ca = proxyBytecode.toCodeAttribute();
ca.setMaxLocals(locals);
ca.computeMaxStack();
nInfo.setCodeAttribute(ca);
// now we have the static method that actually does the we-writes.
// if this is a virtual method then we need to add another virtual method
// with the exact signature of the existing
// method.
// this is so that we do not need to instrument the reflection API to much
if (!staticMethod) {
// as this method is never called the bytecode just returns
MethodInfo method = new MethodInfo(proxy.getConstPool(), mInfo.getName(), mInfo.getDescriptor());
method.setAccessFlags(mInfo.getAccessFlags());
if ((method.getAccessFlags() & AccessFlag.ABSTRACT) == 0) {
Bytecode b = new Bytecode(proxy.getConstPool());
String ret = DescriptorUtils.getReturnType(mInfo.getDescriptor());
if (ret.length() == 1) {
if (ret.equals("V")) {
b.add(Opcode.RETURN);
} else if (ret.equals("D")) {
b.add(Opcode.DCONST_0);
b.add(Opcode.DRETURN);
} else if (ret.equals("F")) {
b.add(Opcode.FCONST_0);
b.add(Opcode.FRETURN);
} else if (ret.equals("J")) {
b.add(Opcode.LCONST_0);
b.add(Opcode.LRETURN);
} else {
b.add(Opcode.ICONST_0);
b.add(Opcode.IRETURN);
}
} else {
b.add(Opcode.ACONST_NULL);
b.add(Opcode.ARETURN);
}
method.setCodeAttribute(b.toCodeAttribute());
method.getCodeAttribute().computeMaxStack();
method.getCodeAttribute().setMaxLocals(locals);
}
copyMethodAttributes(mInfo, method);