本文介绍kvm启动过程中的初始化class-path table,初始化VM所需要的内部类.
初始化class-path table
此处的代码如下:
void InitializeClassLoading()
{
char *classpath = UserClassPath;
int length, pathCount, i;
int tableIndex;
int previousI;
/* Count the number of individual directory paths along CLASSPATH 1.计算classpath的个数*/
length = strlen(classpath);
pathCount = 1;
for (i = 0; i < length; i++) {
if (classpath[i] == PATH_SEPARATOR) pathCount++;
}
/* We use callocObject() since we'll be allocating new objects to fill
* up the table 2. 在堆中分配*/
ClassPathTable = (POINTERLIST)callocObject(SIZEOF_POINTERLIST(pathCount),
GCT_POINTERLIST);
// 3. 加入到gc root 中
makeGlobalRoot((cell **)&ClassPathTable);
ClassPathTable->length = pathCount;
MaxClassPathTableLength = 0;
tableIndex = 0;
previousI = 0;
// 4. 初始化ClassPathTable
for (i = 0; i <= length; i++) {
if (classpath[i] == PATH_SEPARATOR || classpath[i] == 0) {
#ifndef POCKETPC
struct stat sbuf;
#else
DWORD isDir;
WCHAR dirName[MAX_PATH];
#endif /* POCKETPC */
/* Create a new string containing the individual directory path.
* We prepend either a 'j' (jar file) or 'd' (directory) indicating
* the type of classpath element this is.
*/
unsigned int length = i - previousI;
CLASS_PATH_ENTRY result =
(CLASS_PATH_ENTRY)mallocBytes(
sizeof(struct classPathEntryStruct) + length);
/* Copy the name into the result buffer */
memcpy(result->name, classpath + previousI, length);
result->name[length] = '\0';
result->type = '\0'; /* indicates a problem */
#ifndef POCKETPC
if (stat(result->name, &sbuf) < 0) {
/* No need to do anything */
} else if (S_ISDIR(sbuf.st_mode)) {// 如果是目录
/* This is a directory */
/* Store the newly created string to the classpath table */
if (length > MaxClassPathTableLength) {
MaxClassPathTableLength = length;
}
result->type = 'd';
}
#else
/* This is converts result->name to a WCHAR
* so that we check if it is a DIR or not. */
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, result->name,
-1, dirName, sizeof(dirName));
isDir = GetFileAttributes(dirName);
if ((0xFFFFFFFF != isDir) && (isDir & FILE_ATTRIBUTE_DIRECTORY)) {
if (length > MaxClassPathTableLength) {
MaxClassPathTableLength = length;
}
result->type = 'd';
}
#endif /* POCKETPC */
#if JAR_FILES_USE_STDIO
else if (openJARFile(result->name, 0, &result->u.jarInfo)) {// 如果是jar
result->type = 'j';
}
#else
else {
/* This is something we only do for debugging */
long fileLength = sbuf.st_size;
FILE *file = fopen(result->name, "rb");
char *data = mmap(0, fileLength, PROT_READ, MAP_SHARED,
fileno(file), 0);
if (openJARFile(data, fileLength, &result->u.jarInfo)) {
result->type = 'j';
} else {
/* Not a 'jar' file. Unmap it */
if (data != NULL) {
munmap(data, fileLength);
}
}
}
#endif /* JAR_FILES_USE_STDIO */
if (result->type == '\0') {// 如果是其他情况
/* bad entry */
ClassPathTable->length--;
} else {// 加入到ClassPathTable
ClassPathTable->data[tableIndex].cellp = (cell*)result;
tableIndex++;
}
previousI = i+1;
}
}
}
此处的步骤如下:
- 计算classpath的个数
- 在堆中分配. 这个之前文章有介绍
- 加入到gc root 中
- 初始化ClassPathTable,只对classpath是目录,jar包处理,其他情况,是例外.
其中,第3步的代码如下:
void
makeGlobalRoot(cell** object)
{
int index = GlobalRootsLength;
if (index >= MAXIMUM_GLOBAL_ROOTS) {
fatalError(KVM_MSG_GLOBAL_ROOT_OVERFLOW);
}
GlobalRoots[index].cellpp = object;
GlobalRootsLength = index + 1;
}
初始化VM所需要的内部类
此处的代码如下:
void InitializeJavaSystemClasses()
{
#if !ROMIZING
int i;
// 1. 读取Object,Class,String,基本类型
JavaLangObject = (INSTANCE_CLASS)getRawClass("java/lang/Object");
JavaLangClass = (INSTANCE_CLASS)getRawClass("java/lang/Class");
JavaLangString = (INSTANCE_CLASS)getRawClass("java/lang/String");
memset(PrimitiveArrayClasses, 0, sizeof(PrimitiveArrayClasses));
for (i = T_FIRSTPRIMITIVE_TYPE; i <= T_LASTPRIMITIVETYPE; i++) {
if (!IMPLEMENTS_FLOAT && (i == T_FLOAT || i == T_DOUBLE)) {
/* If we're not implementing floats, then don't try to
* create arrays of floats or arrays of doubles */
} else {
PrimitiveArrayClasses[i] =
getArrayClass(1, NULL, typeCodeToSignature((char)i));
}
}
TRY {
/* Now we can go back and create these for real. . . . 2. 加载 */
loadClassfile(JavaLangObject, TRUE);
loadClassfile(JavaLangClass, TRUE);
loadClassfile(JavaLangString, TRUE);
/* Load or initialize some other system classes */
JavaLangSystem = (INSTANCE_CLASS)getClass("java/lang/System");
JavaLangThread = (INSTANCE_CLASS)getClass("java/lang/Thread");
JavaLangThrowable = (INSTANCE_CLASS)getClass("java/lang/Throwable");
JavaLangError = (INSTANCE_CLASS)getClass("java/lang/Error");
} CATCH (e) {
fprintf(stdout,"%s", getClassName((CLASS)e->ofClass));
if (e->message != NULL) {
fprintf(stdout, ": %s\n", getStringContents(e->message));
} else {
fprintf(stdout, "\n");
}
fatalVMError(KVM_MSG_UNABLE_TO_INITIALIZE_SYSTEM_CLASSES);
} END_CATCH
#if INCLUDEDEBUGCODE
if ( (JavaLangObject->status == CLASS_ERROR)
|| (JavaLangClass->status == CLASS_ERROR)
|| (JavaLangString->status == CLASS_ERROR)
|| (JavaLangThread == NULL)
|| (JavaLangThrowable == NULL)
|| (JavaLangError == NULL)) {
fatalVMError(KVM_MSG_UNABLE_TO_INITIALIZE_SYSTEM_CLASSES);
}
#endif /* INCLUDEDEBUGCODE */
#else /* ROMIZING */
InitializeROMImage();
#endif /* !ROMIZING */
if (!ROMIZING || RELOCATABLE_ROM) {
/* Get handy pointers to special methods 2.1 初始化<init>,<clinit>,run,main 方法的描述符 */
initNameAndType = getNameAndTypeKey("<init>", "()V");
clinitNameAndType = getNameAndTypeKey("<clinit>", "()V");
runNameAndType = getNameAndTypeKey("run", "()V");
mainNameAndType = getNameAndTypeKey("main", "([Ljava/lang/String;)V");
// 2.2 获得runCustomCode方法
RunCustomCodeMethod = getSpecialMethod(JavaLangClass,
getNameAndTypeKey("runCustomCode", "()V"));
/* Patch the bytecode, was a "return" 2.3 将runCustomCode方法的字节码修改为CUSTOMCODE */
if (RELOCATABLE_ROM) {
/* Do nothing. Already patched */
} else if (!USESTATIC || (inAnyHeap(RunCustomCodeMethod->u.java.code))){
RunCustomCodeMethod->u.java.code[0] = CUSTOMCODE;
RunCustomCodeMethod->u.java.maxStack =
RunCustomCodeMethod_MAX_STACK_SIZE;
} else {
BYTE newcode = CUSTOMCODE;
short newMaxStack = RunCustomCodeMethod_MAX_STACK_SIZE;
char *start = (char*)((INSTANCE_CLASS)JavaLangClass)->constPool;
int offset = (char*)(RunCustomCodeMethod->u.java.code) - start;
modifyStaticMemory(start, offset, &newcode, sizeof(newcode));
offset = (char *)(&RunCustomCodeMethod->u.java.maxStack) - start;
modifyStaticMemory(start, offset,
&newMaxStack, sizeof(newMaxStack));
}
}
JavaLangOutOfMemoryError =
(INSTANCE_CLASS)getClass(OutOfMemoryError);
// 实例化JavaLangOutOfMemoryError
OutOfMemoryObject =
(THROWABLE_INSTANCE)instantiate(JavaLangOutOfMemoryError);
makeGlobalRoot((cell **)&OutOfMemoryObject);
StackOverflowObject = OutOfMemoryObject;
/* If we had full JLS/JVMS error classes:
StackOverflowObject =
(THROWABLE_INSTANCE)instantiate(
(INSTANCE_CLASS)getClass(StackOverflowError));
*/
// 3. 将StackOverflowObject 加入到root中
makeGlobalRoot((cell **)&StackOverflowObject);
}
步骤如下:
- 读取Object,Class,String,基本类型
- 加载JavaLangObject, JavaLangClass, JavaLangString, System, Thread, Throwable, Error
- 初始化,,run,main 方法的描述符
- 获得runCustomCode方法
- 将runCustomCode方法的字节码修改为CUSTOMCODE
- 将StackOverflowObject 加入到root中
这其中的大部分方法,在之前的文章中介绍,此处就不再展开.