kvm 本地方法实现

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值