KVM的类加载
首先简要介绍一下class文件的结构(详细内容请参考Java虚拟机规范,在《深入Java虚拟机》一书中也有详细描述):长度(字节)名称解释
首先简要介绍一下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中定义有两个非常重要的结构体:
struct classStruct {
COMMON_OBJECT_INFO(INSTANCE_CLASS)
UString packageName; /* Everything before the final '/' */
UString baseName; /* Everything after the final '/' */
CLASS next; /* Next item in this hash table bucket */
unsigned short accessFlags; /* Access information */
unsigned short key; /* Class key */
};
typedef struct classStruct * CLASS;
/* INSTANCE_CLASS */
struct instanceClassStruct {
struct classStruct clazz; /* common info */
/* And specific to instance classes */
INSTANCE_CLASS superClass; /* Superclass, unless java.lang.Object */
CONSTANTPOOL constPool; /* Pointer to constant pool */
FIELDTABLE fieldTable; /* Pointer to instance variable table */
METHODTABLE methodTable; /* Pointer to virtual method table */
unsigned short * ifaceTable; /* Pointer to interface table */
POINTERLIST staticFields; /* Holds static fields of the class */
short instSize; /* The size of class instances */
short status; /* Class readiness status */
THREAD initThread; /* Thread performing class initialization */
NativeFuncPtr finalizer; /* Pointer to finalizer */
};
typedef struct instanceClassStruct * INSTANCE_CLASS;
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) & AllClassblocks.java_lang_String;
这里就生成了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结构中的。
更多推荐
所有评论(0)