Создание MethodNode завершается с ошибкой IllegalStateException

Я хочу получить MethodNode из main() функция

public class TestMethodNode {      
    public void main() {            
    }
}

так что я попробовал это

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.MethodNode;   
import static org.objectweb.asm.Opcodes.ASM7; 
import java.io.IOException;    

public class Instrumentation {
    public byte[] editFunction(String className) throws IOException {    
        byte[] modifiedClass = null;    
        try {    
            ClassReader classReader = new ClassReader(className);
            ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);
            ClassVisitor classAdapter = new ClassVisitor(ASM7, classWriter) {    
                public MethodVisitor visitMethod(
                        int access,
                        String name,
                        String desc,
                        String signature,
                        String[] exceptions) {    
                    if (name.equals("main")) {
                        final MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions);
                        MethodNode methodNode = new MethodNode(access, name, desc, signature, exceptions) {
                            public void visitEnd() {
                                // transform / analyze method here
                                accept(methodVisitor);
                            }
                        };    
                        return methodNode;
                    }  else {  
                        return super.visitMethod(access, name, desc, signature, exceptions);
                    }
                }
            };    
            classReader.accept(classAdapter, 0);
            modifiedClass = classWriter.toByteArray();  
        } catch (IOException ex) {    
            throw ex;
        }    
        return modifiedClass;
    }
}

и получил IllegalStateException из.../asm/tree/MethodNode.java при создании MethodNode

  public MethodNode(
      final int access,
      final String name,
      final String descriptor,
      final String signature,
      final String[] exceptions) {
    this(Opcodes.ASM7, access, name, descriptor, signature, exceptions);
    if (getClass() != MethodNode.class) {
      throw new IllegalStateException();
    }
  }

Что я делаю не так? (Я не хочу взламывать Minecraft, я исследую и пытаюсь манипулировать стеками вызовов, которые включают лямбда-выражения и вложенные / внутренние классы для механизма рабочего процесса, который использует манипулирование байт-кодом во время выполнения.)

2 ответа

Решение

Из документации конструктора MethodNode(int access, String name, String descriptor, String signature, String[] exceptions):

Подклассы не должны использовать этот конструктор. Вместо этого они должны использовать MethodNode(int, int, String, String, String, String[]) версия.

Так как вы создаете подкласс, вы должны изменить вызов

new MethodNode(access, name, desc, signature, exceptions) {
…
}

в

new MethodNode(ASM7, access, name, desc, signature, exceptions) {
…
}

Просто, чтобы предоставить полный рабочий образец для функции прибора main() данного класса

public class Instrumentation {
    public byte[] instrument(String className) {

        byte[] modifiedClass = null;

        try {

            ClassReader classReader = new ClassReader(className);
            ClassWriter classWriter = new ClassWriter(classReader, 4);
            ClassVisitor classVisitor = new ClassVisitor(ASM7) {
                public MethodVisitor visitMethod(
                        int access,
                        String name,
                        String desc,
                        String signature,
                        String[] exceptions) {
                    if (name.equals("main")) {
                        MethodNode methodNode = new MethodNode(ASM7,access, name, desc, signature, exceptions) {
                            public void visitEnd() {
                                // do some stuff here; remove exceptions, insnnode etc. -- smaple iterates through instructions
                                for (int i = 0; i < this.instructions.size();i++) {
                                    AbstractInsnNode node = this.instructions.get(i);
                                }
                            }
                        };
                        return methodNode;
                    } else {
                        return super.visitMethod(access, name, desc, signature, exceptions);
                    }
                }
            };

            classReader.accept(classVisitor,0);
            classReader.accept(classWriter, 0);
            modifiedClass = classWriter.toByteArray();

        } catch (IOException ex) {
           // handle IOException here
        }

        return modifiedClass;
    }
}
Другие вопросы по тегам