在虚拟机初始化函数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条评论)
登录后参与讨论