您现在的位置是:主页 > news > 西安建设和住房保障局网站/深圳网站seo优化

西安建设和住房保障局网站/深圳网站seo优化

admin2025/5/5 2:58:05news

简介西安建设和住房保障局网站,深圳网站seo优化,网站seo解决方案,怎么做网站内的搜索本文介绍kvm加载方法的部分.在jvm规范中,),包括实例初始化方法和类初始化方法(2.9)在内,都由method_info结构所定义。在一个Class文件中,不会有两个方法同时具有相同的方法名和描述符( 4.3.3&am…

西安建设和住房保障局网站,深圳网站seo优化,网站seo解决方案,怎么做网站内的搜索本文介绍kvm加载方法的部分.在jvm规范中,),包括实例初始化方法和类初始化方法(2.9)在内,都由method_info结构所定义。在一个Class文件中,不会有两个方法同时具有相同的方法名和描述符( 4.3.3&am…

本文介绍kvm加载方法的部分.在jvm规范中,),包括实例初始化方法和类初始化方法(§2.9)在内,都由method_info结构所定义。在一个Class文件中,不会有两个方法同时具有相同的方法名和描述符(§ 4.3.3)。method_info结构格式如下:

method_info {  
u2 access_flags;  
u2 name_index;  
u2 descriptor_index;  
u2 attributes_count;  
attribute_info attributes[attributes_count]; 
} 

method_info结构各项的说明如下:

  • access_flags

    在KVM中识别的值为:

    • ACC_PUBLIC
    • ACC_PRIVATE
    • ACC_PROTECTED
    • ACC_STATIC
    • ACC_FINAL
    • ACC_SYNCHRONIZED
    • ACC_NATIVE
    • ACC_ABSTRACT
    • ACC_STRICT

    一个方法只能设置ACC_PRIVATE,ACC_PROTECTED和ACC_PUBLI三个标志中的一个标志;如果一个方法被设置ACC_ABSTRACT标志,则这个方法不能被设置ACC_FINAL,ACC_NATIVE, ACC_PRIVATE, ACC_STATIC, ACC_STRICT和ACC_SYNCHRONIZED标志。

    所有的接口方法必须被设置ACC_ABSTRACT和ACC_PUBLIC标志;但是不能再设置其它的标志了(JLS §9.4)。

    实例初始化方法只能设置ACC_PRIVATE,ACC_PROTECTED和ACC_PUBLIC中的一个标志;但是不能再设置其它的标志了(JLS §9.4)。

    类初始化方法(§2.9)由Java虚拟机隐式自动调用,它的access_flags项的值除了ACC_STRICT标志,其它的标志都将被忽略。

  • name_index

    name_index项的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info(§4.4.7)结构,它要么表示初始化方法的名字(<init>或<clinit>),要么表示一个方法的有效的非全限定名(§4.2.2)

  • descriptor_index

    descriptor_index项的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info(§4.4.7)结构,表示一个有效的方法的描述符(§4.3.3)

  • attributes_count

    attributes_count的项的值表示这个方法的附加属性(§4.7)的数量。

  • attributes[]

attributes表的每一个成员的值必须是attribute(§4.7)结构,一个方法可以有任意个与之相关的属性。

在kvm中识别的属性为Code, Exceptions.

其中code的格式如下:

Code_attribute {  
u2 attribute_name_index;  
u4 attribute_length;    
u2 max_stack;  
u2 max_locals;  
u4 code_length;  
u1 code[code_length];  
u2 exception_table_length;    
{ u2 start_pc;   u2 end_pc;   u2 handler_pc;   u2 catch_type;  } exception_table[exception_table_length];  u2 attributes_count;  attribute_info attributes[attributes_count]; } 

Exceptions属性是一个变长属性,它位于method_info(§4.6)结构的属性表中。Exceptions属性指出了一个方法需要检查的可能抛出的异常。一个method_info结构中最多
只能有一个Exceptions属性。其格式如下:

Exceptions_attribute {  
u2 attribute_name_index;  
u4 attribute_length;  
u2 number_of_exceptions;  
u2 exception_index_table[number_of_exceptions]; 
} 

加载方法

这部分的代码是在j2me_cldc/kvm/VmCommon/src/loader.c 中实现的.代码如下:


