📄 loader.c
字号:
unsigned short typeIndex = loadShort(ClassFileH); bool_t isStatic = (accessFlags & ACC_STATIC) != 0; FIELD thisField; START_TEMPORARY_ROOTS 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, TRUE); verifyFieldType(signature); result.nt.nameKey = change_Name_to_Key(&fieldName, 0, strlen(fieldName)); result.nt.typeKey = change_FieldSignature_to_Key(&signature, 0, strlen(signature)); ASSERTING_NO_ALLOCATION thisField = &CurrentClass->fieldTable->fields[index];#if INCLUDEDEBUGCODE if (traceclassloadingverbose) { fprintf(stdout, "Field '%s' loaded\n", fieldName); }#endif /* INCLUDEDEBUGCODE */ /* 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) { loadStaticFieldAttributes(ClassFileH, CurrentClass, thisField, StringPoolH); if (accessFlags & ACC_POINTER) { staticPtrCount++; } else { staticNonPtrCount += (accessFlags & ACC_DOUBLE) ? 2 : 1; } } else { ignoreAttributes(ClassFileH, StringPoolH); } END_ASSERTING_NO_ALLOCATION END_TEMPORARY_ROOTS } /* We know go back and look at each of the static fields again. */ if (staticPtrCount > 0 || staticNonPtrCount > 0) { /* We put all the statics into a POINTERLIST. We specifically make * a POINTERLIST in which the real length is longer than the value * put into the length field. The garbage collector only will look * at the first "length" fields. * So all the pointer statics go before all the non-pointer statics. * * As a hack, loadStaticFieldAttributes() has put into the offset * field the constant pool entry containing the static's initial * value. The static field should be initialized appropriately * once space for it has been allocated */ /* Allocate space for all the pointers and non pointers. */ 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; if (USESTATIC) { /* Otherwise, this is in permanent memory and won't move */ fieldTable = CurrentClass->fieldTable; } 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':#if !IMPLEMENTS_FLOAT fatalError(KVM_MSG_FLOATING_POINT_NOT_SUPPORTED);#endif tag = CONSTANT_Float; break; case 'D':#if !IMPLEMENTS_FLOAT fatalError(KVM_MSG_FLOATING_POINT_NOT_SUPPORTED);#endif tag = CONSTANT_Double; break; case 'J': tag = CONSTANT_Long; break; default: fatalError(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 } if (fieldCount >= 2) { if (USESTATIC) { /* Otherwise, this is in permanent memory and won't move */ fieldTable = CurrentClass->fieldTable; } ASSERTING_NO_ALLOCATION /* Check to see if there are two fields with the same name/type */ FIELD firstField = &fieldTable->fields[0]; FIELD lastField = firstField + (fieldCount - 1); FIELD outer, inner; for (outer = firstField; outer < lastField; outer++) { for (inner = outer + 1; inner <= lastField; inner++) { if (outer->nameTypeKey.i == inner->nameTypeKey.i) { fatalError(KVM_MSG_DUPLICATE_FIELD_FOUND); } } } END_ASSERTING_NO_ALLOCATION }#if INCLUDEDEBUGCODE if (traceclassloadingverbose) fprintf(stdout, "Fields loaded ok\n");#endif /* INCLUDEDEBUGCODE */}/*========================================================================= * FUNCTION: loadExceptionHandlers() * TYPE: private class file load operation * OVERVIEW: Load the exception handling information associated * with each method in a class file. * INTERFACE: * parameters: constant pool, classfile pointer, method pointer * returns: number of characters read from the class file *=======================================================================*/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);#if USESTATIC handlerTable = (HANDLERTABLE)callocObject(tableSize, GCT_NOPOINTERS);#else handlerTable = (HANDLERTABLE)callocPermanentObject(tableSize);#endif 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) { fatalError(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);}/*========================================================================= * FUNCTION: loadStackMaps() * TYPE: private class file load operation * OVERVIEW: Load the stack maps associated * with each method in a class file. * INTERFACE: * parameters: classfile pointer, method pointer, constant pool * returns: number of characters read from the class file *=======================================================================*/static longloadStackMaps(FILEPOINTER_HANDLE ClassFileH, METHOD_HANDLE thisMethodH){ long bytesRead; INSTANCE_CLASS CurrentClass = unhand(thisMethodH)->ofClass; START_TEMPORARY_ROOTS unsigned short nStackMaps = loadShort(ClassFileH); DECLARE_TEMPORARY_ROOT(POINTERLIST, stackMaps, (POINTERLIST)callocObject(SIZEOF_POINTERLIST(2*nStackMaps), GCT_POINTERLIST)); METHOD thisMethod = unhand(thisMethodH); /* Very volatile */ unsigned tempSize = (thisMethod->u.java.maxStack + thisMethod->frameSize + 2); DECLARE_TEMPORARY_ROOT(unsigned short*, stackMap, (unsigned short *)mallocBytes(sizeof(unsigned short) * tempSize)); unsigned short stackMapIndex; stackMaps->length = nStackMaps; unhand(thisMethodH)->u.java.stackMaps.verifierMap = stackMaps; bytesRead = 2; for (stackMapIndex = 0; stackMapIndex < nStackMaps; stackMapIndex++) { unsigned short i, index; /* Any allocation happens at the end, so we have to dereference this * at least once through each loop. */ thisMethod = unhand(thisMethodH); /* Read in the offset */ stackMaps->data[stackMapIndex + nStackMaps].cell = loadShort(ClassFileH); bytesRead += 2; for (index = 0, i = 0 ; i < 2; i++) { unsigned short j; unsigned short size = loadShort(ClassFileH); unsigned short size_delta = 0; unsigned short size_index = index++; unsigned short maxSize = (i == 0 ? thisMethod->frameSize : thisMethod->u.java.maxStack); bytesRead += 2; for (j = 0; j < size; j++) { unsigned char stackType = loadByte(ClassFileH); bytesRead += 1; /* We are reading the j-th element of the stack map. * This corresponds to the value in the j + size_delta'th * local register or stack location */ if (j + size_delta >= maxSize) { fatalError(KVM_MSG_BAD_STACKMAP); } else if (stackType == ITEM_NewObject) { unsigned short instr = loadShort(ClassFileH); bytesRead += 2; if (instr >= thisMethod->u.java.codeLength) { fatalError(KVM_MSG_BAD_NEWOBJECT); } stackMap[index++] = ENCODE_NEWOBJECT(instr); } else if (stackType < ITEM_Object) { stackMap[index++] = stackType; if (stackType == ITEM_Long || stackType == ITEM_Double){ if (j + size_delta + 1 >= maxSize) { fatalError(KVM_MSG_BAD_STACKMAP); } stackMap[index++] = (stackType == ITEM_Long) ? ITEM_Long_2 : ITEM_Double_2; size_delta++; } } else if (stackType == ITEM_Object) { unsigned short classIndex = loadShort(ClassFileH); CONSTANTPOOL ConstantPool = CurrentClass->constPool; CLASS clazz; bytesRead += 2; verifyConstantPoolEntry(CurrentClass, classIndex, CONSTANT_Class); clazz = CP_ENTRY(classIndex).clazz; stackMap[index++] = clazz->key; } else { fatalError(KVM_MSG_BAD_STACKMAP); } } stackMap[size_index] = size + size_delta; } /* We suspect that there will be a lot of duplication, so it's worth * it to check and see if we already have this identical string */ for (i = 0; ; i++) { if (i == stackMapIndex) { /* We've reached the end, and no duplicate found */ char *temp = mallocBytes(index * sizeof(unsigned short)); memcpy(temp, stackMap, index * sizeof(short)); stackMaps->data[stackMapIndex].cellp = (cell*)temp; break; } else if (memcmp(stackMap, stackMaps->data[i].cellp, index * sizeof(short)) == 0) { /* We have found a duplicate */ stackMaps->data[stackMapIndex] = stackMaps->data[i]; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -