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});
}
}
댓글 없음:
댓글 쓰기