I am trying to do something relatively simple, I think. Take for example the following Java bytecode for a method doSomething(int):
public java.lang.String doSomething(int i);
0 iload_1 [i]
1 invokestatic MyHelper.doSomething(int) : Java.lang.String
4 areturn
This bytecode pretty much only forwards the call to a static helper.
What I want to do now is to replace the invokestatic with invokedynamic using Javassist. I know how to do this with ASM therefore just assume that I want to know how it works for reasons of pure curiosity. Here are some questions I have:
1) Is the following correct: I cannot ruse the javassist CtMethod.instrument() or CtMethod.insertAt() methods because those methods expect a string containing a valid Java expression and I cannot write an invokedynamic in Java syntax?
2) The parameters to an invokestatic are handled just like the parameters of an invokevirtual or invokestatic, right? What I mean is, you put the parameters onto the stack before the invokedynamic just like you would do it for a invokevirtual?
3) Is there example code (or could you come up with some) that uses Javassist to create an invokedynamic bytecode?
This is what I know so far: You can create a Bytecode object which has a method addInvokedynamic(). But this expects the index of a BootstrapMethod in a BootstrapMethodsAttribute. The BootstrapMethod in turn expects an index of a method handle info in the constant pool which wants a method reference and so on. So essentially you have to manage the whole constant pool entries yourself. Which is OK but I am concerned that I don't get it right and introduce weird issues later. Is there an easier way to do this (a helper method or so)? The code I have roughly looks something like this (I don't really "rewrite" the above invokestatic but :
void transform(CtMethod ctmethod, String originalCallDescriptor) {
MethodInfo mInfo = ctmethod.getMethodInfo();
ConstPool pool = ctmethod.getDeclaringClass().getClassFile().getConstPool();
/* add info about the static bootstrap method to the constant pool*/
int mRefIdx = /*somehow create a method reference entry*/
int mHandleIdx = constPool.addMethodHandleInfo(ConstPool.REF_invokeStatic, mRefIdx);
/* create bootstrap methods attribute; there can only be one per class file! */
BootstrapMethodsAttribute.BootstrapMethod[] bms = new BootstrapMethodsAttribute.BootstrapMethod[] {
new BootstrapMethodsAttribute.BootstrapMethod(mHandleIdx, new int[] {})
};
BootstrapMethodsAttribute bmsAttribute = new BootstrapMethodsAttribute(constPool, bms);
mInfo.addAttribute(bmsAttribute);
//... and then later, finally
Bytecode bc = new Bytecode(constPool);
... push parameters ...
bc.addInvokedynamic(0 /*index in bms array*/, mInfo.getName(), originalCallDescriptor);
//replace the original method body with the one containing invokedynamic
mInfo.removeCodeAttribute();
mInfo.setCodeAttribute(bc.toCodeAttribute());
}
Thanks a lot for your help and time!