首先簡要介紹一下class文件的結構(詳細內容請參考Java虛擬機規范,在《深入Java虛擬機》一書中也有詳細描述):
長度(字節)
名稱
解釋
4
magic
0xCAFEBABE,Java文件的標識,常稱為“魔數”
2
minor_version
次版本號
2
major_version
主版本號
2
constant_pool_count
常量池中項目個數
(constant_pool_count-1)*cp_item
constant_pool
常量池,其中存放了(constant_pool_count-1)個常量池項
2
Access_flags
本class的類型信息
2
this_class
本class的全限定名的常量池項索引
2
super_class
超類的全限定名的常量池項索引
2
interfaces_count
實現/擴展的接口數
2*interfaces_count
interfaces
實現/擴展的接口名的常量池項索引
2
fIElds_count
字段數
fIElds_count* cp_item
fIElds
字段信息表
2
methods_count
方法數
methods_count* cp_item
methods
方法信息表
2
attributes_count
屬性數
attributes_count* cp_item
attributes
屬性信息表
文件系統中的一個class文件,要想成為能在虛擬上運行的Java程序的一部分,必須經過“裝載->連接->初始化”三個步驟。其中裝載是最基礎的一步,它的作用是讀取class文件的信息,並生成對象。下面介紹一下KVM中與類加載相關的內容是如何實現的。
數據結構:
在頭文件kvm/vmcommon/h/class.h中定義有兩個非常重要的結構體:
classStruct與instanceClassStruct這兩個結構體都是與class(可能包括類和接口)有關的,但不所不同。classStruct所提供是一些“外圍信息”,包括全限定名和可見性等,是一個class區分其它class的基本信息;instanceClassStruct所提供的是一些“內容信息”,是一個類本身所定義的內容,比如方法表、字段表等等。
程序實現:
下面來看一看在KVM中instanceClassStruct的信息是如何讀取的。
一個kvm虛擬機在運行時,class來自於兩種來源:一是系統類庫,這些類來自KVM本身;二是用戶程序,來自文件系統。下面分別介紹:
1、前文提到過,對於系統類庫,KVM會先把class文件轉化為C語言源代碼,然後編入kvm可執行程序中,這樣當使用系統類庫時,kvm就不再訪問外部,這一步驟叫可暫稱為ROM,ROM過程中所做的事情之一就是生成所有系統類庫中class的INSTANCE_CLASS,也就是說,這些類的信息早在ROM的過程中就已准備好,使用時只要讀入即可。
ROM生成的INSTANCE_CLASS信息存放在源文件tools/jcc/ROMJavaUnix.c的static struct AllClassblocks_Struct AllClassblocks結構中,使用這一結構的代碼也在同一文件中,比如:
INSTANCE_CLASS JavaLangString =
這裡就生成了String類對應的INSTANCE_CLASS結構。
2、對於用戶定義的類,INSTANCE_CLASS信息就要從文件系統中獲得。
獲得類信息的主要入口函數是
void loadClassfile(INSTANCE_CLASS InitiatingClass, bool_t fatalErrorIfFail);
在文件kvm/vmcommon/src/loader.c中。其中參數InitiatingClass就是一個空的INSTANCE_CLASS結構體,在loadClassfile函數中,InitiatingClass的內容將被逐步填充。
在loadClassfile中,將調用另一個重要的函數:
static void loadRawClass(INSTANCE_CLASS CurrentClass, bool_t fatalErrorIfFail);
在這個函數中,將調用下列各方法分別載入class文件中的各種信息:
函數名(參數及返回值省略)
功能
loadVersionInfo()
載入版本號
loadConstantPool()
載入常量池
loadClassInfo()
載入類型信息
loadInterfaces()
載入所實現的接口
loadFIElds()
載入字段表
loadMethods()
載入方法表
ignoreAttributes()
載入擴展的屬性表
上表中的每一個函數都會帶有一個FILEPOINTER_HANDLE型的參數,它是一個文件的句柄,這些函數就是從這個文件中順序讀取各種信息並存入INSTANCE_CLASS結構中的。
首先簡要介紹一下class文件的結構(詳細內容請參考Java虛擬機規范,在《深入Java虛擬機》一書中也有詳細描述):
長度(字節)
名稱
解釋
4
magic
0xCAFEBABE,Java文件的標識,常稱為“魔數”
2
minor_version
次版本號
2
major_version
主版本號
2
constant_pool_count
常量池中項目個數
(constant_pool_count-1)*cp_item
constant_pool
常量池,其中存放了(constant_pool_count-1)個常量池項
2
Access_flags
本class的類型信息
2
this_class
本class的全限定名的常量池項索引
2
super_class
超類的全限定名的常量池項索引
2
interfaces_count
實現/擴展的接口數
2*interfaces_count
interfaces
實現/擴展的接口名的常量池項索引
2
fIElds_count
字段數
fIElds_count* cp_item
fIElds
字段信息表
2
methods_count
方法數
methods_count* cp_item
methods
方法信息表
2
attributes_count
屬性數
attributes_count* cp_item
attributes
屬性信息表
文件系統中的一個class文件,要想成為能在虛擬上運行的Java程序的一部分,必須經過“裝載->連接->初始化”三個步驟。其中裝載是最基礎的一步,它的作用是讀取class文件的信息,並生成對象。下面介紹一下KVM中與類加載相關的內容是如何實現的。
數據結構:
在頭文件kvm/vmcommon/h/class.h中定義有兩個非常重要的結構體:
classStruct與instanceClassStruct這兩個結構體都是與class(可能包括類和接口)有關的,但不所不同。classStruct所提供是一些“外圍信息”,包括全限定名和可見性等,是一個class區分其它class的基本信息;instanceClassStruct所提供的是一些“內容信息”,是一個類本身所定義的內容,比如方法表、字段表等等。
程序實現:
下面來看一看在KVM中instanceClassStruct的信息是如何讀取的。
一個kvm虛擬機在運行時,class來自於兩種來源:一是系統類庫,這些類來自KVM本身;二是用戶程序,來自文件系統。下面分別介紹:
1、前文提到過,對於系統類庫,KVM會先把class文件轉化為C語言源代碼,然後編入kvm可執行程序中,這樣當使用系統類庫時,kvm就不再訪問外部,這一步驟叫可暫稱為ROM,ROM過程中所做的事情之一就是生成所有系統類庫中class的INSTANCE_CLASS,也就是說,這些類的信息早在ROM的過程中就已准備好,使用時只要讀入即可。
ROM生成的INSTANCE_CLASS信息存放在源文件tools/jcc/ROMJavaUnix.c的static struct AllClassblocks_Struct AllClassblocks結構中,使用這一結構的代碼也在同一文件中,比如:
INSTANCE_CLASS JavaLangString =
這裡就生成了String類對應的INSTANCE_CLASS結構。
2、對於用戶定義的類,INSTANCE_CLASS信息就要從文件系統中獲得。
獲得類信息的主要入口函數是
void loadClassfile(INSTANCE_CLASS InitiatingClass, bool_t fatalErrorIfFail);
在文件kvm/vmcommon/src/loader.c中。其中參數InitiatingClass就是一個空的INSTANCE_CLASS結構體,在loadClassfile函數中,InitiatingClass的內容將被逐步填充。
在loadClassfile中,將調用另一個重要的函數:
static void loadRawClass(INSTANCE_CLASS CurrentClass, bool_t fatalErrorIfFail);
在這個函數中,將調用下列各方法分別載入class文件中的各種信息:
函數名(參數及返回值省略)
功能
loadVersionInfo()
載入版本號
loadConstantPool()
載入常量池
loadClassInfo()
載入類型信息
loadInterfaces()
載入所實現的接口
loadFIElds()
載入字段表
loadMethods()
載入方法表
ignoreAttributes()
載入擴展的屬性表
上表中的每一個函數都會帶有一個FILEPOINTER_HANDLE型的參數,它是一個文件的句柄,這些函數就是從這個文件中順序讀取各種信息並存入INSTANCE_CLASS結構中的。