本文介绍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
#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."":()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,关于部分,之前的文章都有介绍,读者可自己查找…