I am developing an instrumentation engine with ASM and I need to intercept the invocation of methods, which receive parameters of array type. For that purpose I implemented a MethodVisitor and in its visitMethodInsn I check if the desc parameter specifies any parameter of array type. If the target method has no parameters of array type, then I have nothing to do and I insert the original method invocation: super.visitMethodInsn(opcode, owner, name, desc);
On the other hand, if the target method has parameters of array type, then I must perform a specific action for its arguments. The easiest solution I got to access each argument was to invoke a mediator method, with the same descriptor of the target method, and in this mediator I can easily access its parameters (corresponding to the arguments passed to the target method).
Yet, a problem arises when the target method is an instance constructor (<init>). In Java the new XXX() is translated to bytecode as follows:
NEW XXX
DUP
INVOKESPECIAL XXXX.<init>()
According to the approach that I explained above, I am moving the INVOKESPECIAL call into a mediator method and the newly instantiated object is the first argument of this mediator. Yet, the verifier raises an error for this mediator, reporting that the first parameter of the mediator (which will be the first argument of the target method – <init>) is not an “unitialized object”. More precisely I got the error: Exception in thread "main" java.lang.VerifyError: Expecting to find unitialized object on stack”.
Once I split the bytecodes NEW and INVOKESPECIAL in two different methods, then the verifier claims that the argument passed to the INVOKESPECIAL has been already initialized.
Any suggestion to work around this problem? (please, do not answer me to avoid the mediator and access directly the arguments in the stack, because it is not simple to duplicate and replace arguments that occupy an arbitrary position in the stack.)
The verifier is correct to reject your code (see JVM specification). There is no way to bypass bytecode verifier.
One way around is to inline the mediator code at the point of constructor invocation. You still can invoke parts of mediator as method calls before or after the invocation of the constructor, but the very constructor invocation has to be in the same method as the new instruction.
Another way is to make special mediators for every class being instantiation, so the mediators invoke the
newinstruction themselves, along with the constructor call.You can also look at existing AOP libraries if they can do the required job correctly.