JvmInternal.java
class JvmInternal {
static int cv = 0;
final static int fcv = 100;
public static void main(String[] args){
int a, b, c;
a = Integer.parseInt(args[0]);
b = Integer.parseInt(args[1]);
c = addTwoArgs(a,b);
}
static int addTwoArgs(int x, int y){
cv = fcv;
return (x + y);
}
}
====================================================
javap -c JvmInternal.class
class JvmInternal {
static int cv;
static final int fcv;
JvmInternal();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: aload_0
1: iconst_0
2: aaload
3: invokestatic #2 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
6: istore_1
7: aload_0
8: iconst_1
9: aaload
10: invokestatic #2 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
13: istore_2
14: iload_1
15: iload_2
16: invokestatic #3 // Method addTwoArgs:(II)I
19: istore_3
20: return
static int addTwoArgs(int, int);
Code:
0: bipush 100
2: putstatic #5 // Field cv:I
5: iload_0
6: iload_1
7: iadd
8: ireturn
static {};
Code:
0: iconst_0
1: putstatic #5 // Field cv:I
4: return
}
JvmInternal 의 수행을 위해서 ClassLoader에 의해 JVM에 적재되는 과정을 거치고, Class가 Loading이 되면 우선 Method Area에 Class의 정보가 올라가게 되고, 이 작업이 완료되면 Heap에는 JvmInternal의 Instance가 하나 생성된다.
JvmInternal();
=> 생성자, Hidden this Method
Code:
0: aload_0
=> local variable영역의 0번 인덱스에서 args의 reference를 로딩
1: invokespecial #1 // Method java/lang/Object."<init>":()V
=> instance의 초기화 메소드를 호출
=> Heap에 JVMInternal 인스턴스를 생성
4: return
=> return ""
/.......
static {}; // static 초기화 블럭?
Code:
0: iconst_0
1: putstatic #5 // Field cv:I
4: return
}
iconst_0 와 putstaatic은 클래스변수인 cv에 값0을 집어 넣었음을 의미함.
fcv 값은 상수이기 때문에 Constant Pool에 들어가 있다.
main() 메소드를 수행하게되면, 이 메소드에 해당하는 Stack에 새로운 Stack Frame이 하나 생성되어 Push된다. 그리고 이 Method를 호출하면서 args[]의 Reference데이터를 그대로 넘겨 주었다.
stack Frame은 메소드의 정보를 바탕으로 알맞은 크기로 생성됨.
public static void main(java.lang.String[]);
Code:
0: aload_0
=> Local Variable 영역의 0번 인덱스를 load
0번 인덱스의 값은 args임
1: iconst_0
=> Reference를 통해 가져온 args의 인덱스 값으로 0이라는 상수를 취함
Array args에서 어떤 값을 가졍ㄹ지에 대해 array index를 지정
2: aaload
=> args[0]의 값을 heap에서 reference를 통해 가져옴
3: invokestatic #2 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
=> parseInt라는 Method를 호출하여 실행
6: istore_1
=> local variable의 1번 인덱스에 위의 결과를 저장
만약 static 메소드가 아닌 instance 메소드라면 local variable의 0번 인덱스에는 this에 해당하는 Reference가 들어가게 된다.
args[0]의 값을 알기위해 Local Variable에 저장된 args[]의 Reference를 Operand Stack에 Push한다.
그 후 값을 가져올 args[]의 인덱스를 지정한다. Heap에 저장된 args[]의 Array Data에서 0번지의 값을 Pop하여 그 Reference로 10을 찾아 Operend Stack으로 집어 넣는다.
7: aload_0
8: iconst_1
9: aaload
10: invokestatic #2 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
13: istore_2
14: iload_1
=> Local Varible 1 번 인덱스에서 값을 load함 a의 값을 load
15: iload_2
=> Local Varible 2 번 인덱스에서 값을 load함 b의 값을 load
16: invokestatic #3 // Method addTwoArgs:(II)I
=> Static Method addTwoArgs를 호출
19: istore_3
=> local variable의 3번 인덱스에 결과를 저장
20: return
=> void형 Method에서 return
차례로 Stack Frame을 삭제하고 프로그램을 종료...
//====================
static int addTwoArgs(int, int);
Code:
0: bipush 100
=> stack에 byte값 100을 집어넣음
값이 byte의 범위에 있으므로 bipush임
128이 넘으면 short으로 인식하여 sipush로 처리함
2: putstatic #5 // Field cv:I
=> static 변수 cv에 100을 집어넣음
5: iload_0
=> local varible 0번 인덱스에서 값을 load함
6: iload_1
=> local varible 1번 인덱스에서 값을 load함
7: iadd
=> 두 int를 더함
8: ireturn
Frame Data에 저장되는 Constant Pool Resolution에는 이 Method에서 사용되는 java.lang.Integer 객체나 java.lang.String객체의 심볼릭레퍼런스에 대한 실제 포인터가 저장되어있음
또한 main() 메소드를 호출한 Hidden this() 메소드의 주소값도 가지고 있다. 이는 main() Method가 정상 종료 후 복귀하기 위한 용도로 사용된다.
차례로 Stack Frame을 삭제하고 프로그램을 종료...
//====================
static int addTwoArgs(int, int);
Code:
0: bipush 100
=> stack에 byte값 100을 집어넣음
값이 byte의 범위에 있으므로 bipush임
128이 넘으면 short으로 인식하여 sipush로 처리함
2: putstatic #5 // Field cv:I
=> static 변수 cv에 100을 집어넣음
5: iload_0
=> local varible 0번 인덱스에서 값을 load함
6: iload_1
=> local varible 1번 인덱스에서 값을 load함
7: iadd
=> 두 int를 더함
8: ireturn
=> Method에서 int값을 반환
Frame Data에 저장되는 Constant Pool Resolution에는 이 Method에서 사용되는 java.lang.Integer 객체나 java.lang.String객체의 심볼릭레퍼런스에 대한 실제 포인터가 저장되어있음
또한 main() 메소드를 호출한 Hidden this() 메소드의 주소값도 가지고 있다. 이는 main() Method가 정상 종료 후 복귀하기 위한 용도로 사용된다.