开发者

Reloading a local variable in ASM

I am trying to retrieve the name of a class implementing a Java interface and then using this name as a key in a data structure to retrieve some code metrics about the class. Here is what I have done:

public void visitMethodInsn(int opcode, String owner, String name, String desc) {

   int methodOwner = _lvs.newLocal(Type.getType("Ljava/lang/String;"));

   if (opcode == Opcodes.INVOKEINTERFACE) {

        // some code to pop the operand stack and
        // get to the object whose method is being called

        // retrieving the name of the class
        int callingObj = _lvs.newLocal(Type.getType(Object.class));
        this.visitVarInsn(Opcodes.ASTORE, callingObj);
        this.visitVarInsn(Opcodes.ALOAD, callingObj);
        this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
        this.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
        this.visitVarInsn(Opcodes.ASTORE, methodOwner);           
        this.visitVarInsn(Opcodes.ALOAD, callingObj);

        /// (1)
        /// some code using the methodOwner ....
        /// something like the following
        /// this.visitVarInsn(Opcodes.ALOAD, methodOwner);

        /// code to reconstruct the operand stack 
        /// for the method to be invoked
   }

   super.visitMethodInsn(opcode, owner, name, desc);

   if (opcode == Opcodes.INVOKEINTERFACE) {
        /// (2)
        /// some more code using the methodOwner  .....
        ///
        /// this.visitVarInsn(Opcodes.ALOAD, methodOwner);
   }
}

If I comment out code snippets in block (2) from the code above, it works. However when I try to access "methodOwner" in block (2), I receive the following verification error indicating that the string object is gone missing. I can't understand why.

  org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 813: Expected an object reference, but found .

Since calling "super.visitMethodInsn(opcode, owner, name, desc);" pops the object whose interface method is called, I can't get a reference to it again. I tried keeping a second copy 开发者_JAVA技巧of the object in another variable but same problem occurs.

I wonder if you have any clue on what is wrong here and if you can give me some advice.

thanks very much for your help


One very, very simple piece of advise. What I usually do when instrument code is write the logic in plain java in a static method and call the method.

for instance

  class ZZZ{
    public static Object handleIntefaceCall(Object callee){
     //process
     return callee;
    }
  }

if the interface has no parameters all you need is call the static method and that is a single line of code

visitMethodInsn(INVOKESTATIC, "pack/ZZZ", "handleIntefaceCall", "(Ljava/lang/Object;)Ljava/lang/Object;");  
super.visitMethodInsn(opcode, owner, name, desc);

If there is a single parameter (but not long/double) you have to add a swap instruction before and after the call.


Your visitor implementation should extend the LocalVariableSorter class and you should call super.visitXXX on itself instead of mixing up visit calls between instance lvs and this.

The problem is that you are calling newLocalVar on one visitor and then using this variable slot in another visitor which doesn't knov about this variable. If this class already extends LocalVariableSorter then you should either replace lvs.xxx() cals with this.xxx() or other way around, but there should not be two visitors interleaved.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