Java Compiler 들여다 보기

이번엔 2006년 7월호의 서광열님이 쓴 마소 기사를 간략히 정리해본다.

자바 디컴파일러! (javap)
자바 디컴파일러는 여태까지 C++로 만들어진 jad만 사용했었는데 이 기사에서 javap를 소개하였다. JavaSE 5에 새로 추가된 것인지 알았더니 1.4.2에도 있네..
그런데 javap를 해보니 jad처럼 (jad -s java *.class) 깔끔하게 소스코드가 나오는게 아니라. 내부에서 수행되는 바이트 코드가 나온다. 예를 들면 내가 다음과 같이 javap package에 Foo라는 클래스를 만들었다.
------------------------------------
package javap;
public class Foo
{
 public static void main(String[] args)
 {
  if( false)
  {
   System.out.println("Never");
  }
 }
}
------------------------------------------------------------------------
그리고 나서  아래와 같이 명령어를 입력하였더니 또 아래와 같이 결과가 나왔다.
------------------------------------------------------------------------
E:\javaSE\00_Essential>javap -classpath . -c javap.Foo
Compiled from "Foo.java"
public class javap.Foo extends java.lang.Object{
public javap.Foo();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
public static void main(java.lang.String[]);
  Code:
   0:   return
}
------------------------------------------------------------------------
즉 JVM에서 처리하는 byte code를 볼 수 있다.

이 아티클에서는 C++의 #ifdef - #endif와 같은 조건부 컴파일 기술에 대해서 이야기 한다. 즉 컴파일 자체도 원하는 부분만 할 수 있도록 하는 기술을 의미한다. 그런데 위의 코드에서 보듯이 'if( false )'라고 적어주면 java 컴파일러가 dead code로 인식하여 그 내용 자체를 컴파일 하지 않는 사실을 사용하면 C++의 #ifdef - #endif를 흉내 낼 수 있다.!

그래서 예전 Interface의 DEBUG를 static final로 선언해서 썼듯이 이기능을 Java SE 5의 static import기능을 활용하여 interface에 정의해 놓고 쓰면 아주 유용할 듯 하다.  ( 오~^^ 좋은걸)

문자열 처리
자바에서 String은 Immutable Pattern의 클래스이다. 즉 String객체는 절대 변화하지 않으며, 만약에 변화를 주면 기존의 객체는 그대로 두고, 새로운 객체가 생성되서 나오게 된다.  이 내용을 어떻게 JVM내부에서 구동되는지 javap를 활용해서 알아 볼 수 있다. 다음과 같이 코드를 적어주면
------------------------------------------------------------------------

package javap;
public class StringTest
{
 public static void main(String[] args)
 {
  String h = "hello";
  h += " world";

 }
}
------------------------------------------------------------------------
그리고 javap를 통해서 확인해 보면
------------------------------------------------------------------------

E:\javaSE\00_Essential>javap -classpath . -c javap.StringTest
Compiled from "StringTest.java"
public class javap.StringTest extends java.lang.Object{
public javap.StringTest();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
public static void main(java.lang.String[]);
  Code:
   0:   ldc     #16; //String hello
   2:   astore_1
   3:   new     #18; //class java/lang/StringBuilder
   6:   dup
   7:   aload_1
   8:   invokestatic    #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   11:  invokespecial   #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   14:  ldc     #29; //String  world
   16:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  astore_1
   23:  return
}
------------------------------------------------------------------------
이처럼 내부에서 StringBuilder를 통해서 한줄의 명령어 "String h = "hello";"가 StringBuilder혹은 StringBuffer를 New하고 append하는 것을 알 수 있다. 이처럼 직접 확인해 볼 수 있어서 아주 좋다! ^^

음~ 결과적으로 jad는 그대로 java source decompiler로 그냥 사용하고 javap라는 java byte code를 볼 수 있는 좋은 툴로 JVM내부에서 어떻게 동작하는지 확인해 볼 수도 있다.
실제도 Java SE 5에서 강화된 언어의 지원(enhanced For loop, type safe enum, autoboxing, unboxing, variable arguments, static import)기능이 javac에 의해서 수행되고 byte코드는 예전과 동일하다고 한다. ~ 좋구나! ^^

by Jipsin | 2006/12/24 16:15 | Java/Essential | 트랙백 | 덧글(2)

트랙백 주소 : http://jipsin08.egloos.com/tb/720905
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by Nietzs at 2009/02/12 17:40
javap는 disassemble(역어셈블)이 아닙니까? "음~ 결과적으로 jad는 그대로 java source decompiler로 그냥 사용하고 javap라는 java byte code를 볼 수 있는(마치 assembler를 보는 듯한 기분이 들지만) 좋은 툴로 JVM내부에서 어떻게 동작하는지 확인해 볼 수도 있다."라고 하신 부분은 틀린 듯 합니다. 마치가 아니라 정말로 disassemble을 하는 명령어입니다.
Commented by Jipsin at 2009/03/20 08:26
하하.. assembler에 대해서 좀더 자세히 적을걸 그랬네요, 저 문맥에서는 학부시절에 봤던 assembler를 생각하고 적은것인데.. '마치'라는 단어를 빼는게 좋겠습니다. ^^

:         :

:

비공개 덧글

<< 이전 페이지다음 페이지 >>