📄 jni.c
字号:
/* * jni.c * Java Native Interface. * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * Copyright (c) 2004-2005 * The Kaffe.org's developers. See ChangeLog for details. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "config-std.h"#include "config-mem.h"#include "jni.h"#include "jnirefs.h"#include "classMethod.h"#include "soft.h"#include "support.h"#include "itypes.h"#include "object.h"#include "errors.h"#include "native.h"#include "file.h"#include "baseClasses.h"#include "stringSupport.h"#include "readClass.h"#include "access.h"#include "lookup.h"#include "thread.h"#include "external.h"#include "gc.h"#include "locks.h"#include "md.h"#include "exception.h"#include "jvmpi_kaffe.h"#include "jni_i.h"#include "jni_funcs.h"#include "native-wrapper.h"#include "kaffe_jni.h"#include "stackTrace.h"extern struct JNINativeInterface Kaffe_JNINativeInterface;extern KaffeVM_Arguments Kaffe_JavaVMInitArgs;static JavaVM Kaffe_JavaVM;JavaVM*KaffeJNI_GetKaffeVM(void){ return &Kaffe_JavaVM;}static jint Kaffe_GetVersion(JNIEnv*);static jclass Kaffe_FindClass(JNIEnv*, const char*);static jint Kaffe_ThrowNew(JNIEnv*, jclass, const char*);static jint Kaffe_Throw(JNIEnv* env, jobject obj);/* * Everything from this point to Kaffe_GetVersion is not * exception-aware. Asynchronous exceptions should not be delivered * to them. * * Everything from Kaffe_GetVersion to Kaffe_GetJavaVM * should be bracketed with BEGIN and END _EXCEPTION_HANDLING. */void NONRETURNINGKaffeJNI_FatalError(JNIEnv* env UNUSED, const char* mess){ kprintf(stderr, "FATAL ERROR: %s\n", mess); abort();}static jintKaffe_GetVersion(JNIEnv* env UNUSED){ return Kaffe_JavaVMArgs.version;}/* * take a VM error and throw it as JNI error */static voidpostError(JNIEnv* env, errorInfo* info){ (*env)->Throw(env, error2Throwable(info));}static jclassKaffe_DefineClass(JNIEnv* env, const char *name UNUSED, jobject loader, const jbyte* buf, jsize len){ Hjava_lang_Class* cls, *dup_cls; classFile hand; errorInfo info; jobject loader_local; classEntry *centry; BEGIN_EXCEPTION_HANDLING(NULL); loader_local = unveil(loader); /* save clobbered reg. */ classFileInit(&hand, NULL, (unsigned char*)buf, (size_t)len, CP_BYTEARRAY); cls = newClass(); if (cls == NULL) { postOutOfMemory(&info); } else { cls = readClass(cls, &hand, loader_local, &info); } if (cls == NULL) { postError(env, &info); } /* * See if an entry for that name and class loader already exists * create one if not. */ centry = lookupClassEntry(cls->name, loader_local, &info); if (centry == 0) { throwError(&info); } if( classMappingLoad(centry, &dup_cls, &info) ) { if(dup_cls != NULL) { postExceptionMessage(&info, JAVA_LANG(ClassFormatError), "Duplicate name: %s", centry->name->data); throwError(&info); } /* * While it is not necessary that one be able to actually *use* * the returned class object at this point, it is mandatory * that the returned clazz object is a functional Class object. * * The following call will make sure that the returned class * object has its dispatch table set. The transition * PRELOADED->PREPARED in processClass sets class->head.dtable. * * Presumably, it shouldn't be necessary here, but is at the * moment - XXX */ else if( processClass(cls, CSTATE_PREPARED, &info) == false ) { throwError(&info); } } else { throwError(&info); } END_EXCEPTION_HANDLING(); return cls;}static jclassKaffe_FindClass(JNIEnv *env UNUSED, const char* name){ stackTraceInfo *trace; Utf8Const* utf8; Hjava_lang_ClassLoader *loader; Hjava_lang_Class *clazz; errorInfo einfo; int i; char* pathname; BEGIN_EXCEPTION_HANDLING(NULL); /* convert name to the form used inside the vm */ pathname = checkPtr(KMALLOC(strlen (name) + 1)); classname2pathname (name, pathname); /* create a new utf8 constant */ utf8 = utf8ConstFromString(pathname); /* free the internal form of name */ KFREE(pathname); /* bail out if we could not create the utf8 constant */ if (utf8 == NULL) { postOutOfMemory (&einfo); throwError (&einfo); } /* Quote from the JNI documentation: * * "In the Java 2 Platform, FindClass locates the class loader associated with the current native method. * If the native code belongs to a system class, no class loader will be involved. Otherwise, the proper * class loader will be invoked to load and link the named class. When FindClass is called through the * Invocation Interface, there is no current native method or its associated class loader. In that case, * the result of ClassLoader.getBaseClassLoader is used." * * So we ... */ /* ... get the stacktrace ... */ trace = (stackTraceInfo *)buildStackTrace (NULL); if (trace == NULL) { postOutOfMemory (&einfo); goto error_out; } /* ... find the first java method on the stack ... */ for (i=0; trace[i].meth != ENDOFSTACK; i++) { if ((trace[i].meth != NULL) && (trace[i].meth->class != NULL)) break; } /* ... determine the loader to be used ... */ if (trace[i].meth == ENDOFSTACK) { jvalue retval; do_execute_java_class_method (&retval, "java/lang/ClassLoader", NULL, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); loader = (Hjava_lang_ClassLoader *)retval.l; } else { loader = trace[i].meth->class->loader; } /* ... and finally call loadArray or loadClass. * * Why don't we delegate to Class.forName? Our implementation of * VMClassLoader.loadClass denies access to classes in internal * packages like kaffe.lang or gnu.classpath (for security reasons). * However, when FindClass is invoked from the native method of a * class defined by the bootstrap loader, that is not correct. * Therefore, we call loadClass / loadArray directly, which corresponds * to what getClass() does. */ if (utf8->data[0] == '[') { clazz = loadArray (utf8, loader, &einfo); } else { clazz = loadClass (utf8, loader, &einfo); } if (clazz == NULL) { goto error_out; } if (processClass (clazz, CSTATE_COMPLETE, &einfo) == false) { goto error_out; } ADD_REF(clazz); utf8ConstRelease(utf8); END_EXCEPTION_HANDLING(); return (clazz);error_out: utf8ConstRelease(utf8); throwError (&einfo); /* This is to make gcc silent on one warning */ return NULL;}static jclassKaffe_GetSuperClass(JNIEnv* env UNUSED, jclass cls){ jclass clz, cls_local; BEGIN_EXCEPTION_HANDLING(NULL); cls_local = unveil(cls); /* save clobbered reg. */ clz = ((Hjava_lang_Class*)cls_local)->superclass; END_EXCEPTION_HANDLING(); return (clz);}static jbooleanKaffe_IsAssignableFrom(JNIEnv* env UNUSED, jclass cls1, jclass cls2){ jboolean r; jclass cls1_local; jclass cls2_local; BEGIN_EXCEPTION_HANDLING(0); cls1_local = unveil(cls1); cls2_local = unveil(cls2); if (instanceof(cls2_local, cls1_local) != 0) { r = JNI_TRUE; } else { r = JNI_FALSE; } END_EXCEPTION_HANDLING(); return (r);}static jintKaffe_Throw(JNIEnv* env UNUSED, jobject obj){ jobject obj_local; BEGIN_EXCEPTION_HANDLING(0); if( obj ) { obj_local = unveil(obj); assert(((Hjava_lang_Object *)obj_local)->vtable); thread_data->exceptObj = (struct Hjava_lang_Throwable*)obj_local; } END_EXCEPTION_HANDLING(); return (0);}static jintKaffe_ThrowNew(JNIEnv* env UNUSED, jclass cls, const char* mess){ Hjava_lang_Object* eobj; jclass cls_local; BEGIN_EXCEPTION_HANDLING(0); cls_local = unveil(cls); eobj = execute_java_constructor(NULL, NULL, cls_local, "(Ljava/lang/String;)V", checkPtr(stringC2Java(mess))); thread_data->exceptObj = (struct Hjava_lang_Throwable*)eobj; END_EXCEPTION_HANDLING(); return (0);}static jobjectKaffe_ExceptionOccurred(JNIEnv* env UNUSED){ jobject obj; BEGIN_EXCEPTION_HANDLING(NULL); obj = thread_data->exceptObj; if (obj != NULL) ADD_REF(obj); END_EXCEPTION_HANDLING(); return (obj);}static jbooleanKaffe_ExceptionCheck(JNIEnv* env UNUSED){ jboolean result; jobject obj; BEGIN_EXCEPTION_HANDLING(0); obj = thread_data->exceptObj; result = (obj == NULL) ? JNI_FALSE : JNI_TRUE; END_EXCEPTION_HANDLING(); return (result);}static voidKaffe_ExceptionDescribe(JNIEnv* env UNUSED){ const char* cname; Hjava_lang_Class* class; Hjava_lang_Throwable *eobj; BEGIN_EXCEPTION_HANDLING_VOID(); eobj = thread_data->exceptObj; while (eobj != NULL) { /* Don't use the java stack printer because the exception * may arise in the IO codec. */ Hjava_lang_String *msg; char *realname; class = OBJECT_CLASS(&eobj->base); cname = CLASS_CNAME(class); realname = KMALLOC(strlen(cname)+1); pathname2classname(cname, realname); msg = unhand(eobj)->detailMessage; if (msg != NULL) { char *cmsg = checkPtr(stringJava2C(msg)); kprintf(stderr, "%s: %s\n", realname, cmsg); KFREE(cmsg); unhand(eobj)->detailMessage = NULL; } else { kprintf(stderr, "%s\n", realname); } KFREE(realname); printStackTrace (eobj, NULL, true); if (eobj->cause != eobj) { eobj = eobj->cause; kprintf(stderr, "caused by: "); } else eobj = NULL; } END_EXCEPTION_HANDLING();}static voidKaffe_ExceptionClear(JNIEnv* env UNUSED){ BEGIN_EXCEPTION_HANDLING_VOID(); thread_data->exceptObj = NULL; END_EXCEPTION_HANDLING();}static jobjectKaffe_AllocObject(JNIEnv* env UNUSED, jclass cls){ jobject obj; Hjava_lang_Class* clazz; jclass cls_local; BEGIN_EXCEPTION_HANDLING(NULL); cls_local = unveil(cls); clazz = (Hjava_lang_Class*)cls_local; if (CLASS_IS_INTERFACE(clazz) || CLASS_IS_ABSTRACT(clazz)) { throwException(InstantiationException(clazz->name->data)); } obj = newObject(clazz); ADD_REF(obj); END_EXCEPTION_HANDLING(); return (obj);}static jobjectKaffe_NewObjectV(JNIEnv* env UNUSED, jclass cls, jmethodID meth, va_list args){ Hjava_lang_Object* obj; Hjava_lang_Class* clazz; jvalue retval; Method* m = (Method*)meth; jclass cls_local; BEGIN_EXCEPTION_HANDLING(NULL); cls_local = unveil(cls); clazz = (Hjava_lang_Class*)cls_local; if (CLASS_IS_INTERFACE(clazz) || CLASS_IS_ABSTRACT(clazz) || !METHOD_IS_CONSTRUCTOR(m)) { throwException(InstantiationException(clazz->name->data)); } obj = newObject(clazz); KaffeVM_callMethodV(m, METHOD_NATIVECODE(m), obj, args, &retval); ADD_REF(obj); END_EXCEPTION_HANDLING(); return (obj);}static jobjectKaffe_NewObject(JNIEnv* env UNUSED, jclass cls, jmethodID meth, ...){ jobject obj; va_list args; jclass cls_local; BEGIN_EXCEPTION_HANDLING(NULL); cls_local = unveil(cls); va_start(args, meth); obj = Kaffe_NewObjectV(env, cls_local, meth, args); va_end(args); END_EXCEPTION_HANDLING(); return (obj);}static jobjectKaffe_NewObjectA(JNIEnv* env UNUSED, jclass cls, jmethodID meth, jvalue* args){ Hjava_lang_Object* obj; Hjava_lang_Class* clazz; jvalue retval; Method* m = (Method*)meth; jclass cls_local; BEGIN_EXCEPTION_HANDLING(NULL); cls_local = unveil(cls); clazz = (Hjava_lang_Class*)cls_local; if (CLASS_IS_INTERFACE(clazz) || CLASS_IS_ABSTRACT(clazz) || !METHOD_IS_CONSTRUCTOR(m)) { throwException(InstantiationException(clazz->name->data)); } obj = newObject(clazz); KaffeVM_callMethodA(m, METHOD_NATIVECODE(m), obj, args, &retval, 0); ADD_REF(obj); END_EXCEPTION_HANDLING(); return (obj);}static jclassKaffe_GetObjectClass(JNIEnv* env UNUSED, jobject obj){ jclass cls; jobject obj_local; BEGIN_EXCEPTION_HANDLING(NULL); obj_local = unveil(obj); cls = ((Hjava_lang_Object*)obj_local)->vtable->class; END_EXCEPTION_HANDLING(); return (cls);}static jbooleanKaffe_IsInstanceOf(JNIEnv* env UNUSED, jobject obj, jclass cls){ jboolean r; jobject obj_local; jclass cls_local; BEGIN_EXCEPTION_HANDLING(0); obj_local = unveil(obj); cls_local = unveil(cls); if (soft_instanceof((Hjava_lang_Class*)cls_local, (Hjava_lang_Object*)obj_local) != 0) { r = JNI_TRUE; } else { r = JNI_FALSE; } END_EXCEPTION_HANDLING(); return (r);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -