kvm启动流程-004

本文介绍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;
       }
    }
}

此处的步骤如下:

  1. 计算classpath的个数
  2. 在堆中分配. 这个之前文章有介绍
  3. 加入到gc root 中
  4. 初始化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);
}

步骤如下:

  1. 读取Object,Class,String,基本类型
  2. 加载JavaLangObject, JavaLangClass, JavaLangString, System, Thread, Throwable, Error
  3. 初始化,,run,main 方法的描述符
  4. 获得runCustomCode方法
  5. 将runCustomCode方法的字节码修改为CUSTOMCODE
  6. 将StackOverflowObject 加入到root中

这其中的大部分方法,在之前的文章中介绍,此处就不再展开.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值