kvm 本地方法实现

it2022-05-09  30

本文介绍kvm中本地方法的实现.

在j2me_cldc/kvm/VmCommon/h/native.h中有如下定义:

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[];

而在编译kvm后,会在j2me_cldc/tools/jcc生成nativeRelocationUninx.c,nativeFunctionTableUnix.c,ROMjavaUnix.c.其中,nativeFunctionTableUnix.c如下:

/* This is a generated file. Do not modify. * Generated on Tue Jul 23 21:47:34 EDT 2019 */ #include <global.h> #if !ROMIZING extern void Java_java_lang_Object_getClass(void); extern void Java_java_lang_Object_hashCode(void); extern void Java_java_lang_Object_notify(void); extern void Java_java_lang_Object_notifyAll(void); extern void Java_java_lang_Object_wait(void); extern void Java_java_lang_Throwable_printStackTrace0(void); extern void Java_java_lang_System_currentTimeMillis(void); extern void Java_java_lang_System_arraycopy(void); extern void Java_java_lang_System_identityHashCode(void); extern void Java_java_lang_System_getProperty0(void); extern void Java_com_sun_cldc_io_ResourceInputStream_open(void); extern void Java_com_sun_cldc_io_ResourceInputStream_close(void); extern void Java_com_sun_cldc_io_ResourceInputStream_size(void); extern void Java_com_sun_cldc_io_ResourceInputStream_read(void); extern void Java_com_sun_cldc_io_ResourceInputStream_readBytes(void); extern void Java_java_lang_Double_doubleToLongBits(void); extern void Java_java_lang_Double_longBitsToDouble(void); extern void Java_java_lang_Float_floatToIntBits(void); extern void Java_java_lang_Float_intBitsToFloat(void); extern void Java_java_lang_Class_forName(void); extern void Java_java_lang_Class_newInstance(void); extern void Java_java_lang_Class_isInstance(void); extern void Java_java_lang_Class_isAssignableFrom(void); extern void Java_java_lang_Class_isInterface(void); extern void Java_java_lang_Class_isArray(void); extern void Java_java_lang_Class_getName(void); extern void Java_java_lang_StringBuffer_append__Ljava_lang_String_2(void); extern void Java_java_lang_StringBuffer_append__I(void); extern void Java_java_lang_StringBuffer_toString(void); extern void Java_java_lang_Thread_currentThread(void); extern void Java_java_lang_Thread_yield(void); extern void Java_java_lang_Thread_sleep(void); extern void Java_java_lang_Thread_start(void); extern void Java_java_lang_Thread_isAlive(void); extern void Java_java_lang_Thread_activeCount(void); extern void Java_java_lang_Thread_setPriority0(void); extern void Java_java_lang_Thread_interrupt0(void); extern void Java_com_sun_cldc_io_Waiter_waitForIO(void); extern void Java_java_lang_Runtime_exitInternal(void); extern void Java_java_lang_Runtime_freeMemory(void); extern void Java_java_lang_Runtime_totalMemory(void); extern void Java_java_lang_Runtime_gc(void); extern void Java_java_lang_Math_sin(void); extern void Java_java_lang_Math_cos(void); extern void Java_java_lang_Math_tan(void); extern void Java_java_lang_Math_sqrt(void); extern void Java_java_lang_Math_ceil(void); extern void Java_java_lang_Math_floor(void); extern void Java_com_sun_cldc_io_ConsoleOutputStream_write(void); extern void Java_java_lang_String_charAt(void); extern void Java_java_lang_String_equals(void); extern void Java_java_lang_String_indexOf__I(void); extern void Java_java_lang_String_indexOf__II(void); extern void Java_java_lang_String_intern(void); extern void Java_java_lang_ref_WeakReference_initializeWeakReference(void); const NativeImplementationType java_lang_Object_natives[] = { { "getClass", NULL, Java_java_lang_Object_getClass}, { "hashCode", NULL, Java_java_lang_Object_hashCode}, { "notify", NULL, Java_java_lang_Object_notify}, { "notifyAll", NULL, Java_java_lang_Object_notifyAll}, { "wait", NULL, Java_java_lang_Object_wait}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Throwable_natives[] = { { "printStackTrace0", NULL, Java_java_lang_Throwable_printStackTrace0}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_System_natives[] = { { "currentTimeMillis", NULL, Java_java_lang_System_currentTimeMillis}, { "arraycopy", NULL, Java_java_lang_System_arraycopy}, { "identityHashCode", NULL, Java_java_lang_System_identityHashCode}, { "getProperty0", NULL, Java_java_lang_System_getProperty0}, NATIVE_END_OF_LIST }; const NativeImplementationType com_sun_cldc_io_ResourceInputStream_natives[] = { { "open", NULL, Java_com_sun_cldc_io_ResourceInputStream_open}, { "close", NULL, Java_com_sun_cldc_io_ResourceInputStream_close}, { "size", NULL, Java_com_sun_cldc_io_ResourceInputStream_size}, { "read", NULL, Java_com_sun_cldc_io_ResourceInputStream_read}, { "readBytes", NULL, Java_com_sun_cldc_io_ResourceInputStream_readBytes}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Double_natives[] = { { "doubleToLongBits", NULL, Java_java_lang_Double_doubleToLongBits}, { "longBitsToDouble", NULL, Java_java_lang_Double_longBitsToDouble}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Float_natives[] = { { "floatToIntBits", NULL, Java_java_lang_Float_floatToIntBits}, { "intBitsToFloat", NULL, Java_java_lang_Float_intBitsToFloat}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Class_natives[] = { { "forName", NULL, Java_java_lang_Class_forName}, { "newInstance", NULL, Java_java_lang_Class_newInstance}, { "isInstance", NULL, Java_java_lang_Class_isInstance}, { "isAssignableFrom", NULL, Java_java_lang_Class_isAssignableFrom}, { "isInterface", NULL, Java_java_lang_Class_isInterface}, { "isArray", NULL, Java_java_lang_Class_isArray}, { "getName", NULL, Java_java_lang_Class_getName}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_StringBuffer_natives[] = { { "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;", Java_java_lang_StringBuffer_append__Ljava_lang_String_2}, { "append", "(I)Ljava/lang/StringBuffer;", Java_java_lang_StringBuffer_append__I}, { "toString", NULL, Java_java_lang_StringBuffer_toString}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Thread_natives[] = { { "currentThread", NULL, Java_java_lang_Thread_currentThread}, { "yield", NULL, Java_java_lang_Thread_yield}, { "sleep", NULL, Java_java_lang_Thread_sleep}, { "start", NULL, Java_java_lang_Thread_start}, { "isAlive", NULL, Java_java_lang_Thread_isAlive}, { "activeCount", NULL, Java_java_lang_Thread_activeCount}, { "setPriority0", NULL, Java_java_lang_Thread_setPriority0}, { "interrupt0", NULL, Java_java_lang_Thread_interrupt0}, NATIVE_END_OF_LIST }; const NativeImplementationType com_sun_cldc_io_Waiter_natives[] = { { "waitForIO", NULL, Java_com_sun_cldc_io_Waiter_waitForIO}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Runtime_natives[] = { { "exitInternal", NULL, Java_java_lang_Runtime_exitInternal}, { "freeMemory", NULL, Java_java_lang_Runtime_freeMemory}, { "totalMemory", NULL, Java_java_lang_Runtime_totalMemory}, { "gc", NULL, Java_java_lang_Runtime_gc}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_Math_natives[] = { { "sin", NULL, Java_java_lang_Math_sin}, { "cos", NULL, Java_java_lang_Math_cos}, { "tan", NULL, Java_java_lang_Math_tan}, { "sqrt", NULL, Java_java_lang_Math_sqrt}, { "ceil", NULL, Java_java_lang_Math_ceil}, { "floor", NULL, Java_java_lang_Math_floor}, NATIVE_END_OF_LIST }; const NativeImplementationType com_sun_cldc_io_ConsoleOutputStream_natives[] = { { "write", NULL, Java_com_sun_cldc_io_ConsoleOutputStream_write}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_String_natives[] = { { "charAt", NULL, Java_java_lang_String_charAt}, { "equals", NULL, Java_java_lang_String_equals}, { "indexOf", "(I)I", Java_java_lang_String_indexOf__I}, { "indexOf", "(II)I", Java_java_lang_String_indexOf__II}, { "intern", NULL, Java_java_lang_String_intern}, NATIVE_END_OF_LIST }; const NativeImplementationType java_lang_ref_WeakReference_natives[] = { { "initializeWeakReference", NULL, Java_java_lang_ref_WeakReference_initializeWeakReference}, NATIVE_END_OF_LIST }; const ClassNativeImplementationType nativeImplementations[] = { { "java/lang", "Object", java_lang_Object_natives }, { "java/lang", "Throwable", java_lang_Throwable_natives }, { "java/lang", "System", java_lang_System_natives }, { "com/sun/cldc/io", "ResourceInputStream", com_sun_cldc_io_ResourceInputStream_natives }, { "java/lang", "Double", java_lang_Double_natives }, { "java/lang", "Float", java_lang_Float_natives }, { "java/lang", "Class", java_lang_Class_natives }, { "java/lang", "StringBuffer", java_lang_StringBuffer_natives }, { "java/lang", "Thread", java_lang_Thread_natives }, { "com/sun/cldc/io", "Waiter", com_sun_cldc_io_Waiter_natives }, { "java/lang", "Runtime", java_lang_Runtime_natives }, { "java/lang", "Math", java_lang_Math_natives }, { "com/sun/cldc/io", "ConsoleOutputStream", com_sun_cldc_io_ConsoleOutputStream_natives }, { "java/lang", "String", java_lang_String_natives }, { "java/lang/ref", "WeakReference", java_lang_ref_WeakReference_natives }, NATIVE_END_OF_LIST }; #endif

