在ASM中重新加载局部变量

时间:2011-10-05 21:23:03

标签: java validation bytecode

我正在尝试检索实现Java接口的类的名称,然后使用此名称作为数据结构中的键来检索有关该类的一些代码度量标准。这就是我所做的:

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);
   }
}

如果我从上面的代码中注释掉块(2)中的代码片段,它就可以了。但是,当我尝试访问块(2)中的“methodOwner”时,我收到以下验证错误,指示字符串对象丢失了。我不明白为什么。

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

由于调用“super.visitMethodInsn(操作码,所有者,名称,desc);”弹出调用其接口方法的对象,我无法再次获得对它的引用。我尝试在另一个变量中保留对象的第二个副本,但是会出现同样的问题。

我想知道你是否对这里的错误有任何线索,如果你能给我一些建议。

非常感谢你的帮助

2 个答案:

答案 0 :(得分:3)

一个非常非常简单的建议。当仪器代码是我通常做的 在静态方法中用普通java编写逻辑并调用方法。

例如

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

如果接口没有参数,则只需调用静态方法,即单行代码

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

如果有一个参数(但不是长/双),则必须在通话前后添加交换指令。

答案 1 :(得分:0)

您的访问者实现应该扩展LocalVariableSorter类,您应该自己调用super.visitXXX,而不是混合实例lvs之间的访问调用。

问题是您在一个访问者上调用newLocalVar,然后在另一个访问者中使用此变量插槽,该访问者不知道该变量。如果这个类已经扩展了LocalVariableSorter,那么你应该用this.xxx()或其他方式替换lvs.xxx()cals,但不应该有两个访问者交错。