2011-10-05 3 views
1

Я пытаюсь получить имя класса, реализующего интерфейс Java, а затем используя это имя в качестве ключа в структуре данных, чтобы получить некоторые метрики кода о классе. Вот что я сделал:Перезагрузка локальной переменной в ASM

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) из ​​приведенного выше кода, он работает. Однако, когда я пытаюсь получить доступ к «methodOwner» в блоке (2), я получаю следующую ошибку проверки, указывающую, что объект string отсутствует. Я не понимаю, почему.

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

С вызовом "super.visitMethodInsn (опкод, владелец, имя, убывание);" выдает объект, метод интерфейса которого вызван, я не могу получить ссылку на него снова. Я попытался сохранить вторую копию объекта в другой переменной, но возникает такая же проблема.

Интересно, есть ли у вас какие-либо подсказки о том, что здесь не так, и если вы можете дать мне совет.

Большое спасибо за вашу помощь

+0

Я должен добавить здесь, что добавление переменной в метод работает в первую очередь, так как код в блоке (1) выполняется без каких-либо проблем. Это сразу после вызова ** super.visitMethodInsn **, что доступ к новым добавленным переменным теряется. – nemo

ответ

0

Ваша реализация посетитель должен расширить класс LocalVariableSorter и вы должны вызвать super.visitXXX на себя вместо того, чтобы перепутать пребывания вызовов между экземпляра LVS и это.

Проблема в том, что вы вызываете newLocalVar на одного посетителя, а затем используете этот слот переменной у другого посетителя, который не знает о этой переменной. Если этот класс уже расширяет LocalVariableSorter, вы должны либо заменить lvs.xxx() cals на this.xxx(), либо наоборот, но не должно быть двух перемежаемых посетителей.

+0

Спасибо Евгению за ответ. Мой посетитель уже расширяет MethodAdapter, поэтому я использую LocalVariableSorter через делегирование, и я уже привязал LVS к адаптеру для класса, методы которого анализируются. Это больше похоже на то, как это объясняется на страницах 64 и 65 руководства ASM. Что ты предлагаешь? – nemo

+0

См. Мои разъяснения выше. –

2

Один очень, очень простой совет. То, что я обычно делаю, когда код прибора , напишите логику в простой 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); 

Если есть один параметр (но не длинный/двойной), вы должны добавить инструкцию свопа до и после вызова.

+0

Спасибо за совет @bestsss. Ты прав. Я должен сделать это для obj.getClass(). GetName() и сделать его более чистым. – nemo

Смежные вопросы