// jni.cc - JNI implementation, including the jump table. /* Copyright (C) 1998, 1999, 2000 Red Hat, Inc. This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ // Note: currently we take the approach of not checking most // arguments. Instead we could do more checking conditionally (e.g., // if DEBUG is defined). That might be beneficial in some cases, // though to me it seems that one could just as easily use the // debugger. #include #include // Must define this before jni.h. #define GCJ_JV_JNIENV_FRIEND \ friend jthrowable &get_throwable (JNIEnv *) #include #include #include #include #include #include #include #include #include #include #include #include #define ClassClass _CL_Q34java4lang5Class extern java::lang::Class ClassClass; #define ObjectClass _CL_Q34java4lang6Object extern java::lang::Class ObjectClass; // This enum is used to select different template instantiations in // the invocation code. enum invocation_type { normal, nonvirtual, static_type, constructor }; // Tell the GC that a certain pointer is live. static void mark_for_gc (void *) { // FIXME. } // Unmark a pointer. static void unmark_for_gc (void *) { // FIXME. } // Return throwable in env. jthrowable & get_throwable (JNIEnv *env) { return env->ex; } static jint _Jv_JNI_GetVersion (JNIEnv *) { return JNI_VERSION_1_2; } static jclass _Jv_JNI_GetSuperclass (JNIEnv *, jclass clazz) { return clazz->getSuperclass (); } static jboolean IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2) { return clazz1->isAssignableFrom (clazz2); } static jint _Jv_JNI_Throw (JNIEnv *env, jthrowable obj) { get_throwable (env) = obj; return 0; } static jint _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) { using namespace java::lang::reflect; JArray *argtypes = (JArray *) JvNewObjectArray (1, &ClassClass, NULL); jclass *elts = elements (argtypes); elts[0] = &StringClass; // FIXME: exception processing. Constructor *cons = clazz->getConstructor (argtypes); jobjectArray values = JvNewObjectArray (1, &StringClass, NULL); jobject *velts = elements (values); velts[0] = JvNewStringUTF (message); // FIXME: exception processing. jobject obj = cons->newInstance (values); get_throwable (env) = reinterpret_cast (obj); return 0; } static jthrowable _Jv_JNI_ExceptionOccurred (JNIEnv *env) { return get_throwable (env); } static void _Jv_JNI_ExceptionDescribe (JNIEnv *env) { if (get_throwable (env) != NULL) get_throwable (env)->printStackTrace(); } static void _Jv_JNI_ExceptionClear (JNIEnv *env) { get_throwable (env) = NULL; } static void _Jv_JNI_FatalError (JNIEnv *, const char *message) { JvFail (message); } static jboolean _Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2) { return obj1 == obj2; } static jobject _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) { jobject obj = NULL; using namespace java::lang::reflect; if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers())) get_throwable (env) = new java::lang::InstantiationException (); else { // FIXME: exception processing. // FIXME: will this work for String? obj = JvAllocObject (clazz); } return obj; } static jclass _Jv_JNI_GetObjectClass (JNIEnv *, jobject obj) { return obj->getClass(); } static jboolean _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz) { return clazz->isInstance(obj); } // // This section concerns method invocation. // template static jmethodID _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz, const char *name, const char *sig) { // FIXME: exception processing. _Jv_InitClass (clazz); _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1); _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) sig, -1); JvAssert (! clazz->isPrimitive()); using namespace java::lang::reflect; while (clazz != NULL) { jint count = JvNumMethods (clazz); jmethodID meth = JvGetFirstMethod (clazz); for (jint i = 0; i < count; ++i) { if (((is_static && Modifier::isStatic (meth->accflags)) || (! is_static && ! Modifier::isStatic (meth->accflags))) && _Jv_equalUtf8Consts (meth->name, name_u) && _Jv_equalUtf8Consts (meth->signature, sig_u)) return meth; meth = meth->getNextMethod(); } clazz = clazz->getSuperclass (); } get_throwable (env) = new java::lang::NoSuchMethodError (); return NULL; } // This is a helper function which turns a va_list into an array of // `jvalue's. It needs signature information in order to do its work. // The array of values must already be allocated. static void array_from_valist (jvalue *values, JArray *arg_types, va_list vargs) { jclass *arg_elts = elements (arg_types); for (int i = 0; i < arg_types->length; ++i) { if (arg_elts[i] == JvPrimClass (byte)) values[i].b = va_arg (vargs, jbyte); else if (arg_elts[i] == JvPrimClass (short)) values[i].s = va_arg (vargs, jshort); else if (arg_elts[i] == JvPrimClass (int)) values[i].i = va_arg (vargs, jint); else if (arg_elts[i] == JvPrimClass (long)) values[i].j = va_arg (vargs, jlong); else if (arg_elts[i] == JvPrimClass (float)) values[i].f = va_arg (vargs, jfloat); else if (arg_elts[i] == JvPrimClass (double)) values[i].d = va_arg (vargs, jdouble); else if (arg_elts[i] == JvPrimClass (boolean)) values[i].z = va_arg (vargs, jboolean); else if (arg_elts[i] == JvPrimClass (char)) values[i].c = va_arg (vargs, jchar); else { // An object. values[i].l = va_arg (vargs, jobject); } } } // This can call any sort of method: virtual, "nonvirtual", static, or // constructor. template static T _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, jmethodID id, va_list vargs) { if (style == normal) id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); jclass return_type; JArray *arg_types; // FIXME: exception processing. _Jv_GetTypesFromSignature (id, decl_class, &arg_types, &return_type); jvalue args[arg_types->length]; array_from_valist (args, arg_types, vargs); jvalue result; jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, style == constructor, arg_types, args, &result); if (ex != NULL) get_throwable (env) = ex; // We cheat a little here. FIXME. return * (T *) &result; } template static T _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { va_list args; T result; va_start (args, method); result = _Jv_JNI_CallAnyMethodV (env, obj, klass, method, args); va_end (args); return result; } template static T _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, jmethodID id, jvalue *args) { if (style == normal) id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); jclass return_type; JArray *arg_types; // FIXME: exception processing. _Jv_GetTypesFromSignature (id, decl_class, &arg_types, &return_type); jvalue result; jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, style == constructor, arg_types, args, &result); if (ex != NULL) get_throwable (env) = ex; // We cheat a little here. FIXME. return * (T *) &result; } template static void _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, jmethodID id, va_list vargs) { if (style == normal) id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); jclass return_type; JArray *arg_types; // FIXME: exception processing. _Jv_GetTypesFromSignature (id, decl_class, &arg_types, &return_type); jvalue args[arg_types->length]; array_from_valist (args, arg_types, vargs); jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, style == constructor, arg_types, args, NULL); if (ex != NULL) get_throwable (env) = ex; } template static void _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { va_list args; va_start (args, method); _Jv_JNI_CallAnyVoidMethodV