2014년 2월 13일 목요일

ASM 4.0 Example - Hello World 주석 달기

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(final String args[]) throws Exception {

        // 아래의 소스에 대하여 자바 클래스 파일에 해당하는 바이트 코드를 만들기
        /**********************************************************************
        public class Example {
            public static void main (String[] args) {
                System.out.println("Hello world!");
            }
        }
        **********************************************************************/

// ClassWriter 만들기 - Object 를 상속 받아서
ClassWriter cw = new ClassWriter(0);
        // visit(int version, int access, String name, String signature, String superName, String[] interfaces)
cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

// 생성자 MethodWriter 만들기
        // visitMethod(int access, String name, String desc, String signature, String[] exceptions)
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);

        // visitVarInsn(int opcode, int var)
        // opcode 는 ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, RET 중 선택사용
        // opcode 참조 : http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html
        // 'this' 변수 지정
mw.visitVarInsn(ALOAD, 0);

// super class constructor
        // visitMethodInsn(int opcode, String owner, String name, String desc)
        // opcode 는 INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE 중 선택사용
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");

        // visitInsn(int opcode)
mw.visitInsn(RETURN);

        // visitMaxs(int maxStack, int maxLocals)
        // 메소드의 최대 스택 사이즈
        // 메소드를 위한 로컬 변수의 최대 사이즈
mw.visitMaxs(1, 1);

mw.visitEnd();

// main 함수 만들기
        // visitMethod(int access, String name, String desc, String signature, String[] exceptions)
mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);

// System 클래스의 'out' field 사용
        // visitFieldInsn(int opcode, String owner, String name, String desc)
        // opcode 는 GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD 중 선택사용
mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

// "Hello World!" String 상수 사용 (ldc instruction)
        // ldc pushes a one-word constant onto the operand stack. int, float, String 등
  mw.visitLdcInsn("Hello world!");
        
// 'prinln' 수행
mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");

        mw.visitInsn(RETURN);

        // visitMaxs(int maxStack, int maxLocals)
        // 메소드의 최대 스택 사이즈
        // 메소드를 위한 로컬 변수의 최대 사이즈
mw.visitMaxs(2, 2);

mw.visitEnd();

// 바이트코드 값 얻기
byte[] code = cw.toByteArray();

// class 파일 만들기
        FileOutputStream fos = new FileOutputStream("Example.class");
fos.write(code);
fos.close();

// 클래스로더로 읽어 들이기
        Helloworld loader = new Helloworld();
Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length);

// 로딩된 클래스의 main 메소드 수행하기
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);

        // 생성자 만들기
Method m = Method.getMethod("void <init> ()");
        // GeneratorAdapter(int access, Method method, String signature, Type[] exceptions, ClassVisitor cv)
GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
mg.loadThis();
mg.invokeConstructor(Type.getType(Object.class), m);
mg.returnValue();
mg.endMethod();

// main 함수 만들기
m = Method.getMethod("void main (String[])");
        // GeneratorAdapter(int access, Method method, String signature, Type[] exceptions, ClassVisitor cv)
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);

        // 로딩된 클래스의 main 메소드 수행하기
exampleClass.getMethods()[0].invoke(null, new Object[]{null});
}
}


댓글 없음:

댓글 쓰기