此处就以Thread.java为例,其有如下本地方法:

public static native Thread currentThread(); public static native void yield(); public static native void sleep(long millis) throws InterruptedException; public synchronized native void start(); public final native boolean isAlive(); public static native int activeCount(); private native void setPriority0(int newPriority); private native void interrupt0();

而kvm在加载Thread.java时解析方法时,会执行如下代码:

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; } } } }

其最终会执行getNativeFunction方法,代码如下:

NativeFunctionPtr getNativeFunction(INSTANCE_CLASS clazz, const char* methodName, const char *methodSignature) { #if !ROMIZING const 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); } // 遍历nativeImplementations,找到符合要求的ClassNativeImplementationType for (cptr = nativeImplementations; cptr->baseName != NULL ; cptr++) { if ( (xstrcmp(cptr->packageName, packageName) == 0) && (xstrcmp(cptr->baseName, baseName) == 0)) { break; } } // 遍历该ClassNativeImplementationType的本地函数表,找到对应函数指针 for (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; }

然后在调用该本地方法时,有如下处理:

/* Check if the method is a native method */ if (thisMethod->accessFlags & ACC_NATIVE) { ip += invokerSize; VMSAVE invokeNativeFunction(thisMethod); VMRESTORE TRACE_METHOD_EXIT(thisMethod); goto reschedulePoint; }

其最终会调用invokeNativeFunction方法.注意,此时调用本地方法时的参数都已存放在栈中.

void invokeNativeFunction(METHOD thisMethod) { #if INCLUDEDEBUGCODE int saved_TemporaryRootsLength; #endif NativeFunctionPtr native = thisMethod->u.native.code; // 1. 如果本地方法不存在,则抛出异常 if (native == NULL) { /* Native function not found; throw error */ /* The GC may get confused by the arguments on the stack */ setSP(getSP() - thisMethod->argCount); START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(char*, className, getClassName((CLASS)(thisMethod->ofClass))); sprintf(str_buffer, KVM_MSG_NATIVE_METHOD_NOT_FOUND_2STRPARAMS, className, methodName(thisMethod)); END_TEMPORARY_ROOTS fatalError(str_buffer); } #if INCLUDEDEBUGCODE if (tracemethodcalls || tracemethodcallsverbose) { frameTracing(thisMethod, "=>", +1); } saved_TemporaryRootsLength = TemporaryRootsLength; #endif #if USE_KNI // 2.计算nativeLp,在本地方法中访问局部变量时使用 if ((thisMethod->accessFlags & ACC_STATIC) && CurrentThread) { CurrentThread->nativeLp = getSP() - (thisMethod->argCount); } else { CurrentThread->nativeLp = getSP() - (thisMethod->argCount-1); } #endif /* USE_KNI */ /* 3. 调用本地方法 */ CurrentNativeMethod = thisMethod; native(); #if USE_KNI // 4. 调用后处理 if (CurrentThread) { CurrentThread->nativeLp = NULL; /* Check for pending exceptions (KNI_Throw) */ if (CurrentThread->pendingException) { const char* pending = CurrentThread->pendingException; CurrentThread->pendingException = NULL; if (CurrentThread->exceptionMessage) { const char* message = CurrentThread->exceptionMessage; CurrentThread->exceptionMessage = NULL; raiseExceptionWithMessage(pending, message); } else { raiseException(pending); } } } #endif /* USE_KNI */ CurrentNativeMethod = NULL; #if INCLUDEDEBUGCODE if (TemporaryRootsLength != saved_TemporaryRootsLength) { START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(char*, className, getClassName((CLASS)(thisMethod->ofClass))); sprintf(str_buffer, KVM_MSG_NATIVE_METHOD_BAD_USE_OF_TEMPORARY_ROOTS, className, methodName(thisMethod)); END_TEMPORARY_ROOTS fatalError(str_buffer); } if (tracemethodcalls || tracemethodcallsverbose) { frameTracing(thisMethod, "<=", +1); } #endif }

此处以一个例子进行介绍:

public class KVMTest{ public static void main(String[] args) throws InterruptedException{ System.out.println(args[0]); new Thread().sleep(1); } }

查看字节码,其内容如下:

public static void main(java.lang.String[]) throws java.lang.InterruptedException; descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: iconst_0 5: aaload 6: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 9: new #4 // class java/lang/Thread 12: dup 13: invokespecial #5 // Method java/lang/Thread."<init>":()V 16: pop 17: lconst_1 18: invokestatic #6 // Method java/lang/Thread.sleep:(J)V 21: return LineNumberTable: line 5: 0 line 7: 9 line 8: 21 Exceptions: throws java.lang.InterruptedException }

可以看到在执行执行invokestatic时,其操作栈顶是1(也就是sleep的参数).然后再执行invokestatic #6,经过上文介绍的invokeNativeFunction处理,最终会执行Java_java_lang_Thread_sleep()方法.代码如下:

void Java_java_lang_Thread_sleep(void) { long64 period; THREAD thisThread = CurrentThread; // 获得执行线程 popLong(period); // 获得要等待的时间 if (ll_zero_lt(period)) { // 如果period < 0 ,则抛出IllegalArgumentException raiseException(IllegalArgumentException); } else if (thisThread->isPendingInterrupt) { // 如果线程正在Interrupt,则调用handlePendingInterrupt handlePendingInterrupt(); } else if (ll_zero_gt(period)) { // 如果>=0。则将线程挂起,同时加入timer队列,等时间到时,则调用resumeThread方法进行恢复 suspendThread(); // 将线程暂停。此处后面会介绍 registerAlarm(thisThread, period, resumeThread); // 这个方法之前的文章有介绍 } else if (ll_zero_eq(period)) { signalTimeToReschedule(); // 此处为宏,宏展开为 Timeslice = 0. 也就是要立即进行线程切换 } }

此处的重要是popLong(period),宏展开为:

getSP()--; *(long64*)(&_lval) = *(long64*)(getSP()); // 进行复制 getSP()--;

此处也就是最终的弹栈操作.

ok,关于部分,之前的文章都有介绍,读者可自己查找…


最新回复(0)