// 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 // Define this before including jni.h. #define __GCJ_JNI_IMPL__ #include #include #include #include #include #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; #define MethodClass _CL_Q44java4lang7reflect6Method extern java::lang::Class MethodClass; // This enum is used to select different template instantiations in // the invocation code. enum invocation_type { normal, nonvirtual, static_type, constructor }; // Forward declaration. extern struct JNINativeInterface _Jv_JNIFunctions; // 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. } static jint _Jv_JNI_GetVersion (JNIEnv *) { return JNI_VERSION_1_2; } static jclass _Jv_JNI_DefineClass (JNIEnv *, jobject loader, const jbyte *buf, jsize bufLen) { jbyteArray bytes = JvNewByteArray (bufLen); jbyte *elts = elements (bytes); memcpy (elts, buf, bufLen * sizeof (jbyte)); java::lang::ClassLoader *l = reinterpret_cast (loader); // FIXME: exception processing. jclass result = l->defineClass (bytes, 0, bufLen); return result; } static jclass _Jv_JNI_FindClass (JNIEnv *env, const char *name) { // FIXME: assume that NAME isn't too long. int len = strlen (name); char s[len + 1]; for (int i = 0; i <= len; ++i) s[i] = (name[i] == '/') ? '.' : name[i]; jstring n = JvNewStringUTF (s); java::lang::ClassLoader *loader; if (env->klass == NULL) { // FIXME: should use getBaseClassLoader, but we don't have that // yet. loader = java::lang::ClassLoader::getSystemClassLoader (); } else loader = env->klass->getClassLoader (); // FIXME: exception processing. jclass r = loader->findClass (n); return r; } static jclass _Jv_JNI_GetSuperclass (JNIEnv *, jclass clazz) { return clazz->getSuperclass (); } static jboolean _Jv_JNI_IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2) { return clazz1->isAssignableFrom (clazz2); } static jint _Jv_JNI_Throw (JNIEnv *env, jthrowable obj) { env->ex = 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); env->ex = reinterpret_cast (obj); return 0; } static jthrowable _Jv_JNI_ExceptionOccurred (JNIEnv *env) { // FIXME: create local reference. return env->ex; } static void _Jv_JNI_ExceptionDescribe (JNIEnv *env) { if (env->ex != NULL) env->ex->printStackTrace(); } static void _Jv_JNI_ExceptionClear (JNIEnv *env) { env->ex = NULL; } static jboolean _Jv_JNI_ExceptionCheck (JNIEnv *env) { return env->ex != 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())) env->ex = 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 (); } env->ex = 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) env->ex = 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) env->ex = 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) env->ex = 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