原创 KVM虚拟机文件加载分析

2011-2-15 14:22 1734 7 7 分类: MCU/ 嵌入式
在虚拟机初始化函数KVM_Start中会调用InitializeJavaSystemClasses函数,这个函数  用于加载一些系统所必需的类库,以及一些必要的初始化工作。  我们大概看一下:  void InitializeJavaSystemClasses()   {   #if !ROMIZING    int i;    /*得到基本类的Calss信息*/    JavaLangObject = (INSTANCE_CLASS)getRawClass("java/lang/Object");    JavaLangClass = (INSTANCE_CLASS)getRawClass("java/lang/Class");    JavaLangString = (INSTANCE_CLASS)getRawClass("java/lang/String");      ..............................    /*加载基本类*/    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");      ..................................    initNameAndType = getNameAndTypeKey("", "()V");    clinitNameAndType = getNameAndTypeKey("", "()V");    runNameAndType = getNameAndTypeKey("run", "()V");    mainNameAndType = getNameAndTypeKey("main", "([Ljava/lang/String;)V");      RunCustomCodeMethod = getSpecialMethod(JavaLangClass,    getNameAndTypeKey("runCustomCode", "()V"));    .....................................   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));   .......................................   }   一步一步往下看函数的调用过程。  getRawClass 实际上会调用getRawClassX函数。我们来看一下部分代码。  CLASS getRawClassX(CONST_CHAR_HANDLE nameH, int offset, int length)   {    ...............................    for (p = className + length ; ;) {    --p;    if (*p == '/') {    int packageNameLength = p - className;    int baseNameLength = (length - 1) - packageNameLength;    //实际上只是把路径解析成包名,以及文件名   packageName = getUStringX(nameH, offset, packageNameLength);    /* p and start may no longer be valid pointers, but there    * difference is still a valid offset */    baseName = getUStringX(nameH, (p + 1) - start, baseNameLength);    break;    } else if (p == className) {    packageName = NULL;    baseName = getUStringX(nameH, offset, length);    break;    }    }    result = change_Name_to_CLASS(packageName, baseName);    return result;    .................................   }   函数返回的是一个CLASS的结构。  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 */   };   getRawClass 中调用的一个最重要的函数就是change_Name_to_CLASS,实际上这个函数会跟据  包名和文件名构成键值,去相应的哈希表去查找,看是否已经建立过这个文件的信息,若有则返回,否则  建立class类型的结构,并插入哈希表。  getRawClass 并没有真正解析class文件,实际的工作是有loadClassfile完成的。回到InitializeJavaSystemClasses   函数。我们看一下loadClassfile实际所做的工作。  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 */   };   instanceClassStruct 是一个非常重要的结构体。上述英文已经给了很好的注释,我们接下来还会对他的每一个域进行  详尽的分析。loadClassfile执行实际的文件加载工作。我们来分段解析一下。    void loadClassfile(INSTANCE_CLASS InitiatingClass, bool_t fatalErrorIfFail)   {    if (clazz->status != CLASS_RAW) //该类必须未加载过   fatalVMError(KVM_MSG_EXPECTED_CLASS_STATUS_OF_CLASS_RAW);      /*    * Iteratively load the raw class bytes of the class and its raw    * superclasses.    */    while (clazz != NULL && clazz->status == CLASS_RAW) {    clazz->status = CLASS_LOADING;    loadRawClass(clazz, fatalErrorIfFail);    if (!fatalErrorIfFail && (clazz->status == CLASS_ERROR)) {    return;    }    clazz->status = CLASS_LOADED;      /*    * Now go up to the superclass.    */    clazz = clazz->superClass;      if (clazz != NULL) {       if (clazz->status == CLASS_ERROR)    raiseException(NoClassDefFoundError);    /*    * If a class is in CLASS_LOADED state, then this is    * equivalent to a recursive call to loadClassfile for the    * class and as such indicates as ClassCircularityError.    */    else if (clazz->status == CLASS_LOADED)    raiseException(ClassCircularityError);    /*    * Any other state is a VM error.    */    else if (clazz->status != CLASS_RAW &&    clazz->status < CLASS_LINKED)    fatalVMError(    KVM_MSG_EXPECTED_CLASS_STATUS_OF_CLASS_RAW_OR_CLASS_LINKED);      }    }      上段代码实际上是加载该类及其所有未加载的父类,状态检查部分我们略过,主要看实际的加载函数loadRawClass(clazz,     fatalErrorIfFail);。    static void loadRawClass(INSTANCE_CLASS CurrentClass, bool_t fatalErrorIfFail)   {   ...................................      /* Load version info and magic value */    loadVersionInfo(&ClassFile); //检查class文件的版本和魔数。     /* Load and create constant pool */    IS_TEMPORARY_ROOT(StringPool,    loadConstantPool(&ClassFile, CurrentClass));//解析常量池     /* Load class identification information */    loadClassInfo(&ClassFile, CurrentClass); //加载文件信息     /* Load interface pointers */    loadInterfaces(&ClassFile, CurrentClass);//加载接口信息     /* Load field information */    loadFields(&ClassFile, CurrentClass, &StringPool);//加载字段     /* Load method information */    loadMethods(&ClassFile, CurrentClass, &StringPool);//加载方法     /* Load the possible extra attributes (e.g., debug info) */    ignoreAttributes(&ClassFile, &StringPool);//省略不支持的属性     ch = loadByteNoEOFCheck(&ClassFile);    if (ch != -1) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_CLASSFILE_SIZE_DOES_NOT_MATCH);    }      /* Ensure that EOF has been reached successfully and close file */    closeClassfile(&ClassFile);      /* Make the class an instance of class 'java.lang.Class' */    CurrentClass->clazz.ofClass = JavaLangClass;    ....................................}     loadRawClass实际上就是class文件的格式解析文件。我们一步一步往下看。常量池中存放有众多信息,因此有必要  对其的实现做深入的了解。首先来看一下虚拟机内部用于存放常量的数据结构,注意是一个union类型。  /* Each of these represents one entry in the constant pool */    +--------+    * | 5 | entry[0]    * | | Contains the number of entries + 1 (4+1 here)    * +--------+    * | | entry[1]    * | | This is the first actual const pool entry    * +--------+    * | | entry[2]    * | | This is the second constant pool entry    * +--------+    * | | ... more constant pool entries ...    * | |    * +--------+    * | | entry[n-1] / n = 5 in this case    * | | Last actual constant pool entry    * +--------++    * |0| | | | | Byte array to store the type tag of each entry.    * +-+-+-+-+-+ If the entry contains a cached (previously resolved) entry,    * then the tag is OR'red with CP_CACHEBIT.    * In this example, 5 bytes are needed. Note that the    * type tag of the zeroeth entry is always zero (dummy entry).   union constantPoolEntryStruct {    struct {    unsigned short classIndex;    unsigned short nameTypeIndex;    } method; /* Also used by Fields */    CLASS clazz;    INTERNED_STRING_INSTANCE String;    cell *cache; /* Either clazz or String */    cell integer;    long length;    NameTypeKey nameTypeKey;    NameKey nameKey;    UString ustring;   };     static POINTERLIST loadConstantPool(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass)   {    unsigned short constantCount = loadShort(ClassFileH);//所含常量个数   .................    DECLARE_TEMPORARY_ROOT(CONSTANTPOOL_ENTRY, RawPool,    (CONSTANTPOOL_ENTRY)mallocBytes(constantCount * (1 + sizeof(*RawPool))));    DECLARE_TEMPORARY_ROOT(POINTERLIST, StringPool,    (POINTERLIST)callocObject(SIZEOF_POINTERLIST(constantCount), GCT_POINTERLIST));    StringPool->length = constantCount;   #define RAW_POOL(i) (RawPool)   #define CP_ENTRY(i) (ConstantPool->entries)    /* Read the constant pool entries from the class file */    for (cpIndex = 1; cpIndex < constantCount; cpIndex++) {    unsigned char tag = loadByte(ClassFileH);    unsigned char *Tags = (unsigned char *)(&RawPool[constantCount]);    Tags[cpIndex] = tag; //这个机制见上图       /*下面的这些解析步骤其实就是按照Class文件的格式一步步来就行了,注释看英文部分就行了*/    switch (tag) {    case CONSTANT_String:    case CONSTANT_Class: {    /* A single 16-bit entry that points to a UTF string */    unsigned short nameIndex = loadShort(ClassFileH);    RAW_POOL(cpIndex).integer = nameIndex;    break;    }      case CONSTANT_Fieldref:    case CONSTANT_Methodref:    case CONSTANT_InterfaceMethodref: {    /* Two 16-bit entries */    unsigned short classIndex = loadShort(ClassFileH);    unsigned short nameTypeIndex = loadShort(ClassFileH);    RAW_POOL(cpIndex).method.classIndex = classIndex;    RAW_POOL(cpIndex).method.nameTypeIndex = nameTypeIndex;    break;    }      case CONSTANT_Float:   #if !IMPLEMENTS_FLOAT    fatalError(KVM_MSG_FLOATING_POINT_NOT_SUPPORTED);   #endif    case CONSTANT_Integer:    {    /* A single 32-bit value */    long value = loadCell(ClassFileH);    RAW_POOL(cpIndex).integer = value;    break;    }      case CONSTANT_Double:   #if !IMPLEMENTS_FLOAT    fatalError(KVM_MSG_FLOATING_POINT_NOT_SUPPORTED);   #endif    case CONSTANT_Long:    /* A 64-bit value */    RAW_POOL(cpIndex).integer = loadCell(ClassFileH);    cpIndex++;    if (cpIndex >= constantCount) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_64BIT_CONSTANT);    }    /* set this location in the Tags array to 0 so it's    * flagged as a bogus location if some TCK test decides    * to read from the middle of this long constant pool entry.    */    Tags[cpIndex] = 0;    RAW_POOL(cpIndex).integer = loadCell(ClassFileH);    break;      case CONSTANT_NameAndType: {    /* Like Fieldref, etc */    unsigned short nameIndex = loadShort(ClassFileH);    unsigned short typeIndex = loadShort(ClassFileH);    /* In the second pass, below, these will be replaced with the    * actual nameKey and typeKey. Currently, they are indices    * to items in the constant pool that may not yet have been    * loaded */    RAW_POOL(cpIndex).nameTypeKey.nt.nameKey = nameIndex;    RAW_POOL(cpIndex).nameTypeKey.nt.typeKey = typeIndex;    break;    }      case CONSTANT_Utf8: {    unsigned short length = loadShort(ClassFileH);    /* This allocation may invalidate ClassFile */    char *string = mallocBytes(length + 1);    STRING_POOL(cpIndex) = string;    loadBytes(ClassFileH, string, length);    string[length] = '\0';      verifyUTF8String(string, length);    }    break;      default:    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_INVALID_CONSTANT_POOL_ENTRY);    break;    }      if (tag != CONSTANT_Utf8) {    lastNonUtfIndex = cpIndex;    }    }    /* Allocate memory for all the entries plus the array of tag bytes    * at the end.    */    int numberOfEntries = lastNonUtfIndex + 1;    /*包括标签和实际的数据*/    int tableSize =numberOfEntries + ((numberOfEntries + (CELL - 1)) >> log2CELL);    ConstantPool = (CONSTANTPOOL)callocPermanentObject(tableSize);    CONSTANTPOOL_LENGTH(ConstantPool) = numberOfEntries;    CurrentClass->constPool = ConstantPool;      /* Now create the constant pool entries ,这个过程需要大家对Class文件的结构有较深的认识*/    for (cpIndex = 1; cpIndex < constantCount; cpIndex++) {    /* These can move between iterations of the loop */    unsigned char *Tags = (unsigned char *)(&RawPool[constantCount]);    unsigned char *CPTags = CONSTANTPOOL_TAGS(ConstantPool);      unsigned char tag = Tags[cpIndex];    if (cpIndex <= lastNonUtfIndex) {    CPTags[cpIndex] = tag;    }      switch (tag) {      case CONSTANT_Class: {    unsigned short nameIndex =    (unsigned short)RAW_POOL(cpIndex).integer;    START_TEMPORARY_ROOTS    DECLARE_TEMPORARY_ROOT(const char *, name,    getUTF8String(&StringPool, nameIndex));    verifyName(name, LegalClass);    CP_ENTRY(cpIndex).clazz =    getRawClassX(&name, 0, strlen(name));    END_TEMPORARY_ROOTS    break;    }      case CONSTANT_String: {    unsigned short nameIndex =    (unsigned short)RAW_POOL(cpIndex).integer;    char *name = getUTF8String(&StringPool, nameIndex);    INTERNED_STRING_INSTANCE string =    internString(name, strlen(name));    CP_ENTRY(cpIndex).String = string;    break;    }    case CONSTANT_Fieldref:    case CONSTANT_Methodref:    case CONSTANT_InterfaceMethodref: {    /* Two 16-bit entries */    unsigned short classIndex = RAW_POOL(cpIndex).method.classIndex;    unsigned short nameTypeIndex =RAW_POOL(cpIndex).method.nameTypeIndex;    if (classIndex >= constantCount ||    Tags[classIndex] != CONSTANT_Class ||    nameTypeIndex >= constantCount ||    Tags[nameTypeIndex] != CONSTANT_NameAndType) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_FIELD_OR_METHOD_REFERENCE);    } else {    unsigned short nameIndex =    RAW_POOL(nameTypeIndex).nameTypeKey.nt.nameKey;    unsigned short typeIndex =    RAW_POOL(nameTypeIndex).nameTypeKey.nt.typeKey;    char* name = getUTF8String(&StringPool, nameIndex);    char* type = getUTF8String(&StringPool, typeIndex);    if ( (tag == CONSTANT_Fieldref && type[0] == '(')    || (tag != CONSTANT_Fieldref && type[0] != '(')    || (tag != CONSTANT_Fieldref &&    !strcmp(name, ""))) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_NAME_OR_TYPE_REFERENCE);    }    CP_ENTRY(cpIndex) = RAW_POOL(cpIndex);    }    break;    }      case CONSTANT_Double:      case CONSTANT_Long:    CP_ENTRY(cpIndex).integer = RAW_POOL(cpIndex).integer;    cpIndex++;    CPTags[cpIndex] = 0;    CP_ENTRY(cpIndex).integer = RAW_POOL(cpIndex).integer;    break;      case CONSTANT_Float:      case CONSTANT_Integer:    CP_ENTRY(cpIndex).integer = RAW_POOL(cpIndex).integer;    break;      case CONSTANT_NameAndType: {    unsigned short nameIndex = RAW_POOL(cpIndex).nameTypeKey.nt.nameKey;    unsigned short typeIndex = RAW_POOL(cpIndex).nameTypeKey.nt.typeKey;    START_TEMPORARY_ROOTS    DECLARE_TEMPORARY_ROOT(const char *, name,    getUTF8String(&StringPool, nameIndex));    DECLARE_TEMPORARY_ROOT(const char *, type,    getUTF8String(&StringPool, typeIndex));    NameKey nameKey;    unsigned short typeKey;    if (type[0] == '(') {    verifyName(name, LegalMethod);    verifyMethodType(name, type);    typeKey = change_MethodSignature_to_Key(&type, 0,    strlen(type));    } else {    verifyName(name, LegalField);    verifyFieldType(type);    typeKey = change_FieldSignature_to_Key(&type, 0,    strlen(type));    }    nameKey = change_Name_to_Key(&name, 0, strlen(name));    CP_ENTRY(cpIndex).nameTypeKey.nt.nameKey = nameKey;    CP_ENTRY(cpIndex).nameTypeKey.nt.typeKey = typeKey;    END_TEMPORARY_ROOTS    break;    }      case CONSTANT_Utf8:    /* We don't need these after loading time. So why bother */    if (cpIndex <= lastNonUtfIndex) {    CP_ENTRY(cpIndex).integer = 0;    CPTags[cpIndex] = 0;    }    break;      default:    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_INVALID_CONSTANT_POOL_ENTRY);    break;    }    }    result = StringPool;    END_TEMPORARY_ROOTS    return result;   }     常量池解析好后接下来解析文件信息  static void   loadClassInfo(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass)   {    INSTANCE_CLASS thisClass;    INSTANCE_CLASS superClass;    CONSTANTPOOL ConstantPool = CurrentClass->constPool;      unsigned short accessFlags = loadShort(ClassFileH) & RECOGNIZED_CLASS_FLAGS;    ..................    unsigned short thisClassIndex = loadShort(ClassFileH);    verifyConstantPoolEntry(CurrentClass, thisClassIndex, CONSTANT_Class);    thisClass = (INSTANCE_CLASS)CP_ENTRY(thisClassIndex).clazz;         }    {    unsigned short superClassIndex = loadShort(ClassFileH);    if (superClassIndex == 0) {    superClass = NULL;    } else {    verifyConstantPoolEntry(CurrentClass, superClassIndex,    CONSTANT_Class);    superClass = (INSTANCE_CLASS)CP_ENTRY(superClassIndex).clazz;    }    }       CurrentClass->superClass = superClass; /*父类*/    CurrentClass->clazz.accessFlags = accessFlags;     }   加载接口,这个代码很简单。  static void loadInterfaces(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass)   {    unsigned short interfaceCount = loadShort(ClassFileH);    long byteSize = (interfaceCount+1) * sizeof(unsigned short);    unsigned int ifIndex;      if (interfaceCount == 0) {    return;    }      if (USESTATIC) {    CurrentClass->ifaceTable = (unsigned short *)mallocBytes(byteSize);    } else {    long cellSize = ByteSizeToCellSize(byteSize);    CurrentClass->ifaceTable =    (unsigned short*)callocPermanentObject(cellSize);    }      /* Store length in the first slot */    CurrentClass->ifaceTable[0] = interfaceCount;      for (ifIndex = 1; ifIndex <= interfaceCount; ifIndex++) {    unsigned short cpIndex = loadShort(ClassFileH);    verifyConstantPoolEntry(CurrentClass, cpIndex, CONSTANT_Class);    CurrentClass->ifaceTable[ifIndex] = cpIndex;/*存放常量池的下标即可*/    }   }   接下来就是加载字段了,字段主要有静态和非静态之分。先看一下数据结构,英文的介绍已经很详细了。  struct fieldTableStruct {    long length;    struct fieldStruct fields[1];   };   /* FIELD */   struct fieldStruct {    NameTypeKey nameTypeKey;    long accessFlags; /* Access indicators (public/private etc.) */    INSTANCE_CLASS ofClass; /* Backpointer to the class owning the field */    union {    long offset; /* for dynamic objects */    void *staticAddress; /* pointer to static. */    } u;   };   static void loadFields(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass,    POINTERLIST_HANDLE StringPoolH)   {    unsigned short fieldCount = loadShort(ClassFileH);//字段个数   int fieldTableSize = SIZEOF_FIELDTABLE(fieldCount);//需申请空间的大小   FIELDTABLE fieldTable;    unsigned int index;      int staticPtrCount = 0;    int staticNonPtrCount = 0;    fieldTable = (FIELDTABLE)callocPermanentObject(fieldTableSize);//申请空间   /* Store the size of the table at the beginning of the table */    fieldTable->length = fieldCount;    CurrentClass->fieldTable = fieldTable;      for (index = 0; index < fieldCount; index++) {    //这部分大家去看class文件的规范吧   unsigned short accessFlags =    loadShort(ClassFileH) & RECOGNIZED_FIELD_FLAGS;    unsigned short nameIndex = loadShort(ClassFileH);    unsigned short typeIndex = loadShort(ClassFileH);    bool_t isStatic = (accessFlags & ACC_STATIC) != 0;    FIELD thisField;         DECLARE_TEMPORARY_ROOT(const char *, fieldName,    getUTF8String(StringPoolH, nameIndex));    DECLARE_TEMPORARY_ROOT(const char *, signature,    getUTF8String(StringPoolH, typeIndex));    NameTypeKey result;      verifyFieldFlags(accessFlags, CurrentClass->clazz.accessFlags);    verifyName(fieldName, LegalField);    verifyFieldType(signature);      result.nt.nameKey =    change_Name_to_Key(&fieldName, 0, strlen(fieldName));    result.nt.typeKey =    change_FieldSignature_to_Key(&signature, 0, strlen(signature));         thisField = &CurrentClass->fieldTable->fields[index];      /* Check if the field is double length, or is a pointer type.    * If so set the appropriate bit in the word */    switch (signature[0]) {    case 'D': case 'J': accessFlags |= ACC_DOUBLE; break;    case 'L': case '[': accessFlags |= ACC_POINTER; break;    }      /* Store the corresponding information in the structure */    thisField->nameTypeKey = result;    thisField->ofClass = CurrentClass;    thisField->accessFlags = accessFlags;      if (isStatic) {    //有可能该静态的字段是个常量,如果是常量,则将u.offset直接用常量池的下标代替   loadStaticFieldAttributes(ClassFileH, CurrentClass,thisField, StringPoolH);    if (accessFlags & ACC_POINTER) {    staticPtrCount++; //统计静态引用的数量   } else {    staticNonPtrCount += (accessFlags & ACC_DOUBLE) ? 2 : 1;//非引用的static    }    } else {    //如果是非静态的字段,后跟的属性全部忽略   ignoreAttributes(ClassFileH, StringPoolH);    }       }     }    //如果存在着静态的字段,则继续往下执行  if (staticPtrCount > 0 || staticNonPtrCount > 0) {    //为静态变量申请空间   int staticsSize = SIZEOF_POINTERLIST(staticNonPtrCount+staticPtrCount);    POINTERLIST statics = (POINTERLIST)callocPermanentObject(staticsSize);      /* All the non-pointers go after all the pointers */    void **nextPtrField = (void **)statics->data;    void **nextNonPtrField = nextPtrField + staticPtrCount;      /* Set the length field so that the GC only looks at the pointers */    statics->length = staticPtrCount;    CurrentClass->staticFields = statics;      ASSERTING_NO_ALLOCATION    CONSTANTPOOL ConstantPool = CurrentClass->constPool;      FOR_EACH_FIELD(thisField, fieldTable)    long accessFlags = thisField->accessFlags;    unsigned short cpIndex;    if (!(accessFlags & ACC_STATIC)) {    continue;    }    cpIndex = (unsigned short)(thisField->u.offset);    if (thisField->accessFlags & ACC_POINTER) {    /* The only possible initialization is for a string */    thisField->u.staticAddress = nextPtrField;    if (cpIndex != 0) {    /*这里是需要注意的*/    verifyConstantPoolEntry(CurrentClass, cpIndex,    CONSTANT_String);    *(INTERNED_STRING_INSTANCE *)nextPtrField =    CP_ENTRY(cpIndex).String;    }    nextPtrField++;    } else {    thisField->u.staticAddress = nextNonPtrField;    if (cpIndex != 0) {    unsigned char tag;    switch(thisField->nameTypeKey.nt.typeKey) {    case 'B': case 'C': case 'Z': case 'S': case 'I':    tag = CONSTANT_Integer;    break;    case 'F':      tag = CONSTANT_Float;    break;    case 'D':    tag = CONSTANT_Double;    break;    case 'J':    tag = CONSTANT_Long;    break;    default:    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_SIGNATURE);    }    verifyConstantPoolEntry(CurrentClass, cpIndex, tag);    if (accessFlags & ACC_DOUBLE) {    /* Initialize a double or long */    CONSTANTPOOL_ENTRY thisEntry = &CP_ENTRY(cpIndex);    unsigned long hiBytes, loBytes;    hiBytes = (unsigned long)(thisEntry[0].integer);    loBytes = (unsigned long)(thisEntry[1].integer);    SET_LONG_FROM_HALVES(nextNonPtrField,    hiBytes, loBytes);    } else {    *(cell *)nextNonPtrField =    CP_ENTRY(cpIndex).integer;    }    }    nextNonPtrField += (accessFlags & ACC_DOUBLE) ? 2 : 1;    }    END_FOR_EACH_FIELD    END_ASSERTING_NO_ALLOCATION    }     .....................   }     接下来是最重要的一个解析方法的函数,还是看一下存放方法的数据结构:  struct methodTableStruct {    long length;    struct methodStruct methods[1];   };   /* METHOD */   struct methodStruct {    NameTypeKey nameTypeKey;    union {    struct {    BYTE* code;    HANDLERTABLE handlers;    union {    STACKMAP pointerMap;    POINTERLIST verifierMap;    } stackMaps;    unsigned short codeLength;    unsigned short maxStack;    /* frameSize should be here, rather than in the generic part, */    /* but this gives us better packing of the bytes */    } java;    struct {    void (*code)(void);    void *info;    } native;    } u;    long accessFlags; /* Access indicators (public/private etc.) */    INSTANCE_CLASS ofClass; /* Backpointer to the class owning the field */    unsigned short frameSize; /* Method frame size (arguments+local vars) */    unsigned short argCount; /* Method argument (parameter) count */   };   其中的异常表如下定义:  /* HANDLERTABLE */   struct exceptionHandlerTableStruct {    long length;    struct exceptionHandlerStruct handlers[1];   };   /* HANDLER */   struct exceptionHandlerStruct {    unsigned short startPC; /* Start and end program counter indices; these */    unsigned short endPC; /* determine the code range where the handler is valid */    unsigned short handlerPC; /* Location that is called upon exception */    unsigned short exception; /* Class of the exception (as a constant pool index) */    /* Note: 0 in 'exception' indicates an 'any' handler */   };       static void   loadMethods(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass,    POINTERLIST_HANDLE StringPoolH)   {    unsigned short methodCount = loadShort(ClassFileH);    if (methodCount == 0) {    return;    }    START_TEMPORARY_ROOTS    //申请空间   int tableSize = SIZEOF_METHODTABLE(methodCount);    unsigned int index;    METHODTABLE methodTable = (METHODTABLE)callocPermanentObject(tableSize);    methodTable->length = methodCount;    CurrentClass->methodTable = methodTable;      for (index = 0; index < methodCount; index++) {      METHOD thisMethod = &methodTable->methods[index];    //调用实际加载函数   loadOneMethod(ClassFileH, CurrentClass, &thisMethod, StringPoolH);      }    END_TEMPORARY_ROOTS      .................}     static void   loadOneMethod(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass,    METHOD_HANDLE thisMethodH, POINTERLIST_HANDLE StringPoolH)   {      METHOD thisMethod;    unsigned short accessFlags =    loadShort(ClassFileH) & RECOGNIZED_METHOD_FLAGS;    unsigned short nameIndex = loadShort(ClassFileH);    unsigned short typeIndex = loadShort(ClassFileH);    START_TEMPORARY_ROOTS    DECLARE_TEMPORARY_ROOT(const char *, methodName,getUTF8String(StringPoolH, nameIndex));    DECLARE_TEMPORARY_ROOT(const char *, signature,getUTF8String(StringPoolH, typeIndex));    NameTypeKey result;    result.nt.nameKey =    change_Name_to_Key(&methodName, 0, strlen(methodName));    result.nt.typeKey =    change_MethodSignature_to_Key(&signature, 0, strlen(signature));      ASSERTING_NO_ALLOCATION    thisMethod = unhand(thisMethodH);    thisMethod->nameTypeKey = result;    thisMethod->argCount = verifyMethodType(methodName, signature);      /* If this is a virtual method, increment argument counter,多一个的 */    if (!(accessFlags & ACC_STATIC)) {    thisMethod->argCount++;    }      if (thisMethod->argCount > 255) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_TOO_MANY_METHOD_ARGUMENTS);    }    switch (strchr(signature, ')')[1]) {    case 'D': case 'J': accessFlags |= ACC_DOUBLE; break;    case 'L': case '[': accessFlags |= ACC_POINTER; break;    case 'V': accessFlags |= (ACC_POINTER | ACC_DOUBLE); break;    }      thisMethod->accessFlags = accessFlags;    thisMethod->ofClass = CurrentClass;    /* These values will be initialized later */    thisMethod->frameSize = 0;    thisMethod->u.java.maxStack = 0;    thisMethod->u.java.handlers = NIL;    END_ASSERTING_NO_ALLOCATION      loadMethodAttributes(ClassFileH, thisMethodH, StringPoolH);    ................................    //对native方法的处理   if (accessFlags & ACC_NATIVE) {    /* Store native function pointer in the code field */    thisMethod->u.native.info = NULL;    thisMethod->u.native.code =    getNativeFunction(CurrentClass, methodName, signature);      /* Check for finalizers, skipping java.lang.Object */    if (CurrentClass->superClass != NULL) {    if (strcmp(methodName, "finalize") == 0) {    if (accessFlags & ACC_PRIVATE) {    /* private native finalize() method found */    /* Save native finalizer pointer in the class field */    CurrentClass->finalizer =    (NativeFuncPtr)thisMethod->u.native.code;    }    }    }    }   .........................   }   上述方法中调用了一个函数loadMethodAttributes。该函数完成实际方法信息的加载,其主要是对code属性的解析。  static void   loadMethodAttributes(FILEPOINTER_HANDLE ClassFileH,    METHOD_HANDLE thisMethodH,    POINTERLIST_HANDLE StringPoolH)   {    unsigned short attrCount = loadShort(ClassFileH);    METHOD thisMethod = unhand(thisMethodH);    int attrIndex;    bool_t needCode = !(thisMethod->accessFlags & (ACC_NATIVE | ACC_ABSTRACT));    bool_t needExceptionTable = TRUE; /* always optional */      /* See if the field has any attributes in the class file */    for (attrIndex = 0; attrIndex < attrCount; attrIndex++) {    unsigned short attrNameIndex = loadShort(ClassFileH);    unsigned int attrLength = loadCell(ClassFileH);    char* attrName = getUTF8String(StringPoolH, attrNameIndex);    /* Check if the attribute contains source code */    if (strcmp(attrName, "Code") == 0) {    unsigned int actualLength;    if (!needCode) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_DUPLICATE_CODE_ATTRIBUTE);    }    actualLength = loadCodeAttribute(ClassFileH, thisMethodH, StringPoolH);    if (actualLength != attrLength) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_CODE_ATTRIBUTE_LENGTH);    }    needCode = FALSE;    }   ............................   }   static unsigned int   loadCodeAttribute(FILEPOINTER_HANDLE ClassFileH,    METHOD_HANDLE thisMethodH,    POINTERLIST_HANDLE StringPoolH)   {    unsigned int actualAttrLength;    unsigned int codeLength;    int nCodeAttrs;    int codeAttrIndex;    BYTE* code;    bool_t needStackMap = TRUE;      METHOD thisMethod = unhand(thisMethodH);    /* Create a code object and store it in the method */    thisMethod->u.java.maxStack = loadShort(ClassFileH); /* max stack */    thisMethod->frameSize = loadShort(ClassFileH); /* frame size */    codeLength = loadCell(ClassFileH); /* code length */      /* KVM verifier cannot handle bytecode longer than 32 KB */    if (codeLength >= 0x7FFF) {    raiseExceptionWithMessage(OutOfMemoryError,    KVM_MSG_METHOD_LONGER_THAN_32KB);    }      /* KVM frames cannot contain more than 512 locals */    if (thisMethod->u.java.maxStack + thisMethod->frameSize >    MAXIMUM_STACK_AND_LOCALS) {    raiseExceptionWithMessage(OutOfMemoryError,    KVM_MSG_TOO_MANY_LOCALS_AND_STACK);    }      /* Allocate memory for storing the bytecode array */    code = (BYTE *)callocPermanentObject(ByteSizeToCellSize(codeLength));       thisMethod = unhand(thisMethodH);    thisMethod->u.java.code = code;      thisMethod->u.java.codeLength = codeLength;    loadBytes(ClassFileH, (char *)thisMethod->u.java.code, codeLength);    actualAttrLength = 2 + 2 + 4 + codeLength;      /* Load exception handlers associated with the method */    actualAttrLength += loadExceptionHandlers(ClassFileH, thisMethodH);      nCodeAttrs = loadShort(ClassFileH);    actualAttrLength += 2;    for (codeAttrIndex = 0; codeAttrIndex < nCodeAttrs; codeAttrIndex++) {    unsigned short codeAttrNameIndex = loadShort(ClassFileH);    unsigned int codeAttrLength = loadCell(ClassFileH);    char* codeAttrName = getUTF8String(StringPoolH, codeAttrNameIndex);    /* Check if the attribute contains stack maps */    if (!strcmp(codeAttrName, "StackMap")) {    unsigned int stackMapAttrSize;    if (!needStackMap) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_DUPLICATE_STACKMAP_ATTRIBUTE);    }    needStackMap = FALSE;    stackMapAttrSize = loadStackMaps(ClassFileH, thisMethodH);    if (stackMapAttrSize != codeAttrLength) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_ATTRIBUTE_SIZE);    }    } else {    skipBytes(ClassFileH, codeAttrLength);    }    actualAttrLength += 6 + codeAttrLength;    }    return actualAttrLength;   }   加载异常信息的函数  static int   loadExceptionHandlers(FILEPOINTER_HANDLE ClassFileH, METHOD_HANDLE thisMethodH)   {    unsigned short numberOfHandlers = loadShort(ClassFileH);    if (numberOfHandlers > 0) {    HANDLERTABLE handlerTable;    METHOD thisMethod;    int tableSize = SIZEOF_HANDLERTABLE(numberOfHandlers);      handlerTable = (HANDLERTABLE)callocPermanentObject(tableSize);      handlerTable->length = numberOfHandlers;    thisMethod = unhand(thisMethodH);    thisMethod->u.java.handlers = handlerTable;      ASSERTING_NO_ALLOCATION    FOR_EACH_HANDLER(thisHandler, handlerTable)    unsigned short startPC = loadShort(ClassFileH);    unsigned short endPC = loadShort(ClassFileH);    unsigned short handlerPC = loadShort(ClassFileH);    unsigned short exception = loadShort(ClassFileH);      if (startPC >= thisMethod->u.java.codeLength ||    endPC > thisMethod->u.java.codeLength ||    startPC >= endPC ||    handlerPC >= thisMethod->u.java.codeLength) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_EXCEPTION_HANDLER_FOUND);    }    if (exception != 0) {    verifyConstantPoolEntry(thisMethod->ofClass,    exception, CONSTANT_Class);    }    thisHandler->startPC = startPC;    thisHandler->endPC = endPC;    thisHandler->handlerPC = handlerPC;    thisHandler->exception = exception;    END_FOR_EACH_HANDLER    END_ASSERTING_NO_ALLOCATION    } else {    /* Method has no associated exception handlers */    unhand(thisMethodH)->u.java.handlers = NULL;    }    return (numberOfHandlers * 8 + 2);   }     /////////////////////////////////////////////////////////   再回到loadClassfile函数继续往下看    void   loadClassfile(INSTANCE_CLASS InitiatingClass, bool_t fatalErrorIfFail)   {    while ((clazz = findSuperMostUnlinked(InitiatingClass)) != NULL) {      if (clazz->superClass == NULL) {    if (clazz != JavaLangObject) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_SUPERCLASS);    }       clazz->instSize = 0;    }    else {    INSTANCE_CLASS superClass = clazz->superClass;    /*    * Cannot inherit from an array class.    */    if (IS_ARRAY_CLASS((CLASS)superClass))    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_SUPERCLASS);      /*    * The superclass cannot be an interface. From the    * JVM Spec section 5.3.5:    *    * If the class of interface named as the direct    * superclass of C is in fact an interface, loading    * throws an IncompatibleClassChangeError.    */    if (superClass->clazz.accessFlags & ACC_INTERFACE) {    raiseExceptionWithMessage(IncompatibleClassChangeError,    KVM_MSG_CLASS_EXTENDS_INTERFACE);    }    /*    * The superclass cannot be final.    * Inheriting from a final class is a VerifyError according    * to J2SE JVM behaviour. There is no explicit    * documentation in the JVM Spec.    */    if (superClass->clazz.accessFlags & ACC_FINAL) {    raiseExceptionWithMessage(VerifyError,    KVM_MSG_CLASS_EXTENDS_FINAL_CLASS);    }      /*    * The current class must have access to its super class    */    verifyClassAccess((CLASS)superClass,clazz);      /*    * If this is an interface class, its superclass must be    * java.lang.Object.    */    if (superClass != JavaLangObject &&    (clazz->clazz.accessFlags & ACC_INTERFACE)) {    raiseExceptionWithMessage(ClassFormatError,    KVM_MSG_BAD_SUPERCLASS);    }      /*    * Compute instance size and instance field offset.    * Make the instance size of the new class "inherit"    * the instance size of the superclass    */    clazz->instSize = superClass->instSize;    }      .........................      FOR_EACH_FIELD(thisField, clazz->fieldTable)    unsigned short accessFlags = (unsigned short)thisField->accessFlags;    //记载偏移量   if ((accessFlags & ACC_STATIC) == 0) {    thisField->u.offset = clazz->instSize;    clazz->instSize += (accessFlags & ACC_DOUBLE) ? 2 : 1;    }    END_FOR_EACH_FIELD    moveClassFieldsToStatic(clazz);    clazz->status = CLASS_LINKED;      }   

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /6 下一条