static void
loadMethods(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass,POINTERLIST_HANDLE StringPoolH)
{// 1. 获得方法的数量unsigned short methodCount = loadShort(ClassFileH);if (methodCount == 0) {return;}// 2. 计算并分配大小START_TEMPORARY_ROOTSint tableSize = SIZEOF_METHODTABLE(methodCount);unsigned int index;
#if USESTATICDECLARE_TEMPORARY_ROOT(METHODTABLE, methodTable,(METHODTABLE)callocObject(tableSize, GCT_METHODTABLE));
#elseMETHODTABLE methodTable = (METHODTABLE)callocPermanentObject(tableSize);
#endifmethodTable->length = methodCount;CurrentClass->methodTable = methodTable;#if INCLUDEDEBUGCODEif (traceclassloadingverbose) {fprintf(stdout, "Loading methods\n");}
#endif /* INCLUDEDEBUGCODE */// 3. 加载每一个方法for (index = 0; index < methodCount; index++) {
#if USESTATICSTART_TEMPORARY_ROOTSDECLARE_TEMPORARY_METHOD_ROOT(thisMethod, methodTable, index);loadOneMethod(ClassFileH, CurrentClass, &thisMethod, StringPoolH);END_TEMPORARY_ROOTS
#elseMETHOD thisMethod = &methodTable->methods[index];loadOneMethod(ClassFileH, CurrentClass, &thisMethod, StringPoolH);
#endif}END_TEMPORARY_ROOTS// 4. 检查是否有重复的方法if (methodCount >= 2) {/* Check to see if there are two methods with the same name/type */METHODTABLE methodTable = CurrentClass->methodTable;METHOD firstMethod = &methodTable->methods[0];METHOD lastMethod = firstMethod + (methodCount - 1);METHOD outer, inner;for (outer = firstMethod; outer < lastMethod; outer++) {for (inner = outer + 1; inner <= lastMethod; inner++) {if (outer->nameTypeKey.i == inner->nameTypeKey.i) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_DUPLICATE_METHOD_FOUND);}}}}#if INCLUDEDEBUGCODEif (traceclassloadingverbose) {fprintf(stdout, "Methods loaded ok\n");}
#endif /* INCLUDEDEBUGCODE */}

其步骤如下:

  1. 获得方法的数量

  2. 计算并分配大小.计算的公式为:

    (sizeof(struct methodTableStruct) + 3) >> 2 +  (n - 1) * (sizeof(struct methodStruct) + 3) >> 2
    

    methodTableStruct的格式如下:

    struct methodTableStruct { long length; // 该方法表的数量struct methodStruct methods[1];
    };
    

    methodStruct的定义如下:

        struct methodStruct {NameTypeKey   nameTypeKey;union { struct {BYTE* code; // 字节码指针HANDLERTABLE handlers;union {STACKMAP pointerMap;POINTERLIST verifierMap;} stackMaps; // stackMapsunsigned short codeLength; // 字节码的长度unsigned short maxStack; } java; // 对应java方法struct { void (*code)(void);void *info;} native; // 对应本地方法} u;long  accessFlags;        /* 该方法的访问标记 */INSTANCE_CLASS ofClass;   /* 该方法所对应的类 */unsigned short frameSize; /* 帧的大小 arguments+local vars */unsigned short argCount;  /* 参数的数量 */};
    
  3. 加载每一个方法

  4. 检查是否有重复的方法

其中,第3步所对应的方法为: loadOneMethod。其代码如下:

static void
loadOneMethod(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass,METHOD_HANDLE thisMethodH, POINTERLIST_HANDLE StringPoolH)
{METHOD thisMethod;// 1. 加载访问标记, nameIndex, typeIndexunsigned short accessFlags =loadShort(ClassFileH) & RECOGNIZED_METHOD_FLAGS;unsigned short nameIndex   = loadShort(ClassFileH);unsigned short typeIndex   = loadShort(ClassFileH);START_TEMPORARY_ROOTS// 2. 获得方法名,方法签名DECLARE_TEMPORARY_ROOT(const char *, methodName,getUTF8String(StringPoolH, nameIndex));DECLARE_TEMPORARY_ROOT(const char *, signature,getUTF8String(StringPoolH, typeIndex));NameTypeKey result;// 3. 校验访问标记if (strcmp(methodName, "<clinit>") == 0) {accessFlags = ACC_STATIC;} else {verifyMethodFlags(accessFlags,CurrentClass->clazz.accessFlags,methodName);}verifyName(methodName, LegalMethod);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// 4. 计算参数的数量thisMethod = unhand(thisMethodH);thisMethod->nameTypeKey = result;thisMethod->argCount = verifyMethodType(methodName, signature);/* 如果该方法不是静态的,则还需添加一个,对应this*/if (!(accessFlags & ACC_STATIC)) {thisMethod->argCount++;}// 如果参数数量大于255,则抛出异常 if (thisMethod->argCount > 255) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_TOO_MANY_METHOD_ARGUMENTS);}#if INCLUDEDEBUGCODEif (traceclassloadingverbose) {fprintf(stdout, "Method '%s' loaded\n", methodName);}
#endif /* INCLUDEDEBUGCODE *//* Check if the field is double length, or is a pointer type.  If so* set the appropriate bit in the word */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// 5. 加载方法的属性loadMethodAttributes(ClassFileH, thisMethodH, StringPoolH);/* Garbage collection may have happened */thisMethod = unhand(thisMethodH);if (!(thisMethod->accessFlags & (ACC_NATIVE | ACC_ABSTRACT))) {if ( thisMethod->frameSize < thisMethod->argCount) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_BAD_FRAME_SIZE);}}// 6. 处理本地方法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;}}}}END_TEMPORARY_ROOTS}

加载方法属性

对应的方法为:loadMethodAttributes.代码如下:

static void
loadMethodAttributes(FILEPOINTER_HANDLE ClassFileH,METHOD_HANDLE thisMethodH,POINTERLIST_HANDLE StringPoolH)
{// 1. 获得方法属性的数量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 *//* 2. 遍历属性 */for (attrIndex = 0; attrIndex < attrCount; attrIndex++) {unsigned short attrNameIndex = loadShort(ClassFileH);unsigned int   attrLength    = loadCell(ClassFileH);char*          attrName      = getUTF8String(StringPoolH, attrNameIndex);/*  2.1 读取Code属性 */if (strcmp(attrName, "Code") == 0) {unsigned int actualLength;if (!needCode) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_DUPLICATE_CODE_ATTRIBUTE);}// 加载code 属性actualLength = loadCodeAttribute(ClassFileH, thisMethodH, StringPoolH);if (actualLength != attrLength) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_BAD_CODE_ATTRIBUTE_LENGTH);}needCode = FALSE;} else if (!strcmp(attrName, "Exceptions")) {// 2.2 读取Exceptions 属性/* Do minimal checking of this attribute. */unsigned int exceptionCount;unsigned int i;if (!needExceptionTable) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_DUPLICATE_EXCEPTION_TABLE);}needExceptionTable = FALSE;exceptionCount = loadShort(ClassFileH);if (2 * exceptionCount + 2 != attrLength) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_BAD_EXCEPTION_ATTRIBUTE);}for (i = 0; i < exceptionCount; i++) {unsigned short exception = loadShort(ClassFileH);if (exception == 0) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_BAD_EXCEPTION_ATTRIBUTE);} else {verifyConstantPoolEntry(unhand(thisMethodH)->ofClass,exception, CONSTANT_Class);}}} else {/* 2.3 跳过其他属性 */skipBytes(ClassFileH, attrLength);}}// 3. 如果该方法不是本地方法,抽象方法,如果没有定义Code属性,则抛出异常if (needCode) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_MISSING_CODE_ATTRIBUTE);}
}

这里比较关键的是loadCodeAttribute,代码如下:

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);thisMethod->u.java.maxStack = loadShort(ClassFileH); /* 读取 maxstack */thisMethod->frameSize       = loadShort(ClassFileH); /* 读者栈帧大小 */codeLength                  = loadCell(ClassFileH);  /* 读取code的length *//* 在kvm中,code不能大于32KB */if (codeLength >= 0x7FFF) {raiseExceptionWithMessage(OutOfMemoryError,KVM_MSG_METHOD_LONGER_THAN_32KB);}/* 在kvm中,不能有超过512个局部变量*/if (thisMethod->u.java.maxStack + thisMethod->frameSize >MAXIMUM_STACK_AND_LOCALS) {raiseExceptionWithMessage(OutOfMemoryError,KVM_MSG_TOO_MANY_LOCALS_AND_STACK);}/* 在持久代中分配大小 */if (USESTATIC && !ENABLEFASTBYTECODES) {code = (BYTE *)mallocBytes(codeLength);} else {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 */// 读取StackMapif (!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;
}

对于复制字节码,其最终调用的方法为loadBytesInternal:

static int
loadBytesInternal(FILEPOINTER_HANDLE ClassFileH, char *buffer, int pos,int length, bool_t checkEOF)
{int n;FILEPOINTER ClassFile = unhand(ClassFileH);if (!ClassFile->isJarFile) {// 对应class文件FILE *file = ((struct stdioPointerStruct*)ClassFile)->file;/** If 'pos' is -1 then just read sequentially.  Used internally by* loadBytes() which is called from classloader.*/if (pos != -1)fseek(file, pos, SEEK_SET);n = fread(buffer, 1, length, file);  // 使用fread函数读取if (n != length) {if (checkEOF) {raiseExceptionWithMessage(ClassFormatError,KVM_MSG_CLASSFILE_SIZE_DOES_NOT_MATCH);} else {if (n > 0)return (n);elsereturn (-1);        /* eof */}} else {return (n);}} else {// 对应jar包中的情况struct jarPointerStruct *ds = (struct jarPointerStruct *)ClassFile;int avail;if (pos == -1)pos = ds->dataIndex;avail = ds->dataLen - pos;if (avail < length && checkEOF) /* inconceivable? */{raiseExceptionWithMessage(ClassFormatError,KVM_MSG_CLASSFILE_SIZE_DOES_NOT_MATCH);} else {if (avail) {int readLength = (avail > length) ? length : avail;memcpy(buffer, &ds->data[pos], readLength); // 使用memcpy 读取ds->dataIndex = pos + readLength;return (readLength);} else {return (-1);}}}return (0);
}

加载本地方法

这部分涉及的数据结构如下:

typedef void NativeFunctionType(void); // 本地方法的指针
typedef NativeFunctionType *NativeFunctionPtr;typedef struct {const char *const name; // 方法名称const char *const signature; // 签名const NativeFunctionPtr implementation; // 本地方法指针
} NativeImplementationType;typedef struct {const char *const packageName; // 包名const char *const baseName;  // 类名const NativeImplementationType *const implementation; 
} ClassNativeImplementationType;extern const ClassNativeImplementationType nativeImplementations[]; // 本地函数表

加载本地方法的实现为:

NativeFunctionPtr
getNativeFunction(INSTANCE_CLASS clazz, const char* methodName, const char *methodSignature)
{
#if !ROMIZINGconst ClassNativeImplementationType *cptr;const NativeImplementationType *mptr;UString UBaseName    = clazz->clazz.baseName;UString UPackageName = clazz->clazz.packageName;char* baseName;char* packageName;// 获得包名if (UPackageName == NULL) {packageName = "";} else {packageName = UStringInfo(UPackageName);}// 获得类名if (UBaseName == NULL) {baseName = "";} else {baseName = UStringInfo(UBaseName);}// 遍历本地方法表for (cptr = nativeImplementations; cptr->baseName != NULL ; cptr++) {                 if (   (xstrcmp(cptr->packageName, packageName) == 0) && (xstrcmp(cptr->baseName, baseName) == 0)) { break;}}//  遍历实现,如果找到方法名,方法签名都相同的就返回,否则返回nullfor (mptr = cptr->implementation; mptr != NULL ; mptr++) {const char *name = mptr->name;if (name == NULL) {return NULL;}if (strcmp(name, methodName) == 0) {const char *signature = mptr->signature;/* The signature is NULL for non-overloaded native methods. */if (signature == NULL || (xstrcmp(signature, methodSignature) == 0)){return mptr->implementation;}}}
#endif /* !ROMIZING */return NULL;
}

至此, loadRawClass 方法 就介绍完毕了.