Я пытаюсь изучить java asm framework для инструментария байт-кода, но не могу найти по нему достаточную документацию или учебные пособия

Я пытаюсь изучить фреймворк java asm для инструментария байт-кода, но не могу найти по нему достаточную документацию или учебные пособия.

Я изучал ClassReader, ClassWriter и ClassVisitor и еще несколько похожих API, но не очень понимаю, как их реализовать и как написать соответствующие адаптеры.

Допустим, у меня есть Java-класс HelloWorld.

public class HelloWorld {

    public static void main(String[] args) {
//some code.....

    }

}

Теперь я хочу вставить переменную int i = 10; в байт-коде. Пожалуйста, дайте мне представление о том, какой адаптер / программу мне следует написать.

Заранее спасибо!


person Shubham Chaurasia    schedule 18.02.2015    source источник
comment
Вы читали: download.forge.objectweb.org/asm/asm4-guide. pdf? Там есть простые примеры, я считаю, что они объясняют, что вы хотите делать (я читал это некоторое время назад, поэтому я не уверен).   -  person Grzesuav    schedule 19.02.2015


Ответы (2)


Ниже приведен способ добавления дополнительных полей в класс, например «int i = 10;». Предполагая, что вы используете javaagent для выполнения инструментария: 1) Используйте следующий класс в качестве основного класса java-агента.

import java.lang.instrument.Instrumentation;

public class SimpleAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        ClassTransformer transformer = new ClassTransformer();
        inst.addTransformer(transformer);
    }
}   

2) addTransformer вызывает метод преобразования класса ClassTransformer, который определяется следующим образом

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

public class ClassTransformer implements ClassFileTransformer{
    public byte[] transform(ClassLoader    loader,
            String              className,
            Class            classBeingRedefined,
            ProtectionDomain    protectionDomain,
            byte[]              b)
                    throws IllegalClassFormatException {
        try
        {
                ClassReader cr=new ClassReader(b);
                ClassWriter cw = new ClassWriter(cr,ClassWriter.COMPUTE_MAXS);
                AddField cp = new AddField(cw);
                cr.accept(cp,0);
                return cw.toByteArray();
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
        return b;
    }
}

3) наконец, AddField, который выглядит следующим образом, является ClassVisitor, который отвечает за добавление нового поля в класс

import static org.objectweb.asm.Opcodes.ASM4;
import org.objectweb.asm.ClassVisitor;


class AddField extends ClassVisitor{

    static String className;
    static String methName, descrip;
    public AddField(ClassVisitor cv) {
        super(ASM4, cv);
    }

    @Override
    public void visit(int version, int access, String name,
            String signature, String superName, String[] interfaces) {
        className = name;
        cv.visit(version, access, name, signature, superName, interfaces);
    }
    public void visitEnd() {
        cv.visitField(0, "i", "I", null , new Integer(10));
        cv.visitEnd();
    }
}

4. ** NEW EDIT ** для добавления переменной в метод. Переменная должна быть сохранена во временной переменной, и ее можно будет использовать позже. Для этой цели можно использовать следующий адаптер (см. OnMethodEnter):

import static org.objectweb.asm.Opcodes.ASM4;
import static org.objectweb.asm.Opcodes.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.AdviceAdapter;

public class MethodAdapter extends ClassVisitor {


    public MethodAdapter(ClassVisitor cv) {
        super(ASM4, cv);
    }

    @Override
    public void visit(int version, int access, String name,
            String signature, String superName, String[] interfaces) {
        cv.visit(version, access, name, signature, superName, interfaces);
    }


    public MethodVisitor visitMethod(int access, String name,
            String desc, String signature, String[] exceptions) {
        MethodVisitor mv;
        mv = cv.visitMethod(access, name, desc, signature, exceptions);
        mv = new AddVariableAdapter(access, name, desc, mv);
        return mv;
    }
    public void visitEnd() {
        cv.visitEnd();
    }


    public class AddVariableAdapter extends AdviceAdapter{
        public AddCallAdapter(int access, String name, String desc,  
                MethodVisitor mv) {  
            super(ASM4, mv, access, name, desc);  
        }  

        protected void onMethodEnter()  {
            mv.visitIntInsn(BIPUSH, 10); // pushes the number 10 on to the stack
            mv.visitVarInsn(ISTORE, 1);  // pops the top of the stack into a local variable indexed by 1
        /*  code to print the local variable
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitVarInsn(ILOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");*/
        }
    }
}
person sri91    schedule 19.02.2015
comment
Извините, но я думаю, что это не ответ. Он хотел вставить переменную, а не поле. - person Clashsoft; 19.02.2015
comment
Спасибо за разъяснение. Я добавил адаптер для добавления переменной. - person sri91; 20.02.2015
comment
Как бы вы это запустили? - person KyelJmD; 07.03.2018

Хороший способ узнать, как использовать ASM, - запустить инструмент ASMifier. Если вы просто хотите знать, как определенные языковые конструкторы, такие как инициализаторы переменных, преобразуются в байт-код, может быть полезно создать простой класс Java, скомпилировать его, найти его .class файл и запустить на нем javap или открыть его с помощью IDE.

person Clashsoft    schedule 18.02.2015