Перезагрузка локальной переменной в ASM - PullRequest
1 голос
/ 06 октября 2011

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

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 06 октября 2011

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

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

0 голосов
/ 06 октября 2011

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

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

...