1. 程式人生 > >ASM(位元組碼處理工具)

ASM(位元組碼處理工具)

import java.io.FileOutputStream;
import java.io.PrintStream;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

/**
 * @author Eric Bruneton
 */
public class Helloworld extends ClassLoader implements Opcodes {

    public static void main(String args[]) throws Exception {
        // 生成如下類檔案
        // public class Example {
        //     public static void main (String[] args) {
        //         System.out.println("Hello world!");
        //     }
        // }

        // 為Example提供ClassWriter,要求Example繼承自Object
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

        // 為隱含的預設構造器建立MethodWriter
        MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
                null);
        // 將this變數放入區域性變量表
        mw.visitVarInsn(ALOAD, 0);
        // 呼叫父類的預設建構函式
        mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",false);
        mw.visitInsn(RETURN);
        // 這段程式碼使用了最大為1的棧元素,且只有一個區域性變數
        mw.visitMaxs(1, 1);
        mw.visitEnd();

        // 為main方法建立MethodWriter 
        mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",
                "([Ljava/lang/String;)V", null, null);
        // 將System的out域入棧
        mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
                "Ljava/io/PrintStream;");
        // String型別的"Hello World!"常量入棧
        mw.visitLdcInsn("Hello world!");
        // 呼叫System.out的println方法
        mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
                "(Ljava/lang/String;)V", false);
        mw.visitInsn(RETURN);
        // 這段程式碼使用了最大為2的棧元素,包含兩個區域性變數
        mw.visitMaxs(2, 2);
        mw.visitEnd();

        // 獲得Example類的位元組碼,並且動態載入它
        byte[] code = cw.toByteArray();

        FileOutputStream fos = new FileOutputStream("Example.class");
        fos.write(code);
        fos.close();

        Helloworld loader = new Helloworld();
        Class<?> exampleClass = loader.defineClass("Example", code, 0,
                code.length);

        // 使用動態生成的類列印'Helloworld'
        exampleClass.getMethods()[0].invoke(null, new Object[] { null });

        // ------------------------------------------------------------------------
        // 使用GeneratorAdapter的示例(很方便但是更慢)
        // ------------------------------------------------------------------------

        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

        // 為隱含的預設構造器建立GeneratorAdapter 
        Method m = Method.getMethod("void <init> ()");
        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
        mg.loadThis();
        mg.invokeConstructor(Type.getType(Object.class), m);
        mg.returnValue();
        mg.endMethod();

        // 為main方法建立GeneratorAdapter
        m = Method.getMethod("void main (String[])");
        mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
        mg.getStatic(Type.getType(System.class), "out",
                Type.getType(PrintStream.class));
        mg.push("Hello world!");
        mg.invokeVirtual(Type.getType(PrintStream.class),
                Method.getMethod("void println (String)"));
        mg.returnValue();
        mg.endMethod();

        cw.visitEnd();

        code = cw.toByteArray();
        loader = new Helloworld();
        exampleClass = loader.defineClass("Example", code, 0, code.length);

        // 使用動態生成的類列印'Helloworld'
        exampleClass.getMethods()[0].invoke(null, new Object[] { null });
    }
}