| // jni.cc - JNI implementation, including the jump table. |
| |
| /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
| Free Software Foundation |
| |
| 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. */ |
| |
| #include <config.h> |
| |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <string.h> |
| |
| #include <gcj/cni.h> |
| #include <jvm.h> |
| #include <java-assert.h> |
| #include <jni.h> |
| #ifdef ENABLE_JVMPI |
| #include <jvmpi.h> |
| #endif |
| #ifdef INTERPRETER |
| #include <jvmti.h> |
| #include "jvmti-int.h" |
| #endif |
| #include <java/lang/Class.h> |
| #include <java/lang/ClassLoader.h> |
| #include <java/lang/Throwable.h> |
| #include <java/lang/ArrayIndexOutOfBoundsException.h> |
| #include <java/lang/StringIndexOutOfBoundsException.h> |
| #include <java/lang/StringBuffer.h> |
| #include <java/lang/UnsatisfiedLinkError.h> |
| #include <java/lang/InstantiationException.h> |
| #include <java/lang/NoSuchFieldError.h> |
| #include <java/lang/NoSuchMethodError.h> |
| #include <java/lang/reflect/Constructor.h> |
| #include <java/lang/reflect/Method.h> |
| #include <java/lang/reflect/Modifier.h> |
| #include <java/lang/OutOfMemoryError.h> |
| #include <java/lang/Integer.h> |
| #include <java/lang/ThreadGroup.h> |
| #include <java/lang/Thread.h> |
| #include <java/lang/IllegalAccessError.h> |
| #include <java/nio/Buffer.h> |
| #include <java/nio/DirectByteBufferImpl.h> |
| #include <java/nio/DirectByteBufferImpl$ReadWrite.h> |
| #include <java/util/IdentityHashMap.h> |
| #include <gnu/gcj/RawData.h> |
| #include <java/lang/ClassNotFoundException.h> |
| |
| #include <gcj/method.h> |
| #include <gcj/field.h> |
| |
| #include <java-interp.h> |
| #include <java-threads.h> |
| |
| using namespace gcj; |
| |
| // This enum is used to select different template instantiations in |
| // the invocation code. |
| enum invocation_type |
| { |
| normal, |
| nonvirtual, |
| static_type, |
| constructor |
| }; |
| |
| // Forward declarations. |
| extern struct JNINativeInterface_ _Jv_JNIFunctions; |
| extern struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions; |
| |
| // Number of slots in the default frame. The VM must allow at least |
| // 16. |
| #define FRAME_SIZE 16 |
| |
| // Mark value indicating this is an overflow frame. |
| #define MARK_NONE 0 |
| // Mark value indicating this is a user frame. |
| #define MARK_USER 1 |
| // Mark value indicating this is a system frame. |
| #define MARK_SYSTEM 2 |
| |
| // This structure is used to keep track of local references. |
| struct _Jv_JNI_LocalFrame |
| { |
| // This is one of the MARK_ constants. |
| unsigned char marker; |
| |
| // Flag to indicate some locals were allocated. |
| bool allocated_p; |
| |
| // Number of elements in frame. |
| int size; |
| |
| // The class loader of the JNI method that allocated this frame. |
| ::java::lang::ClassLoader *loader; |
| |
| // Next frame in chain. |
| _Jv_JNI_LocalFrame *next; |
| |
| // The elements. These are allocated using the C "struct hack". |
| jobject vec[0]; |
| }; |
| |
| // This holds a reference count for all local references. |
| static java::util::IdentityHashMap *local_ref_table; |
| // This holds a reference count for all global references. |
| static java::util::IdentityHashMap *global_ref_table; |
| |
| // The only VM. |
| JavaVM *_Jv_the_vm; |
| |
| #ifdef ENABLE_JVMPI |
| // The only JVMPI interface description. |
| static JVMPI_Interface _Jv_JVMPI_Interface; |
| |
| static jint |
| jvmpiEnableEvent (jint event_type, void *) |
| { |
| switch (event_type) |
| { |
| case JVMPI_EVENT_OBJECT_ALLOC: |
| _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent; |
| break; |
| |
| case JVMPI_EVENT_THREAD_START: |
| _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent; |
| break; |
| |
| case JVMPI_EVENT_THREAD_END: |
| _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent; |
| break; |
| |
| default: |
| return JVMPI_NOT_AVAILABLE; |
| } |
| |
| return JVMPI_SUCCESS; |
| } |
| |
| static jint |
| jvmpiDisableEvent (jint event_type, void *) |
| { |
| switch (event_type) |
| { |
| case JVMPI_EVENT_OBJECT_ALLOC: |
| _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL; |
| break; |
| |
| default: |
| return JVMPI_NOT_AVAILABLE; |
| } |
| |
| return JVMPI_SUCCESS; |
| } |
| #endif |
| |
| |
| |
| void |
| _Jv_JNI_Init (void) |
| { |
| local_ref_table = new java::util::IdentityHashMap; |
| global_ref_table = new java::util::IdentityHashMap; |
| |
| #ifdef ENABLE_JVMPI |
| _Jv_JVMPI_Interface.version = 1; |
| _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent; |
| _Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent; |
| _Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC; |
| _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC; |
| _Jv_JVMPI_Interface.RunGC = &_Jv_RunGC; |
| #endif |
| } |
| |
| // Tell the GC that a certain pointer is live. |
| static void |
| mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) |
| { |
| JvSynchronize sync (ref_table); |
| |
| using namespace java::lang; |
| Integer *refcount = (Integer *) ref_table->get (obj); |
| jint val = (refcount == NULL) ? 0 : refcount->intValue (); |
| // FIXME: what about out of memory error? |
| ref_table->put (obj, new Integer (val + 1)); |
| } |
| |
| // Unmark a pointer. |
| static void |
| unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) |
| { |
| JvSynchronize sync (ref_table); |
| |
| using namespace java::lang; |
| Integer *refcount = (Integer *) ref_table->get (obj); |
| JvAssert (refcount); |
| jint val = refcount->intValue () - 1; |
| JvAssert (val >= 0); |
| if (val == 0) |
| ref_table->remove (obj); |
| else |
| // FIXME: what about out of memory error? |
| ref_table->put (obj, new Integer (val)); |
| } |
| |
| // "Unwrap" some random non-reference type. This exists to simplify |
| // other template functions. |
| template<typename T> |
| static T |
| unwrap (T val) |
| { |
| return val; |
| } |
| |
| // Unwrap a weak reference, if required. |
| template<typename T> |
| static T * |
| unwrap (T *obj) |
| { |
| using namespace gnu::gcj::runtime; |
| // We can compare the class directly because JNIWeakRef is `final'. |
| // Doing it this way is much faster. |
| if (obj == NULL || obj->getClass () != &JNIWeakRef::class$) |
| return obj; |
| JNIWeakRef *wr = reinterpret_cast<JNIWeakRef *> (obj); |
| return reinterpret_cast<T *> (wr->get ()); |
| } |
| |
| jobject |
| _Jv_UnwrapJNIweakReference (jobject obj) |
| { |
| return unwrap (obj); |
| } |
| |
| |
| |
| static jobject JNICALL |
| _Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj) |
| { |
| // This seems weird but I think it is correct. |
| obj = unwrap (obj); |
| mark_for_gc (obj, global_ref_table); |
| return obj; |
| } |
| |
| static void JNICALL |
| _Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj) |
| { |
| // This seems weird but I think it is correct. |
| obj = unwrap (obj); |
| |
| // NULL is ok here -- the JNI specification doesn't say so, but this |
| // is a no-op. |
| if (! obj) |
| return; |
| |
| unmark_for_gc (obj, global_ref_table); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj) |
| { |
| _Jv_JNI_LocalFrame *frame; |
| |
| // This seems weird but I think it is correct. |
| obj = unwrap (obj); |
| |
| // NULL is ok here -- the JNI specification doesn't say so, but this |
| // is a no-op. |
| if (! obj) |
| return; |
| |
| for (frame = env->locals; frame != NULL; frame = frame->next) |
| { |
| for (int i = 0; i < frame->size; ++i) |
| { |
| if (frame->vec[i] == obj) |
| { |
| frame->vec[i] = NULL; |
| unmark_for_gc (obj, local_ref_table); |
| return; |
| } |
| } |
| |
| // Don't go past a marked frame. |
| JvAssert (frame->marker == MARK_NONE); |
| } |
| |
| JvAssert (0); |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) |
| { |
| // It is easier to just always allocate a new frame of the requested |
| // size. This isn't the most efficient thing, but for now we don't |
| // care. Note that _Jv_JNI_PushLocalFrame relies on this right now. |
| |
| _Jv_JNI_LocalFrame *frame; |
| try |
| { |
| frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame) |
| + size * sizeof (jobject)); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return JNI_ERR; |
| } |
| |
| frame->marker = MARK_NONE; |
| frame->size = size; |
| frame->allocated_p = false; |
| memset (&frame->vec[0], 0, size * sizeof (jobject)); |
| frame->loader = env->locals->loader; |
| frame->next = env->locals; |
| env->locals = frame; |
| |
| return 0; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) |
| { |
| jint r = _Jv_JNI_EnsureLocalCapacity (env, size); |
| if (r < 0) |
| return r; |
| |
| // The new frame is on top. |
| env->locals->marker = MARK_USER; |
| |
| return 0; |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) |
| { |
| // This seems weird but I think it is correct. |
| obj = unwrap (obj); |
| |
| // Try to find an open slot somewhere in the topmost frame. |
| _Jv_JNI_LocalFrame *frame = env->locals; |
| bool done = false, set = false; |
| for (; frame != NULL && ! done; frame = frame->next) |
| { |
| for (int i = 0; i < frame->size; ++i) |
| { |
| if (frame->vec[i] == NULL) |
| { |
| set = true; |
| done = true; |
| frame->vec[i] = obj; |
| frame->allocated_p = true; |
| break; |
| } |
| } |
| |
| // If we found a slot, or if the frame we just searched is the |
| // mark frame, then we are done. |
| if (done || frame == NULL || frame->marker != MARK_NONE) |
| break; |
| } |
| |
| if (! set) |
| { |
| // No slots, so we allocate a new frame. According to the spec |
| // we could just die here. FIXME: return value. |
| _Jv_JNI_EnsureLocalCapacity (env, 16); |
| // We know the first element of the new frame will be ok. |
| env->locals->vec[0] = obj; |
| env->locals->allocated_p = true; |
| } |
| |
| mark_for_gc (obj, local_ref_table); |
| return obj; |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop) |
| { |
| _Jv_JNI_LocalFrame *rf = env->locals; |
| |
| bool done = false; |
| while (rf != NULL && ! done) |
| { |
| for (int i = 0; i < rf->size; ++i) |
| if (rf->vec[i] != NULL) |
| unmark_for_gc (rf->vec[i], local_ref_table); |
| |
| // If the frame we just freed is the marker frame, we are done. |
| done = (rf->marker == stop); |
| |
| _Jv_JNI_LocalFrame *n = rf->next; |
| // When N==NULL, we've reached the reusable bottom_locals, and we must |
| // not free it. However, we must be sure to clear all its elements. |
| if (n == NULL) |
| { |
| if (rf->allocated_p) |
| memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); |
| rf->allocated_p = false; |
| rf = NULL; |
| break; |
| } |
| |
| _Jv_Free (rf); |
| rf = n; |
| } |
| |
| // Update the local frame information. |
| env->locals = rf; |
| |
| return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result); |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result) |
| { |
| return _Jv_JNI_PopLocalFrame (env, result, MARK_USER); |
| } |
| |
| // Make sure an array's type is compatible with the type of the |
| // destination. |
| template<typename T> |
| static bool |
| _Jv_JNI_check_types (JNIEnv *env, JArray<T> *array, jclass K) |
| { |
| jclass klass = array->getClass()->getComponentType(); |
| if (__builtin_expect (klass != K, false)) |
| { |
| env->ex = new java::lang::IllegalAccessError (); |
| return false; |
| } |
| else |
| return true; |
| } |
| |
| // Pop a `system' frame from the stack. This is `extern "C"' as it is |
| // used by the compiler. |
| extern "C" void |
| _Jv_JNI_PopSystemFrame (JNIEnv *env) |
| { |
| // Only enter slow path when we're not at the bottom, or there have been |
| // allocations. Usually this is false and we can just null out the locals |
| // field. |
| |
| if (__builtin_expect ((env->locals->next |
| || env->locals->allocated_p), false)) |
| _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM); |
| else |
| env->locals = NULL; |
| |
| #ifdef INTERPRETER |
| if (__builtin_expect (env->ex != NULL, false)) |
| { |
| jthrowable t = env->ex; |
| env->ex = NULL; |
| if (JVMTI_REQUESTED_EVENT (Exception)) |
| _Jv_ReportJVMTIExceptionThrow (t); |
| throw t; |
| } |
| #endif |
| } |
| |
| template<typename T> T extract_from_jvalue(jvalue const & t); |
| template<> jboolean extract_from_jvalue(jvalue const & jv) { return jv.z; } |
| template<> jbyte extract_from_jvalue(jvalue const & jv) { return jv.b; } |
| template<> jchar extract_from_jvalue(jvalue const & jv) { return jv.c; } |
| template<> jshort extract_from_jvalue(jvalue const & jv) { return jv.s; } |
| template<> jint extract_from_jvalue(jvalue const & jv) { return jv.i; } |
| template<> jlong extract_from_jvalue(jvalue const & jv) { return jv.j; } |
| template<> jfloat extract_from_jvalue(jvalue const & jv) { return jv.f; } |
| template<> jdouble extract_from_jvalue(jvalue const & jv) { return jv.d; } |
| template<> jobject extract_from_jvalue(jvalue const & jv) { return jv.l; } |
| |
| |
| // This function is used from other template functions. It wraps the |
| // return value appropriately; we specialize it so that object returns |
| // are turned into local references. |
| template<typename T> |
| static T |
| wrap_value (JNIEnv *, T value) |
| { |
| return value; |
| } |
| |
| // This specialization is used for jobject, jclass, jstring, jarray, |
| // etc. |
| template<typename R, typename T> |
| static T * |
| wrap_value (JNIEnv *env, T *value) |
| { |
| return (value == NULL |
| ? value |
| : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value)); |
| } |
| |
| |
| |
| static jint JNICALL |
| _Jv_JNI_GetVersion (JNIEnv *) |
| { |
| return JNI_VERSION_1_4; |
| } |
| |
| static jclass JNICALL |
| _Jv_JNI_DefineClass (JNIEnv *env, const char *name, jobject loader, |
| const jbyte *buf, jsize bufLen) |
| { |
| try |
| { |
| loader = unwrap (loader); |
| |
| jstring sname = JvNewStringUTF (name); |
| jbyteArray bytes = JvNewByteArray (bufLen); |
| |
| jbyte *elts = elements (bytes); |
| memcpy (elts, buf, bufLen * sizeof (jbyte)); |
| |
| java::lang::ClassLoader *l |
| = reinterpret_cast<java::lang::ClassLoader *> (loader); |
| |
| jclass result = l->defineClass (sname, bytes, 0, bufLen); |
| return (jclass) wrap_value (env, result); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| static jclass JNICALL |
| _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]; |
| |
| jclass r = NULL; |
| try |
| { |
| // This might throw an out of memory exception. |
| jstring n = JvNewStringUTF (s); |
| |
| java::lang::ClassLoader *loader = NULL; |
| if (env->locals->loader != NULL) |
| loader = env->locals->loader; |
| |
| if (loader == NULL) |
| { |
| // FIXME: should use getBaseClassLoader, but we don't have that |
| // yet. |
| loader = java::lang::ClassLoader::getSystemClassLoader (); |
| } |
| |
| r = loader->loadClass (n); |
| _Jv_InitClass (r); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return (jclass) wrap_value (env, r); |
| } |
| |
| static jclass JNICALL |
| _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz) |
| { |
| return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ()); |
| } |
| |
| static jboolean JNICALL |
| _Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2) |
| { |
| return unwrap (clazz2)->isAssignableFrom (unwrap (clazz1)); |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_Throw (JNIEnv *env, jthrowable obj) |
| { |
| // We check in case the user did some funky cast. |
| obj = unwrap (obj); |
| JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj)); |
| env->ex = obj; |
| return 0; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) |
| { |
| using namespace java::lang::reflect; |
| |
| clazz = unwrap (clazz); |
| JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz)); |
| |
| int r = JNI_OK; |
| try |
| { |
| JArray<jclass> *argtypes |
| = (JArray<jclass> *) JvNewObjectArray (1, &java::lang::Class::class$, |
| NULL); |
| |
| jclass *elts = elements (argtypes); |
| elts[0] = &java::lang::String::class$; |
| |
| Constructor *cons = clazz->getConstructor (argtypes); |
| |
| jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$, |
| NULL); |
| jobject *velts = elements (values); |
| velts[0] = JvNewStringUTF (message); |
| |
| jobject obj = cons->newInstance (values); |
| |
| env->ex = reinterpret_cast<jthrowable> (obj); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| r = JNI_ERR; |
| } |
| |
| return r; |
| } |
| |
| static jthrowable JNICALL |
| _Jv_JNI_ExceptionOccurred (JNIEnv *env) |
| { |
| return (jthrowable) wrap_value (env, env->ex); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ExceptionDescribe (JNIEnv *env) |
| { |
| if (env->ex != NULL) |
| env->ex->printStackTrace(); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ExceptionClear (JNIEnv *env) |
| { |
| env->ex = NULL; |
| } |
| |
| static jboolean JNICALL |
| _Jv_JNI_ExceptionCheck (JNIEnv *env) |
| { |
| return env->ex != NULL; |
| } |
| |
| static void JNICALL |
| _Jv_JNI_FatalError (JNIEnv *, const char *message) |
| { |
| JvFail (message); |
| } |
| |
| |
| |
| static jboolean JNICALL |
| _Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2) |
| { |
| return unwrap (obj1) == unwrap (obj2); |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) |
| { |
| jobject obj = NULL; |
| using namespace java::lang::reflect; |
| |
| try |
| { |
| clazz = unwrap (clazz); |
| JvAssert (clazz && ! clazz->isArray ()); |
| if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers())) |
| env->ex = new java::lang::InstantiationException (); |
| else |
| obj = _Jv_AllocObject (clazz); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return wrap_value (env, obj); |
| } |
| |
| static jclass JNICALL |
| _Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj) |
| { |
| obj = unwrap (obj); |
| JvAssert (obj); |
| return (jclass) wrap_value (env, obj->getClass()); |
| } |
| |
| static jboolean JNICALL |
| _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz) |
| { |
| return unwrap (clazz)->isInstance(unwrap (obj)); |
| } |
| |
| |
| |
| // |
| // This section concerns method invocation. |
| // |
| |
| template<jboolean is_static> |
| static jmethodID JNICALL |
| _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz, |
| const char *name, const char *sig) |
| { |
| try |
| { |
| clazz = unwrap (clazz); |
| _Jv_InitClass (clazz); |
| |
| _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1); |
| |
| // FIXME: assume that SIG isn't too long. |
| int len = strlen (sig); |
| char s[len + 1]; |
| for (int i = 0; i <= len; ++i) |
| s[i] = (sig[i] == '/') ? '.' : sig[i]; |
| _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -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 (); |
| } |
| |
| java::lang::StringBuffer *name_sig = |
| new java::lang::StringBuffer (JvNewStringUTF (name)); |
| name_sig->append ((jchar) ' '); |
| name_sig->append (JvNewStringUTF (s)); |
| env->ex = new java::lang::NoSuchMethodError (name_sig->toString ()); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| 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<jclass> *arg_types, va_list vargs) |
| { |
| jclass *arg_elts = elements (arg_types); |
| for (int i = 0; i < arg_types->length; ++i) |
| { |
| // Here we assume that sizeof(int) >= sizeof(jint), because we |
| // use `int' when decoding the varargs. Likewise for |
| // float, and double. Also we assume that sizeof(jlong) >= |
| // sizeof(int), i.e. that jlong values are not further |
| // promoted. |
| JvAssert (sizeof (int) >= sizeof (jint)); |
| JvAssert (sizeof (jlong) >= sizeof (int)); |
| JvAssert (sizeof (double) >= sizeof (jfloat)); |
| JvAssert (sizeof (double) >= sizeof (jdouble)); |
| if (arg_elts[i] == JvPrimClass (byte)) |
| values[i].b = (jbyte) va_arg (vargs, int); |
| else if (arg_elts[i] == JvPrimClass (short)) |
| values[i].s = (jshort) va_arg (vargs, int); |
| else if (arg_elts[i] == JvPrimClass (int)) |
| values[i].i = (jint) va_arg (vargs, int); |
| else if (arg_elts[i] == JvPrimClass (long)) |
| values[i].j = (jlong) va_arg (vargs, jlong); |
| else if (arg_elts[i] == JvPrimClass (float)) |
| values[i].f = (jfloat) va_arg (vargs, double); |
| else if (arg_elts[i] == JvPrimClass (double)) |
| values[i].d = (jdouble) va_arg (vargs, double); |
| else if (arg_elts[i] == JvPrimClass (boolean)) |
| values[i].z = (jboolean) va_arg (vargs, int); |
| else if (arg_elts[i] == JvPrimClass (char)) |
| values[i].c = (jchar) va_arg (vargs, int); |
| else |
| { |
| // An object. |
| values[i].l = unwrap (va_arg (vargs, jobject)); |
| } |
| } |
| } |
| |
| // This can call any sort of method: virtual, "nonvirtual", static, or |
| // constructor. |
| template<typename T, invocation_type style> |
| static T JNICALL |
| _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID id, va_list vargs) |
| { |
| obj = unwrap (obj); |
| klass = unwrap (klass); |
| |
| jclass decl_class = klass ? klass : obj->getClass (); |
| JvAssert (decl_class != NULL); |
| |
| jclass return_type; |
| JArray<jclass> *arg_types; |
| |
| try |
| { |
| _Jv_GetTypesFromSignature (id, decl_class, |
| &arg_types, &return_type); |
| |
| jvalue args[arg_types->length]; |
| array_from_valist (args, arg_types, vargs); |
| |
| // For constructors we need to pass the Class we are instantiating. |
| if (style == constructor) |
| return_type = klass; |
| |
| jvalue result; |
| _Jv_CallAnyMethodA (obj, return_type, id, |
| style == constructor, |
| style == normal, |
| arg_types, args, &result); |
| |
| return wrap_value (env, extract_from_jvalue<T>(result)); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return wrap_value (env, (T) 0); |
| } |
| |
| template<typename T, invocation_type style> |
| static T JNICALL |
| _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID method, ...) |
| { |
| va_list args; |
| T result; |
| |
| va_start (args, method); |
| result = _Jv_JNI_CallAnyMethodV<T, style> (env, obj, klass, method, args); |
| va_end (args); |
| |
| return result; |
| } |
| |
| template<typename T, invocation_type style> |
| static T JNICALL |
| _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID id, const jvalue *args) |
| { |
| obj = unwrap (obj); |
| klass = unwrap (klass); |
| |
| jclass decl_class = klass ? klass : obj->getClass (); |
| JvAssert (decl_class != NULL); |
| |
| jclass return_type; |
| JArray<jclass> *arg_types; |
| try |
| { |
| _Jv_GetTypesFromSignature (id, decl_class, |
| &arg_types, &return_type); |
| |
| // For constructors we need to pass the Class we are instantiating. |
| if (style == constructor) |
| return_type = klass; |
| |
| // Unwrap arguments as required. Eww. |
| jclass *type_elts = elements (arg_types); |
| jvalue arg_copy[arg_types->length]; |
| for (int i = 0; i < arg_types->length; ++i) |
| { |
| if (type_elts[i]->isPrimitive ()) |
| arg_copy[i] = args[i]; |
| else |
| arg_copy[i].l = unwrap (args[i].l); |
| } |
| |
| jvalue result; |
| _Jv_CallAnyMethodA (obj, return_type, id, |
| style == constructor, |
| style == normal, |
| arg_types, arg_copy, &result); |
| |
| return wrap_value (env, extract_from_jvalue<T>(result)); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return wrap_value (env, (T) 0); |
| } |
| |
| template<invocation_type style> |
| static void JNICALL |
| _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID id, va_list vargs) |
| { |
| obj = unwrap (obj); |
| klass = unwrap (klass); |
| |
| jclass decl_class = klass ? klass : obj->getClass (); |
| JvAssert (decl_class != NULL); |
| |
| jclass return_type; |
| JArray<jclass> *arg_types; |
| try |
| { |
| _Jv_GetTypesFromSignature (id, decl_class, |
| &arg_types, &return_type); |
| |
| jvalue args[arg_types->length]; |
| array_from_valist (args, arg_types, vargs); |
| |
| // For constructors we need to pass the Class we are instantiating. |
| if (style == constructor) |
| return_type = klass; |
| |
| _Jv_CallAnyMethodA (obj, return_type, id, |
| style == constructor, |
| style == normal, |
| arg_types, args, NULL); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| |
| template<invocation_type style> |
| static void JNICALL |
| _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID method, ...) |
| { |
| va_list args; |
| |
| va_start (args, method); |
| _Jv_JNI_CallAnyVoidMethodV<style> (env, obj, klass, method, args); |
| va_end (args); |
| } |
| |
| template<invocation_type style> |
| static void JNICALL |
| _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass, |
| jmethodID id, const jvalue *args) |
| { |
| jclass decl_class = klass ? klass : obj->getClass (); |
| JvAssert (decl_class != NULL); |
| |
| jclass return_type; |
| JArray<jclass> *arg_types; |
| try |
| { |
| _Jv_GetTypesFromSignature (id, decl_class, |
| &arg_types, &return_type); |
| |
| // Unwrap arguments as required. Eww. |
| jclass *type_elts = elements (arg_types); |
| jvalue arg_copy[arg_types->length]; |
| for (int i = 0; i < arg_types->length; ++i) |
| { |
| if (type_elts[i]->isPrimitive ()) |
| arg_copy[i] = args[i]; |
| else |
| arg_copy[i].l = unwrap (args[i].l); |
| } |
| |
| _Jv_CallAnyMethodA (obj, return_type, id, |
| style == constructor, |
| style == normal, |
| arg_types, args, NULL); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, |
| jmethodID id, va_list args) |
| { |
| return _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args); |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...) |
| { |
| va_list args; |
| T result; |
| |
| va_start (args, id); |
| result = _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args); |
| va_end (args); |
| |
| return result; |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, |
| jmethodID id, const jvalue *args) |
| { |
| return _Jv_JNI_CallAnyMethodA<T, normal> (env, obj, NULL, id, args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, |
| jmethodID id, va_list args) |
| { |
| _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...) |
| { |
| va_list args; |
| |
| va_start (args, id); |
| _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args); |
| va_end (args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, |
| jmethodID id, const jvalue *args) |
| { |
| _Jv_JNI_CallAnyVoidMethodA<normal> (env, obj, NULL, id, args); |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallStaticMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass, |
| jmethodID id, va_list args) |
| { |
| JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); |
| JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); |
| |
| return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args); |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallStaticMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, |
| jmethodID id, ...) |
| { |
| va_list args; |
| T result; |
| |
| JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); |
| JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); |
| |
| va_start (args, id); |
| result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, |
| id, args); |
| va_end (args); |
| |
| return result; |
| } |
| |
| // Functions with this signature are used to implement functions in |
| // the CallStaticMethod family. |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id, |
| const jvalue *args) |
| { |
| JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); |
| JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); |
| |
| return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, |
| jmethodID id, va_list args) |
| { |
| _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, |
| jmethodID id, ...) |
| { |
| va_list args; |
| |
| va_start (args, id); |
| _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args); |
| va_end (args); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, |
| jmethodID id, const jvalue *args) |
| { |
| _Jv_JNI_CallAnyVoidMethodA<static_type> (env, NULL, klass, id, args); |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_NewObjectV (JNIEnv *env, jclass klass, |
| jmethodID id, va_list args) |
| { |
| JvAssert (klass && ! klass->isArray ()); |
| JvAssert (! strcmp (id->name->chars(), "<init>") |
| && id->signature->len() > 2 |
| && id->signature->chars()[0] == '(' |
| && ! strcmp (&id->signature->chars()[id->signature->len() - 2], |
| ")V")); |
| |
| return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass, |
| id, args); |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...) |
| { |
| JvAssert (klass && ! klass->isArray ()); |
| JvAssert (! strcmp (id->name->chars(), "<init>") |
| && id->signature->len() > 2 |
| && id->signature->chars()[0] == '(' |
| && ! strcmp (&id->signature->chars()[id->signature->len() - 2], |
| ")V")); |
| |
| va_list args; |
| jobject result; |
| |
| va_start (args, id); |
| result = _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass, |
| id, args); |
| va_end (args); |
| |
| return result; |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id, |
| const jvalue *args) |
| { |
| JvAssert (klass && ! klass->isArray ()); |
| JvAssert (! strcmp (id->name->chars(), "<init>") |
| && id->signature->len() > 2 |
| && id->signature->chars()[0] == '(' |
| && ! strcmp (&id->signature->chars()[id->signature->len() - 2], |
| ")V")); |
| |
| return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass, |
| id, args); |
| } |
| |
| |
| |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field) |
| { |
| obj = unwrap (obj); |
| JvAssert (obj); |
| T *ptr = (T *) ((char *) obj + field->getOffset ()); |
| return wrap_value (env, *ptr); |
| } |
| |
| template<typename T> |
| static void JNICALL |
| _Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value) |
| { |
| obj = unwrap (obj); |
| value = unwrap (value); |
| |
| JvAssert (obj); |
| T *ptr = (T *) ((char *) obj + field->getOffset ()); |
| *ptr = value; |
| } |
| |
| template<jboolean is_static> |
| static jfieldID JNICALL |
| _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz, |
| const char *name, const char *sig) |
| { |
| try |
| { |
| clazz = unwrap (clazz); |
| |
| _Jv_InitClass (clazz); |
| |
| _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1); |
| |
| // FIXME: assume that SIG isn't too long. |
| int len = strlen (sig); |
| char s[len + 1]; |
| for (int i = 0; i <= len; ++i) |
| s[i] = (sig[i] == '/') ? '.' : sig[i]; |
| java::lang::ClassLoader *loader = clazz->getClassLoaderInternal (); |
| jclass field_class = _Jv_FindClassFromSignature ((char *) s, loader); |
| if (! field_class) |
| throw new java::lang::ClassNotFoundException(JvNewStringUTF(s)); |
| |
| while (clazz != NULL) |
| { |
| // We acquire the class lock so that fields aren't resolved |
| // while we are running. |
| JvSynchronize sync (clazz); |
| |
| jint count = (is_static |
| ? JvNumStaticFields (clazz) |
| : JvNumInstanceFields (clazz)); |
| jfieldID field = (is_static |
| ? JvGetFirstStaticField (clazz) |
| : JvGetFirstInstanceField (clazz)); |
| for (jint i = 0; i < count; ++i) |
| { |
| _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz); |
| |
| // The field might be resolved or it might not be. It |
| // is much simpler to always resolve it. |
| _Jv_Linker::resolve_field (field, loader); |
| if (_Jv_equalUtf8Consts (f_name, a_name) |
| && field->getClass() == field_class) |
| return field; |
| |
| field = field->getNextField (); |
| } |
| |
| clazz = clazz->getSuperclass (); |
| } |
| |
| env->ex = new java::lang::NoSuchFieldError (); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| return NULL; |
| } |
| |
| template<typename T> |
| static T JNICALL |
| _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field) |
| { |
| T *ptr = (T *) field->u.addr; |
| return wrap_value (env, *ptr); |
| } |
| |
| template<typename T> |
| static void JNICALL |
| _Jv_JNI_SetStaticField (JNIEnv *, jclass, jfieldID field, T value) |
| { |
| value = unwrap (value); |
| T *ptr = (T *) field->u.addr; |
| *ptr = value; |
| } |
| |
| static jstring JNICALL |
| _Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len) |
| { |
| try |
| { |
| jstring r = _Jv_NewString (unichars, len); |
| return (jstring) wrap_value (env, r); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| static jsize JNICALL |
| _Jv_JNI_GetStringLength (JNIEnv *, jstring string) |
| { |
| return unwrap (string)->length(); |
| } |
| |
| static const jchar * JNICALL |
| _Jv_JNI_GetStringChars (JNIEnv *, jstring string, jboolean *isCopy) |
| { |
| string = unwrap (string); |
| jchar *result = _Jv_GetStringChars (string); |
| mark_for_gc (string, global_ref_table); |
| if (isCopy) |
| *isCopy = false; |
| return (const jchar *) result; |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ReleaseStringChars (JNIEnv *, jstring string, const jchar *) |
| { |
| unmark_for_gc (unwrap (string), global_ref_table); |
| } |
| |
| static jstring JNICALL |
| _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes) |
| { |
| try |
| { |
| // For compatibility with the JDK. |
| if (!bytes) |
| return NULL; |
| jstring result = JvNewStringUTF (bytes); |
| return (jstring) wrap_value (env, result); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| static jsize JNICALL |
| _Jv_JNI_GetStringUTFLength (JNIEnv *, jstring string) |
| { |
| return JvGetStringUTFLength (unwrap (string)); |
| } |
| |
| static const char * JNICALL |
| _Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, |
| jboolean *isCopy) |
| { |
| try |
| { |
| string = unwrap (string); |
| if (string == NULL) |
| return NULL; |
| jsize len = JvGetStringUTFLength (string); |
| char *r = (char *) _Jv_Malloc (len + 1); |
| JvGetStringUTFRegion (string, 0, string->length(), r); |
| r[len] = '\0'; |
| |
| if (isCopy) |
| *isCopy = true; |
| |
| return (const char *) r; |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ReleaseStringUTFChars (JNIEnv *, jstring, const char *utf) |
| { |
| _Jv_Free ((void *) utf); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, |
| jsize len, jchar *buf) |
| { |
| string = unwrap (string); |
| jchar *result = _Jv_GetStringChars (string); |
| if (start < 0 || start > string->length () |
| || len < 0 || start + len > string->length ()) |
| { |
| try |
| { |
| env->ex = new java::lang::StringIndexOutOfBoundsException (); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| else |
| memcpy (buf, &result[start], len * sizeof (jchar)); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start, |
| jsize len, char *buf) |
| { |
| str = unwrap (str); |
| |
| if (start < 0 || start > str->length () |
| || len < 0 || start + len > str->length ()) |
| { |
| try |
| { |
| env->ex = new java::lang::StringIndexOutOfBoundsException (); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| else |
| _Jv_GetStringUTFRegion (str, start, len, buf); |
| } |
| |
| static const jchar * JNICALL |
| _Jv_JNI_GetStringCritical (JNIEnv *, jstring str, jboolean *isCopy) |
| { |
| jchar *result = _Jv_GetStringChars (unwrap (str)); |
| if (isCopy) |
| *isCopy = false; |
| return result; |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ReleaseStringCritical (JNIEnv *, jstring, const jchar *) |
| { |
| // Nothing. |
| } |
| |
| static jsize JNICALL |
| _Jv_JNI_GetArrayLength (JNIEnv *, jarray array) |
| { |
| return unwrap (array)->length; |
| } |
| |
| static jobjectArray JNICALL |
| _Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, |
| jclass elementClass, jobject init) |
| { |
| try |
| { |
| elementClass = unwrap (elementClass); |
| init = unwrap (init); |
| |
| _Jv_CheckCast (elementClass, init); |
| jarray result = JvNewObjectArray (length, elementClass, init); |
| return (jobjectArray) wrap_value (env, result); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| static jobject JNICALL |
| _Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array, |
| jsize index) |
| { |
| if ((unsigned) index >= (unsigned) array->length) |
| _Jv_ThrowBadArrayIndex (index); |
| jobject *elts = elements (unwrap (array)); |
| return wrap_value (env, elts[index]); |
| } |
| |
| static void JNICALL |
| _Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, |
| jsize index, jobject value) |
| { |
| try |
| { |
| array = unwrap (array); |
| value = unwrap (value); |
| |
| _Jv_CheckArrayStore (array, value); |
| if ((unsigned) index >= (unsigned) array->length) |
| _Jv_ThrowBadArrayIndex (index); |
| jobject *elts = elements (array); |
| elts[index] = value; |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| |
| template<typename T, jclass K> |
| static JArray<T> * JNICALL |
| _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length) |
| { |
| try |
| { |
| return (JArray<T> *) wrap_value (env, _Jv_NewPrimArray (K, length)); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| return NULL; |
| } |
| } |
| |
| template<typename T, jclass K> |
| static T * JNICALL |
| _Jv_JNI_GetPrimitiveArrayElements (JNIEnv *env, JArray<T> *array, |
| jboolean *isCopy) |
| { |
| array = unwrap (array); |
| if (! _Jv_JNI_check_types (env, array, K)) |
| return NULL; |
| T *elts = elements (array); |
| if (isCopy) |
| { |
| // We elect never to copy. |
| *isCopy = false; |
| } |
| mark_for_gc (array, global_ref_table); |
| return elts; |
| } |
| |
| template<typename T, jclass K> |
| static void JNICALL |
| _Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *env, JArray<T> *array, |
| T *, jint /* mode */) |
| { |
| array = unwrap (array); |
| _Jv_JNI_check_types (env, array, K); |
| // Note that we ignore MODE. We can do this because we never copy |
| // the array elements. My reading of the JNI documentation is that |
| // this is an option for the implementor. |
| unmark_for_gc (array, global_ref_table); |
| } |
| |
| template<typename T, jclass K> |
| static void JNICALL |
| _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array, |
| jsize start, jsize len, |
| T *buf) |
| { |
| array = unwrap (array); |
| if (! _Jv_JNI_check_types (env, array, K)) |
| return; |
| |
| // The cast to unsigned lets us save a comparison. |
| if (start < 0 || len < 0 |
| || (unsigned long) (start + len) > (unsigned long) array->length) |
| { |
| try |
| { |
| // FIXME: index. |
| env->ex = new java::lang::ArrayIndexOutOfBoundsException (); |
| } |
| catch (jthrowable t) |
| { |
| // Could have thown out of memory error. |
| env->ex = t; |
| } |
| } |
| else |
| { |
| T *elts = elements (array) + start; |
| memcpy (buf, elts, len * sizeof (T)); |
| } |
| } |
| |
| template<typename T, jclass K> |
| static void JNICALL |
| _Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array, |
| jsize start, jsize len, const T *buf) |
| { |
| array = unwrap (array); |
| if (! _Jv_JNI_check_types (env, array, K)) |
| return; |
| |
| // The cast to unsigned lets us save a comparison. |
| if (start < 0 || len < 0 |
| || (unsigned long) (start + len) > (unsigned long) array->length) |
| { |
| try |
| { |
| // FIXME: index. |
| env->ex = new java::lang::ArrayIndexOutOfBoundsException (); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| } |
| else |
| { |
| T *elts = elements (array) + start; |
| memcpy (elts, buf, len * sizeof (T)); |
| } |
| } |
| |
| static void * JNICALL |
| _Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array, |
| jboolean *isCopy) |
| { |
| array = unwrap (array); |
| // FIXME: does this work? |
| jclass klass = array->getClass()->getComponentType(); |
| JvAssert (klass->isPrimitive ()); |
| char *r = _Jv_GetArrayElementFromElementType (array, klass); |
| if (isCopy) |
| *isCopy = false; |
| return r; |
| } |
| |
| static void JNICALL |
| _Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint) |
| { |
| // Nothing. |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj) |
| { |
| try |
| { |
| _Jv_MonitorEnter (unwrap (obj)); |
| return 0; |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| return JNI_ERR; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_MonitorExit (JNIEnv *env, jobject obj) |
| { |
| try |
| { |
| _Jv_MonitorExit (unwrap (obj)); |
| return 0; |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| return JNI_ERR; |
| } |
| |
| // JDK 1.2 |
| jobject JNICALL |
| _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID, |
| jboolean) |
| { |
| try |
| { |
| cls = unwrap (cls); |
| java::lang::reflect::Field *field = new java::lang::reflect::Field(); |
| field->declaringClass = cls; |
| field->offset = (char*) fieldID - (char *) cls->fields; |
| field->name = _Jv_NewStringUtf8Const (fieldID->getNameUtf8Const (cls)); |
| return wrap_value (env, field); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| return NULL; |
| } |
| |
| // JDK 1.2 |
| static jfieldID JNICALL |
| _Jv_JNI_FromReflectedField (JNIEnv *, jobject f) |
| { |
| using namespace java::lang::reflect; |
| |
| f = unwrap (f); |
| Field *field = reinterpret_cast<Field *> (f); |
| return _Jv_FromReflectedField (field); |
| } |
| |
| jobject JNICALL |
| _Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id, |
| jboolean) |
| { |
| using namespace java::lang::reflect; |
| |
| jobject result = NULL; |
| klass = unwrap (klass); |
| |
| try |
| { |
| if (_Jv_equalUtf8Consts (id->name, init_name)) |
| { |
| // A constructor. |
| Constructor *cons = new Constructor (); |
| cons->offset = (char *) id - (char *) &klass->methods; |
| cons->declaringClass = klass; |
| result = cons; |
| } |
| else |
| { |
| Method *meth = new Method (); |
| meth->offset = (char *) id - (char *) &klass->methods; |
| meth->declaringClass = klass; |
| result = meth; |
| } |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return wrap_value (env, result); |
| } |
| |
| static jmethodID JNICALL |
| _Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method) |
| { |
| using namespace java::lang::reflect; |
| method = unwrap (method); |
| if (Method::class$.isInstance (method)) |
| return _Jv_FromReflectedMethod (reinterpret_cast<Method *> (method)); |
| return |
| _Jv_FromReflectedConstructor (reinterpret_cast<Constructor *> (method)); |
| } |
| |
| // JDK 1.2. |
| jweak JNICALL |
| _Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj) |
| { |
| using namespace gnu::gcj::runtime; |
| JNIWeakRef *ref = NULL; |
| |
| try |
| { |
| // This seems weird but I think it is correct. |
| obj = unwrap (obj); |
| ref = new JNIWeakRef (obj); |
| mark_for_gc (ref, global_ref_table); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| |
| return reinterpret_cast<jweak> (ref); |
| } |
| |
| void JNICALL |
| _Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj) |
| { |
| // JDK compatibility. |
| if (obj == NULL) |
| return; |
| |
| using namespace gnu::gcj::runtime; |
| JNIWeakRef *ref = reinterpret_cast<JNIWeakRef *> (obj); |
| unmark_for_gc (ref, global_ref_table); |
| ref->clear (); |
| } |
| |
| |
| |
| // Direct byte buffers. |
| |
| static jobject JNICALL |
| _Jv_JNI_NewDirectByteBuffer (JNIEnv *, void *address, jlong length) |
| { |
| using namespace gnu::gcj; |
| using namespace java::nio; |
| return new DirectByteBufferImpl$ReadWrite |
| (reinterpret_cast<RawData *> (address), length); |
| } |
| |
| static void * JNICALL |
| _Jv_JNI_GetDirectBufferAddress (JNIEnv *, jobject buffer) |
| { |
| using namespace java::nio; |
| if (! _Jv_IsInstanceOf (buffer, &Buffer::class$)) |
| return NULL; |
| Buffer *tmp = static_cast<Buffer *> (buffer); |
| return reinterpret_cast<void *> (tmp->address); |
| } |
| |
| static jlong JNICALL |
| _Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer) |
| { |
| using namespace java::nio; |
| if (! _Jv_IsInstanceOf (buffer, &Buffer::class$)) |
| return -1; |
| Buffer *tmp = static_cast<Buffer *> (buffer); |
| if (tmp->address == NULL) |
| return -1; |
| return tmp->capacity(); |
| } |
| |
| static jobjectRefType JNICALL |
| _Jv_JNI_GetObjectRefType (JNIEnv *, MAYBE_UNUSED jobject object) |
| { |
| JvFail("GetObjectRefType not implemented"); |
| return JNIInvalidRefType; |
| } |
| |
| |
| |
| struct NativeMethodCacheEntry : public JNINativeMethod |
| { |
| char *className; |
| }; |
| |
| // Hash table of native methods. |
| static NativeMethodCacheEntry *nathash; |
| // Number of slots used. |
| static int nathash_count = 0; |
| // Number of slots available. Must be power of 2. |
| static int nathash_size = 0; |
| |
| #define DELETED_ENTRY ((char *) (~0)) |
| |
| // Compute a hash value for a native method descriptor. |
| static int |
| hash (const NativeMethodCacheEntry *method) |
| { |
| char *ptr; |
| int hash = 0; |
| |
| ptr = method->className; |
| while (*ptr) |
| hash = (31 * hash) + *ptr++; |
| |
| ptr = method->name; |
| while (*ptr) |
| hash = (31 * hash) + *ptr++; |
| |
| ptr = method->signature; |
| while (*ptr) |
| hash = (31 * hash) + *ptr++; |
| |
| return hash; |
| } |
| |
| // Find the slot where a native method goes. |
| static NativeMethodCacheEntry * |
| nathash_find_slot (const NativeMethodCacheEntry *method) |
| { |
| jint h = hash (method); |
| int step = (h ^ (h >> 16)) | 1; |
| int w = h & (nathash_size - 1); |
| int del = -1; |
| |
| for (;;) |
| { |
| NativeMethodCacheEntry *slotp = &nathash[w]; |
| if (slotp->name == NULL) |
| { |
| if (del >= 0) |
| return &nathash[del]; |
| else |
| return slotp; |
| } |
| else if (slotp->name == DELETED_ENTRY) |
| del = w; |
| else if (! strcmp (slotp->name, method->name) |
| && ! strcmp (slotp->signature, method->signature) |
| && ! strcmp (slotp->className, method->className)) |
| return slotp; |
| w = (w + step) & (nathash_size - 1); |
| } |
| } |
| |
| // Find a method. Return NULL if it isn't in the hash table. |
| static void * |
| nathash_find (NativeMethodCacheEntry *method) |
| { |
| if (nathash == NULL) |
| return NULL; |
| NativeMethodCacheEntry *slot = nathash_find_slot (method); |
| if (slot->name == NULL || slot->name == DELETED_ENTRY) |
| return NULL; |
| return slot->fnPtr; |
| } |
| |
| static void |
| natrehash () |
| { |
| if (nathash == NULL) |
| { |
| nathash_size = 1024; |
| nathash = |
| (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size |
| * sizeof (NativeMethodCacheEntry)); |
| } |
| else |
| { |
| int savesize = nathash_size; |
| NativeMethodCacheEntry *savehash = nathash; |
| nathash_size *= 2; |
| nathash = |
| (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size |
| * sizeof (NativeMethodCacheEntry)); |
| |
| for (int i = 0; i < savesize; ++i) |
| { |
| if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY) |
| { |
| NativeMethodCacheEntry *slot = nathash_find_slot (&savehash[i]); |
| *slot = savehash[i]; |
| } |
| } |
| } |
| } |
| |
| static void |
| nathash_add (const NativeMethodCacheEntry *method) |
| { |
| if (3 * nathash_count >= 2 * nathash_size) |
| natrehash (); |
| NativeMethodCacheEntry *slot = nathash_find_slot (method); |
| // If the slot has a real entry in it, then there is no work to do. |
| if (slot->name != NULL && slot->name != DELETED_ENTRY) |
| return; |
| // FIXME: memory leak? |
| slot->name = strdup (method->name); |
| slot->className = strdup (method->className); |
| // This was already strduped in _Jv_JNI_RegisterNatives. |
| slot->signature = method->signature; |
| slot->fnPtr = method->fnPtr; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass, |
| const JNINativeMethod *methods, |
| jint nMethods) |
| { |
| // Synchronize while we do the work. This must match |
| // synchronization in some other functions that manipulate or use |
| // the nathash table. |
| JvSynchronize sync (global_ref_table); |
| |
| NativeMethodCacheEntry dottedMethod; |
| |
| // Look at each descriptor given us, and find the corresponding |
| // method in the class. |
| for (int j = 0; j < nMethods; ++j) |
| { |
| bool found = false; |
| |
| _Jv_Method *imeths = JvGetFirstMethod (klass); |
| for (int i = 0; i < JvNumMethods (klass); ++i) |
| { |
| _Jv_Method *self = &imeths[i]; |
| |
| // Copy this JNINativeMethod and do a slash to dot |
| // conversion on the signature. |
| dottedMethod.name = methods[j].name; |
| // FIXME: we leak a little memory here if the method |
| // is not found. |
| dottedMethod.signature = strdup (methods[j].signature); |
| dottedMethod.fnPtr = methods[j].fnPtr; |
| dottedMethod.className = _Jv_GetClassNameUtf8 (klass)->chars(); |
| char *c = dottedMethod.signature; |
| while (*c) |
| { |
| if (*c == '/') |
| *c = '.'; |
| c++; |
| } |
| |
| if (! strcmp (self->name->chars (), dottedMethod.name) |
| && ! strcmp (self->signature->chars (), dottedMethod.signature)) |
| { |
| if (! (self->accflags & java::lang::reflect::Modifier::NATIVE)) |
| break; |
| |
| // Found a match that is native. |
| found = true; |
| nathash_add (&dottedMethod); |
| |
| break; |
| } |
| } |
| |
| if (! found) |
| { |
| jstring m = JvNewStringUTF (methods[j].name); |
| try |
| { |
| env->ex = new java::lang::NoSuchMethodError (m); |
| } |
| catch (jthrowable t) |
| { |
| env->ex = t; |
| } |
| return JNI_ERR; |
| } |
| } |
| |
| return JNI_OK; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_UnregisterNatives (JNIEnv *, jclass) |
| { |
| // FIXME -- we could implement this. |
| return JNI_ERR; |
| } |
| |
| |
| |
| // Add a character to the buffer, encoding properly. |
| static void |
| add_char (char *buf, jchar c, int *here) |
| { |
| if (c == '_') |
| { |
| buf[(*here)++] = '_'; |
| buf[(*here)++] = '1'; |
| } |
| else if (c == ';') |
| { |
| buf[(*here)++] = '_'; |
| buf[(*here)++] = '2'; |
| } |
| else if (c == '[') |
| { |
| buf[(*here)++] = '_'; |
| buf[(*here)++] = '3'; |
| } |
| |
| // Also check for `.' here because we might be passed an internal |
| // qualified class name like `foo.bar'. |
| else if (c == '/' || c == '.') |
| buf[(*here)++] = '_'; |
| else if ((c >= '0' && c <= '9') |
| || (c >= 'a' && c <= 'z') |
| || (c >= 'A' && c <= 'Z')) |
| buf[(*here)++] = (char) c; |
| else |
| { |
| // "Unicode" character. |
| buf[(*here)++] = '_'; |
| buf[(*here)++] = '0'; |
| for (int i = 0; i < 4; ++i) |
| { |
| int val = c & 0x0f; |
| buf[(*here) + 3 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val); |
| c >>= 4; |
| } |
| *here += 4; |
| } |
| } |
| |
| // Compute a mangled name for a native function. This computes the |
| // long name, and also returns an index which indicates where a NUL |
| // can be placed to create the short name. This function assumes that |
| // the buffer is large enough for its results. |
| static void |
| mangled_name (jclass klass, _Jv_Utf8Const *func_name, |
| _Jv_Utf8Const *signature, char *buf, int *long_start) |
| { |
| strcpy (buf, "Java_"); |
| int here = 5; |
| |
| // Add fully qualified class name. |
| jchar *chars = _Jv_GetStringChars (klass->getName ()); |
| jint len = klass->getName ()->length (); |
| for (int i = 0; i < len; ++i) |
| add_char (buf, chars[i], &here); |
| |
| // Don't use add_char because we need a literal `_'. |
| buf[here++] = '_'; |
| |
| const unsigned char *fn = (const unsigned char *) func_name->chars (); |
| const unsigned char *limit = fn + func_name->len (); |
| for (int i = 0; ; ++i) |
| { |
| int ch = UTF8_GET (fn, limit); |
| if (ch < 0) |
| break; |
| add_char (buf, ch, &here); |
| } |
| |
| // This is where the long signature begins. |
| *long_start = here; |
| buf[here++] = '_'; |
| buf[here++] = '_'; |
| |
| const unsigned char *sig = (const unsigned char *) signature->chars (); |
| limit = sig + signature->len (); |
| JvAssert (sig[0] == '('); |
| ++sig; |
| while (1) |
| { |
| int ch = UTF8_GET (sig, limit); |
| if (ch == ')' || ch < 0) |
| break; |
| add_char (buf, ch, &here); |
| } |
| |
| buf[here] = '\0'; |
| } |
| |
| JNIEnv * |
| _Jv_GetJNIEnvNewFrameWithLoader (::java::lang::ClassLoader *loader) |
| { |
| JNIEnv *env = _Jv_GetCurrentJNIEnv (); |
| if (__builtin_expect (env == NULL, false)) |
| { |
| env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); |
| env->functions = &_Jv_JNIFunctions; |
| env->locals = NULL; |
| // We set env->ex below. |
| |
| // Set up the bottom, reusable frame. |
| env->bottom_locals = (_Jv_JNI_LocalFrame *) |
| _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) |
| + (FRAME_SIZE |
| * sizeof (jobject))); |
| |
| env->bottom_locals->marker = MARK_SYSTEM; |
| env->bottom_locals->size = FRAME_SIZE; |
| env->bottom_locals->next = NULL; |
| env->bottom_locals->allocated_p = false; |
| // We set the klass field below. |
| memset (&env->bottom_locals->vec[0], 0, |
| env->bottom_locals->size * sizeof (jobject)); |
| |
| _Jv_SetCurrentJNIEnv (env); |
| } |
| |
| // If we're in a simple JNI call (non-nested), we can just reuse the |
| // locals frame we allocated many calls ago, back when the env was first |
| // built, above. |
| |
| if (__builtin_expect (env->locals == NULL, true)) |
| { |
| env->locals = env->bottom_locals; |
| env->locals->loader = loader; |
| } |
| else |
| { |
| // Alternatively, we might be re-entering JNI, in which case we can't |
| // reuse the bottom_locals frame, because it is already underneath |
| // us. So we need to make a new one. |
| _Jv_JNI_LocalFrame *frame |
| = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) |
| + (FRAME_SIZE |
| * sizeof (jobject))); |
| |
| frame->marker = MARK_SYSTEM; |
| frame->size = FRAME_SIZE; |
| frame->allocated_p = false; |
| frame->next = env->locals; |
| frame->loader = loader; |
| |
| memset (&frame->vec[0], 0, |
| frame->size * sizeof (jobject)); |
| |
| env->locals = frame; |
| } |
| |
| env->ex = NULL; |
| |
| return env; |
| } |
| |
| // Return the current thread's JNIEnv; if one does not exist, create |
| // it. Also create a new system frame for use. This is `extern "C"' |
| // because the compiler calls it. |
| extern "C" JNIEnv * |
| _Jv_GetJNIEnvNewFrame (jclass klass) |
| { |
| return _Jv_GetJNIEnvNewFrameWithLoader (klass->getClassLoaderInternal()); |
| } |
| |
| // Destroy the env's reusable resources. This is called from the thread |
| // destructor "finalize_native" in natThread.cc |
| void |
| _Jv_FreeJNIEnv (_Jv_JNIEnv *env) |
| { |
| if (env == NULL) |
| return; |
| |
| if (env->bottom_locals != NULL) |
| _Jv_Free (env->bottom_locals); |
| |
| _Jv_Free (env); |
| } |
| |
| // Return the function which implements a particular JNI method. If |
| // we can't find the function, we throw the appropriate exception. |
| // This is `extern "C"' because the compiler uses it. |
| extern "C" void * |
| _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name, |
| _Jv_Utf8Const *signature, MAYBE_UNUSED int args_size) |
| { |
| int name_length = name->len(); |
| int sig_length = signature->len(); |
| char buf[10 + 6 * (name_length + sig_length) + 12]; |
| int long_start; |
| void *function; |
| |
| // Synchronize on something convenient. Right now we use the hash. |
| JvSynchronize sync (global_ref_table); |
| |
| // First see if we have an override in the hash table. |
| strncpy (buf, name->chars (), name_length); |
| buf[name_length] = '\0'; |
| strncpy (buf + name_length + 1, signature->chars (), sig_length); |
| buf[name_length + sig_length + 1] = '\0'; |
| NativeMethodCacheEntry meth; |
| meth.name = buf; |
| meth.signature = buf + name_length + 1; |
| meth.className = _Jv_GetClassNameUtf8(klass)->chars(); |
| function = nathash_find (&meth); |
| if (function != NULL) |
| return function; |
| |
| // If there was no override, then look in the symbol table. |
| buf[0] = '_'; |
| mangled_name (klass, name, signature, buf + 1, &long_start); |
| char c = buf[long_start + 1]; |
| buf[long_start + 1] = '\0'; |
| |
| function = _Jv_FindSymbolInExecutable (buf + 1); |
| #ifdef WIN32 |
| // On Win32, we use the "stdcall" calling convention (see JNICALL |
| // in jni.h). |
| // |
| // For a function named 'fooBar' that takes 'nn' bytes as arguments, |
| // by default, MinGW GCC exports it as 'fooBar@nn', MSVC exports it |
| // as '_fooBar@nn' and Borland C exports it as 'fooBar'. We try to |
| // take care of all these variations here. |
| |
| char asz_buf[12]; /* '@' + '2147483647' (32-bit INT_MAX) + '\0' */ |
| char long_nm_sv[11]; /* Ditto, except for the '\0'. */ |
| |
| if (function == NULL) |
| { |
| // We have tried searching for the 'fooBar' form (BCC) - now |
| // try the others. |
| |
| // First, save the part of the long name that will be damaged |
| // by appending '@nn'. |
| memcpy (long_nm_sv, (buf + long_start + 1 + 1), sizeof (long_nm_sv)); |
| |
| sprintf (asz_buf, "@%d", args_size); |
| strcat (buf, asz_buf); |
| |
| // Search for the '_fooBar@nn' form (MSVC). |
| function = _Jv_FindSymbolInExecutable (buf); |
| |
| if (function == NULL) |
| { |
| // Search for the 'fooBar@nn' form (MinGW GCC). |
| function = _Jv_FindSymbolInExecutable (buf + 1); |
| } |
| } |
| #endif /* WIN32 */ |
| |
| if (function == NULL) |
| { |
| buf[long_start + 1] = c; |
| #ifdef WIN32 |
| // Restore the part of the long name that was damaged by |
| // appending the '@nn'. |
| memcpy ((buf + long_start + 1 + 1), long_nm_sv, sizeof (long_nm_sv)); |
| #endif /* WIN32 */ |
| function = _Jv_FindSymbolInExecutable (buf + 1); |
| if (function == NULL) |
| { |
| #ifdef WIN32 |
| strcat (buf, asz_buf); |
| function = _Jv_FindSymbolInExecutable (buf); |
| if (function == NULL) |
| function = _Jv_FindSymbolInExecutable (buf + 1); |
| |
| if (function == NULL) |
| #endif /* WIN32 */ |
| { |
| jstring str = JvNewStringUTF (name->chars ()); |
| throw new java::lang::UnsatisfiedLinkError (str); |
| } |
| } |
| } |
| |
| return function; |
| } |
| |
| #ifdef INTERPRETER |
| |
| // This function is the stub which is used to turn an ordinary (CNI) |
| // method call into a JNI call. |
| void |
| _Jv_JNIMethod::call (ffi_cif *, void *ret, INTERP_FFI_RAW_TYPE *args, |
| void *__this) |
| { |
| _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this; |
| |
| JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class); |
| |
| // FIXME: we should mark every reference parameter as a local. For |
| // now we assume a conservative GC, and we assume that the |
| // references are on the stack somewhere. |
| |
| // We cache the value that we find, of course, but if we don't find |
| // a value we don't cache that fact -- we might subsequently load a |
| // library which finds the function in question. |
| { |
| // Synchronize on a convenient object to ensure sanity in case two |
| // threads reach this point for the same function at the same |
| // time. |
| JvSynchronize sync (global_ref_table); |
| if (_this->function == NULL) |
| { |
| int args_size = sizeof (JNIEnv *) + _this->args_raw_size; |
| |
| if (_this->self->accflags & java::lang::reflect::Modifier::STATIC) |
| args_size += sizeof (_this->defining_class); |
| |
| _this->function = _Jv_LookupJNIMethod (_this->defining_class, |
| _this->self->name, |
| _this->self->signature, |
| args_size); |
| } |
| } |
| |
| JvAssert (_this->args_raw_size % sizeof (INTERP_FFI_RAW_TYPE) == 0); |
| INTERP_FFI_RAW_TYPE |
| real_args[2 + _this->args_raw_size / sizeof (INTERP_FFI_RAW_TYPE)]; |
| int offset = 0; |
| |
| // First argument is always the environment pointer. |
| real_args[offset++].ptr = env; |
| |
| // For a static method, we pass in the Class. For non-static |
| // methods, the `this' argument is already handled. |
| if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC)) |
| real_args[offset++].ptr = _this->defining_class; |
| |
| // In libgcj, the callee synchronizes. |
| jobject sync = NULL; |
| if ((_this->self->accflags & java::lang::reflect::Modifier::SYNCHRONIZED)) |
| { |
| if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC)) |
| sync = _this->defining_class; |
| else |
| sync = (jobject) args[0].ptr; |
| _Jv_MonitorEnter (sync); |
| } |
| |
| // Copy over passed-in arguments. |
| memcpy (&real_args[offset], args, _this->args_raw_size); |
| |
| // Add a frame to the composite (interpreted + JNI) call stack |
| java::lang::Thread *thread = java::lang::Thread::currentThread(); |
| _Jv_NativeFrame nat_frame (_this, thread); |
| |
| // The actual call to the JNI function. |
| #if FFI_NATIVE_RAW_API |
| ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function, |
| ret, real_args); |
| #else |
| ffi_java_raw_call (&_this->jni_cif, (void (*)()) _this->function, |
| ret, real_args); |
| #endif |
| |
| // We might need to unwrap a JNI weak reference here. |
| if (_this->jni_cif.rtype == &ffi_type_pointer) |
| { |
| _Jv_value *val = (_Jv_value *) ret; |
| val->object_value = unwrap (val->object_value); |
| } |
| |
| if (sync != NULL) |
| _Jv_MonitorExit (sync); |
| |
| _Jv_JNI_PopSystemFrame (env); |
| } |
| |
| #endif /* INTERPRETER */ |
| |
| |
| |
| // |
| // Invocation API. |
| // |
| |
| // An internal helper function. |
| static jint |
| _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, |
| void *args, jboolean is_daemon) |
| { |
| JavaVMAttachArgs *attach = reinterpret_cast<JavaVMAttachArgs *> (args); |
| java::lang::ThreadGroup *group = NULL; |
| |
| if (attach) |
| { |
| // FIXME: do we really want to support 1.1? |
| if (attach->version != JNI_VERSION_1_4 |
| && attach->version != JNI_VERSION_1_2 |
| && attach->version != JNI_VERSION_1_1) |
| return JNI_EVERSION; |
| |
| JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group)); |
| group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group); |
| } |
| |
| // Attaching an already-attached thread is a no-op. |
| JNIEnv *env = _Jv_GetCurrentJNIEnv (); |
| if (env != NULL) |
| { |
| *penv = reinterpret_cast<void *> (env); |
| return 0; |
| } |
| |
| env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); |
| if (env == NULL) |
| return JNI_ERR; |
| env->functions = &_Jv_JNIFunctions; |
| env->ex = NULL; |
| env->bottom_locals |
| = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) |
| + (FRAME_SIZE |
| * sizeof (jobject))); |
| env->locals = env->bottom_locals; |
| if (env->locals == NULL) |
| { |
| _Jv_Free (env); |
| return JNI_ERR; |
| } |
| |
| env->locals->allocated_p = false; |
| env->locals->marker = MARK_SYSTEM; |
| env->locals->size = FRAME_SIZE; |
| env->locals->loader = NULL; |
| env->locals->next = NULL; |
| |
| for (int i = 0; i < env->locals->size; ++i) |
| env->locals->vec[i] = NULL; |
| |
| *penv = reinterpret_cast<void *> (env); |
| |
| // This thread might already be a Java thread -- this function might |
| // have been called simply to set the new JNIEnv. |
| if (_Jv_ThreadCurrent () == NULL) |
| { |
| try |
| { |
| if (is_daemon) |
| _Jv_AttachCurrentThreadAsDaemon (name, group); |
| else |
| _Jv_AttachCurrentThread (name, group); |
| } |
| catch (jthrowable t) |
| { |
| return JNI_ERR; |
| } |
| } |
| _Jv_SetCurrentJNIEnv (env); |
| |
| return 0; |
| } |
| |
| // This is the one actually used by JNI. |
| jint JNICALL |
| _Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args) |
| { |
| return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, false); |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_AttachCurrentThreadAsDaemon (JavaVM *vm, void **penv, |
| void *args) |
| { |
| return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, true); |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_DestroyJavaVM (JavaVM *vm) |
| { |
| JvAssert (_Jv_the_vm && vm == _Jv_the_vm); |
| |
| union |
| { |
| JNIEnv *env; |
| void *env_p; |
| }; |
| |
| if (_Jv_ThreadCurrent () != NULL) |
| { |
| jstring main_name; |
| // This sucks. |
| try |
| { |
| main_name = JvNewStringLatin1 ("main"); |
| } |
| catch (jthrowable t) |
| { |
| return JNI_ERR; |
| } |
| |
| jint r = _Jv_JNI_AttachCurrentThread (vm, main_name, &env_p, |
| NULL, false); |
| if (r < 0) |
| return r; |
| } |
| else |
| env = _Jv_GetCurrentJNIEnv (); |
| |
| _Jv_ThreadWait (); |
| |
| // Docs say that this always returns an error code. |
| return JNI_ERR; |
| } |
| |
| jint JNICALL |
| _Jv_JNI_DetachCurrentThread (JavaVM *) |
| { |
| jint code = _Jv_DetachCurrentThread (); |
| return code ? JNI_EDETACHED : 0; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) |
| { |
| if (_Jv_ThreadCurrent () == NULL) |
| { |
| *penv = NULL; |
| return JNI_EDETACHED; |
| } |
| |
| #ifdef ENABLE_JVMPI |
| // Handle JVMPI requests. |
| if (version == JVMPI_VERSION_1) |
| { |
| *penv = (void *) &_Jv_JVMPI_Interface; |
| return 0; |
| } |
| #endif |
| |
| #ifdef INTERPRETER |
| // Handle JVMTI requests |
| if (version == JVMTI_VERSION_1_0) |
| { |
| *penv = (void *) _Jv_GetJVMTIEnv (); |
| return 0; |
| } |
| #endif |
| |
| // FIXME: do we really want to support 1.1? |
| if (version != JNI_VERSION_1_4 && version != JNI_VERSION_1_2 |
| && version != JNI_VERSION_1_1) |
| { |
| *penv = NULL; |
| return JNI_EVERSION; |
| } |
| |
| *penv = (void *) _Jv_GetCurrentJNIEnv (); |
| return 0; |
| } |
| |
| JavaVM * |
| _Jv_GetJavaVM () |
| { |
| // FIXME: synchronize |
| if (! _Jv_the_vm) |
| { |
| JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM)); |
| if (nvm != NULL) |
| nvm->functions = &_Jv_JNI_InvokeFunctions; |
| _Jv_the_vm = nvm; |
| } |
| |
| // If this is a Java thread, we want to make sure it has an |
| // associated JNIEnv. |
| if (_Jv_ThreadCurrent () != NULL) |
| { |
| void *ignore; |
| _Jv_JNI_AttachCurrentThread (_Jv_the_vm, &ignore, NULL); |
| } |
| |
| return _Jv_the_vm; |
| } |
| |
| static jint JNICALL |
| _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) |
| { |
| *vm = _Jv_GetJavaVM (); |
| return *vm == NULL ? JNI_ERR : JNI_OK; |
| } |
| |
| |
| |
| #define RESERVED NULL |
| |
| struct JNINativeInterface_ _Jv_JNIFunctions = |
| { |
| RESERVED, |
| RESERVED, |
| RESERVED, |
| RESERVED, |
| _Jv_JNI_GetVersion, // GetVersion |
| _Jv_JNI_DefineClass, // DefineClass |
| _Jv_JNI_FindClass, // FindClass |
| _Jv_JNI_FromReflectedMethod, // FromReflectedMethod |
| _Jv_JNI_FromReflectedField, // FromReflectedField |
| _Jv_JNI_ToReflectedMethod, // ToReflectedMethod |
| _Jv_JNI_GetSuperclass, // GetSuperclass |
| _Jv_JNI_IsAssignableFrom, // IsAssignableFrom |
| _Jv_JNI_ToReflectedField, // ToReflectedField |
| _Jv_JNI_Throw, // Throw |
| _Jv_JNI_ThrowNew, // ThrowNew |
| _Jv_JNI_ExceptionOccurred, // ExceptionOccurred |
| _Jv_JNI_ExceptionDescribe, // ExceptionDescribe |
| _Jv_JNI_ExceptionClear, // ExceptionClear |
| _Jv_JNI_FatalError, // FatalError |
| |
| _Jv_JNI_PushLocalFrame, // PushLocalFrame |
| _Jv_JNI_PopLocalFrame, // PopLocalFrame |
| _Jv_JNI_NewGlobalRef, // NewGlobalRef |
| _Jv_JNI_DeleteGlobalRef, // DeleteGlobalRef |
| _Jv_JNI_DeleteLocalRef, // DeleteLocalRef |
| |
| _Jv_JNI_IsSameObject, // IsSameObject |
| |
| _Jv_JNI_NewLocalRef, // NewLocalRef |
| _Jv_JNI_EnsureLocalCapacity, // EnsureLocalCapacity |
| |
| _Jv_JNI_AllocObject, // AllocObject |
| _Jv_JNI_NewObject, // NewObject |
| _Jv_JNI_NewObjectV, // NewObjectV |
| _Jv_JNI_NewObjectA, // NewObjectA |
| _Jv_JNI_GetObjectClass, // GetObjectClass |
| _Jv_JNI_IsInstanceOf, // IsInstanceOf |
| _Jv_JNI_GetAnyMethodID<false>, // GetMethodID |
| |
| _Jv_JNI_CallMethod<jobject>, // CallObjectMethod |
| _Jv_JNI_CallMethodV<jobject>, // CallObjectMethodV |
| _Jv_JNI_CallMethodA<jobject>, // CallObjectMethodA |
| _Jv_JNI_CallMethod<jboolean>, // CallBooleanMethod |
| _Jv_JNI_CallMethodV<jboolean>, // CallBooleanMethodV |
| _Jv_JNI_CallMethodA<jboolean>, // CallBooleanMethodA |
| _Jv_JNI_CallMethod<jbyte>, // CallByteMethod |
| _Jv_JNI_CallMethodV<jbyte>, // CallByteMethodV |
| _Jv_JNI_CallMethodA<jbyte>, // CallByteMethodA |
| _Jv_JNI_CallMethod<jchar>, // CallCharMethod |
| _Jv_JNI_CallMethodV<jchar>, // CallCharMethodV |
| _Jv_JNI_CallMethodA<jchar>, // CallCharMethodA |
| _Jv_JNI_CallMethod<jshort>, // CallShortMethod |
| _Jv_JNI_CallMethodV<jshort>, // CallShortMethodV |
| _Jv_JNI_CallMethodA<jshort>, // CallShortMethodA |
| _Jv_JNI_CallMethod<jint>, // CallIntMethod |
| _Jv_JNI_CallMethodV<jint>, // CallIntMethodV |
| _Jv_JNI_CallMethodA<jint>, // CallIntMethodA |
| _Jv_JNI_CallMethod<jlong>, // CallLongMethod |
| _Jv_JNI_CallMethodV<jlong>, // CallLongMethodV |
| _Jv_JNI_CallMethodA<jlong>, // CallLongMethodA |
| _Jv_JNI_CallMethod<jfloat>, // CallFloatMethod |
| _Jv_JNI_CallMethodV<jfloat>, // CallFloatMethodV |
| _Jv_JNI_CallMethodA<jfloat>, // CallFloatMethodA |
| _Jv_JNI_CallMethod<jdouble>, // CallDoubleMethod |
| _Jv_JNI_CallMethodV<jdouble>, // CallDoubleMethodV |
| _Jv_JNI_CallMethodA<jdouble>, // CallDoubleMethodA |
| _Jv_JNI_CallVoidMethod, // CallVoidMethod |
| _Jv_JNI_CallVoidMethodV, // CallVoidMethodV |
| _Jv_JNI_CallVoidMethodA, // CallVoidMethodA |
| |
| // Nonvirtual method invocation functions follow. |
| _Jv_JNI_CallAnyMethod<jobject, nonvirtual>, // CallNonvirtualObjectMethod |
| _Jv_JNI_CallAnyMethodV<jobject, nonvirtual>, // CallNonvirtualObjectMethodV |
| _Jv_JNI_CallAnyMethodA<jobject, nonvirtual>, // CallNonvirtualObjectMethodA |
| _Jv_JNI_CallAnyMethod<jboolean, nonvirtual>, // CallNonvirtualBooleanMethod |
| _Jv_JNI_CallAnyMethodV<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodV |
| _Jv_JNI_CallAnyMethodA<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodA |
| _Jv_JNI_CallAnyMethod<jbyte, nonvirtual>, // CallNonvirtualByteMethod |
| _Jv_JNI_CallAnyMethodV<jbyte, nonvirtual>, // CallNonvirtualByteMethodV |
| _Jv_JNI_CallAnyMethodA<jbyte, nonvirtual>, // CallNonvirtualByteMethodA |
| _Jv_JNI_CallAnyMethod<jchar, nonvirtual>, // CallNonvirtualCharMethod |
| _Jv_JNI_CallAnyMethodV<jchar, nonvirtual>, // CallNonvirtualCharMethodV |
| _Jv_JNI_CallAnyMethodA<jchar, nonvirtual>, // CallNonvirtualCharMethodA |
| _Jv_JNI_CallAnyMethod<jshort, nonvirtual>, // CallNonvirtualShortMethod |
| _Jv_JNI_CallAnyMethodV<jshort, nonvirtual>, // CallNonvirtualShortMethodV |
| _Jv_JNI_CallAnyMethodA<jshort, nonvirtual>, // CallNonvirtualShortMethodA |
| _Jv_JNI_CallAnyMethod<jint, nonvirtual>, // CallNonvirtualIntMethod |
| _Jv_JNI_CallAnyMethodV<jint, nonvirtual>, // CallNonvirtualIntMethodV |
| _Jv_JNI_CallAnyMethodA<jint, nonvirtual>, // CallNonvirtualIntMethodA |
| _Jv_JNI_CallAnyMethod<jlong, nonvirtual>, // CallNonvirtualLongMethod |
| _Jv_JNI_CallAnyMethodV<jlong, nonvirtual>, // CallNonvirtualLongMethodV |
| _Jv_JNI_CallAnyMethodA<jlong, nonvirtual>, // CallNonvirtualLongMethodA |
| _Jv_JNI_CallAnyMethod<jfloat, nonvirtual>, // CallNonvirtualFloatMethod |
| _Jv_JNI_CallAnyMethodV<jfloat, nonvirtual>, // CallNonvirtualFloatMethodV |
| _Jv_JNI_CallAnyMethodA<jfloat, nonvirtual>, // CallNonvirtualFloatMethodA |
| _Jv_JNI_CallAnyMethod<jdouble, nonvirtual>, // CallNonvirtualDoubleMethod |
| _Jv_JNI_CallAnyMethodV<jdouble, nonvirtual>, // CallNonvirtualDoubleMethodV |
| _Jv_JNI_CallAnyMethodA<jdouble, nonvirtual>, // CallNonvirtualDoubleMethodA |
| _Jv_JNI_CallAnyVoidMethod<nonvirtual>, // CallNonvirtualVoidMethod |
| _Jv_JNI_CallAnyVoidMethodV<nonvirtual>, // CallNonvirtualVoidMethodV |
| _Jv_JNI_CallAnyVoidMethodA<nonvirtual>, // CallNonvirtualVoidMethodA |
| |
| _Jv_JNI_GetAnyFieldID<false>, // GetFieldID |
| _Jv_JNI_GetField<jobject>, // GetObjectField |
| _Jv_JNI_GetField<jboolean>, // GetBooleanField |
| _Jv_JNI_GetField<jbyte>, // GetByteField |
| _Jv_JNI_GetField<jchar>, // GetCharField |
| _Jv_JNI_GetField<jshort>, // GetShortField |
| _Jv_JNI_GetField<jint>, // GetIntField |
| _Jv_JNI_GetField<jlong>, // GetLongField |
| _Jv_JNI_GetField<jfloat>, // GetFloatField |
| _Jv_JNI_GetField<jdouble>, // GetDoubleField |
| _Jv_JNI_SetField, // SetObjectField |
| _Jv_JNI_SetField, // SetBooleanField |
| _Jv_JNI_SetField, // SetByteField |
| _Jv_JNI_SetField, // SetCharField |
| _Jv_JNI_SetField, // SetShortField |
| _Jv_JNI_SetField, // SetIntField |
| _Jv_JNI_SetField, // SetLongField |
| _Jv_JNI_SetField, // SetFloatField |
| _Jv_JNI_SetField, // SetDoubleField |
| _Jv_JNI_GetAnyMethodID<true>, // GetStaticMethodID |
| |
| _Jv_JNI_CallStaticMethod<jobject>, // CallStaticObjectMethod |
| _Jv_JNI_CallStaticMethodV<jobject>, // CallStaticObjectMethodV |
| _Jv_JNI_CallStaticMethodA<jobject>, // CallStaticObjectMethodA |
| _Jv_JNI_CallStaticMethod<jboolean>, // CallStaticBooleanMethod |
| _Jv_JNI_CallStaticMethodV<jboolean>, // CallStaticBooleanMethodV |
| _Jv_JNI_CallStaticMethodA<jboolean>, // CallStaticBooleanMethodA |
| _Jv_JNI_CallStaticMethod<jbyte>, // CallStaticByteMethod |
| _Jv_JNI_CallStaticMethodV<jbyte>, // CallStaticByteMethodV |
| _Jv_JNI_CallStaticMethodA<jbyte>, // CallStaticByteMethodA |
| _Jv_JNI_CallStaticMethod<jchar>, // CallStaticCharMethod |
| _Jv_JNI_CallStaticMethodV<jchar>, // CallStaticCharMethodV |
| _Jv_JNI_CallStaticMethodA<jchar>, // CallStaticCharMethodA |
| _Jv_JNI_CallStaticMethod<jshort>, // CallStaticShortMethod |
| _Jv_JNI_CallStaticMethodV<jshort>, // CallStaticShortMethodV |
| _Jv_JNI_CallStaticMethodA<jshort>, // CallStaticShortMethodA |
| _Jv_JNI_CallStaticMethod<jint>, // CallStaticIntMethod |
| _Jv_JNI_CallStaticMethodV<jint>, // CallStaticIntMethodV |
| _Jv_JNI_CallStaticMethodA<jint>, // CallStaticIntMethodA |
| _Jv_JNI_CallStaticMethod<jlong>, // CallStaticLongMethod |
| _Jv_JNI_CallStaticMethodV<jlong>, // CallStaticLongMethodV |
| _Jv_JNI_CallStaticMethodA<jlong>, // CallStaticLongMethodA |
| _Jv_JNI_CallStaticMethod<jfloat>, // CallStaticFloatMethod |
| _Jv_JNI_CallStaticMethodV<jfloat>, // CallStaticFloatMethodV |
| _Jv_JNI_CallStaticMethodA<jfloat>, // CallStaticFloatMethodA |
| _Jv_JNI_CallStaticMethod<jdouble>, // CallStaticDoubleMethod |
| _Jv_JNI_CallStaticMethodV<jdouble>, // CallStaticDoubleMethodV |
| _Jv_JNI_CallStaticMethodA<jdouble>, // CallStaticDoubleMethodA |
| _Jv_JNI_CallStaticVoidMethod, // CallStaticVoidMethod |
| _Jv_JNI_CallStaticVoidMethodV, // CallStaticVoidMethodV |
| _Jv_JNI_CallStaticVoidMethodA, // CallStaticVoidMethodA |
| |
| _Jv_JNI_GetAnyFieldID<true>, // GetStaticFieldID |
| _Jv_JNI_GetStaticField<jobject>, // GetStaticObjectField |
| _Jv_JNI_GetStaticField<jboolean>, // GetStaticBooleanField |
| _Jv_JNI_GetStaticField<jbyte>, // GetStaticByteField |
| _Jv_JNI_GetStaticField<jchar>, // GetStaticCharField |
| _Jv_JNI_GetStaticField<jshort>, // GetStaticShortField |
| _Jv_JNI_GetStaticField<jint>, // GetStaticIntField |
| _Jv_JNI_GetStaticField<jlong>, // GetStaticLongField |
| _Jv_JNI_GetStaticField<jfloat>, // GetStaticFloatField |
| _Jv_JNI_GetStaticField<jdouble>, // GetStaticDoubleField |
| _Jv_JNI_SetStaticField, // SetStaticObjectField |
| _Jv_JNI_SetStaticField, // SetStaticBooleanField |
| _Jv_JNI_SetStaticField, // SetStaticByteField |
| _Jv_JNI_SetStaticField, // SetStaticCharField |
| _Jv_JNI_SetStaticField, // SetStaticShortField |
| _Jv_JNI_SetStaticField, // SetStaticIntField |
| _Jv_JNI_SetStaticField, // SetStaticLongField |
| _Jv_JNI_SetStaticField, // SetStaticFloatField |
| _Jv_JNI_SetStaticField, // SetStaticDoubleField |
| _Jv_JNI_NewString, // NewString |
| _Jv_JNI_GetStringLength, // GetStringLength |
| _Jv_JNI_GetStringChars, // GetStringChars |
| _Jv_JNI_ReleaseStringChars, // ReleaseStringChars |
| _Jv_JNI_NewStringUTF, // NewStringUTF |
| _Jv_JNI_GetStringUTFLength, // GetStringUTFLength |
| _Jv_JNI_GetStringUTFChars, // GetStringUTFChars |
| _Jv_JNI_ReleaseStringUTFChars, // ReleaseStringUTFChars |
| _Jv_JNI_GetArrayLength, // GetArrayLength |
| _Jv_JNI_NewObjectArray, // NewObjectArray |
| _Jv_JNI_GetObjectArrayElement, // GetObjectArrayElement |
| _Jv_JNI_SetObjectArrayElement, // SetObjectArrayElement |
| _Jv_JNI_NewPrimitiveArray<jboolean, JvPrimClass (boolean)>, |
| // NewBooleanArray |
| _Jv_JNI_NewPrimitiveArray<jbyte, JvPrimClass (byte)>, // NewByteArray |
| _Jv_JNI_NewPrimitiveArray<jchar, JvPrimClass (char)>, // NewCharArray |
| _Jv_JNI_NewPrimitiveArray<jshort, JvPrimClass (short)>, // NewShortArray |
| _Jv_JNI_NewPrimitiveArray<jint, JvPrimClass (int)>, // NewIntArray |
| _Jv_JNI_NewPrimitiveArray<jlong, JvPrimClass (long)>, // NewLongArray |
| _Jv_JNI_NewPrimitiveArray<jfloat, JvPrimClass (float)>, // NewFloatArray |
| _Jv_JNI_NewPrimitiveArray<jdouble, JvPrimClass (double)>, // NewDoubleArray |
| _Jv_JNI_GetPrimitiveArrayElements<jboolean, JvPrimClass (boolean)>, |
| // GetBooleanArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jbyte, JvPrimClass (byte)>, |
| // GetByteArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jchar, JvPrimClass (char)>, |
| // GetCharArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jshort, JvPrimClass (short)>, |
| // GetShortArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jint, JvPrimClass (int)>, |
| // GetIntArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jlong, JvPrimClass (long)>, |
| // GetLongArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jfloat, JvPrimClass (float)>, |
| // GetFloatArrayElements |
| _Jv_JNI_GetPrimitiveArrayElements<jdouble, JvPrimClass (double)>, |
| // GetDoubleArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jboolean, JvPrimClass (boolean)>, |
| // ReleaseBooleanArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jbyte, JvPrimClass (byte)>, |
| // ReleaseByteArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jchar, JvPrimClass (char)>, |
| // ReleaseCharArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jshort, JvPrimClass (short)>, |
| // ReleaseShortArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jint, JvPrimClass (int)>, |
| // ReleaseIntArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jlong, JvPrimClass (long)>, |
| // ReleaseLongArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jfloat, JvPrimClass (float)>, |
| // ReleaseFloatArrayElements |
| _Jv_JNI_ReleasePrimitiveArrayElements<jdouble, JvPrimClass (double)>, |
| // ReleaseDoubleArrayElements |
| _Jv_JNI_GetPrimitiveArrayRegion<jboolean, JvPrimClass (boolean)>, |
| // GetBooleanArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jbyte, JvPrimClass (byte)>, |
| // GetByteArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jchar, JvPrimClass (char)>, |
| // GetCharArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jshort, JvPrimClass (short)>, |
| // GetShortArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jint, JvPrimClass (int)>, |
| // GetIntArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jlong, JvPrimClass (long)>, |
| // GetLongArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jfloat, JvPrimClass (float)>, |
| // GetFloatArrayRegion |
| _Jv_JNI_GetPrimitiveArrayRegion<jdouble, JvPrimClass (double)>, |
| // GetDoubleArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jboolean, JvPrimClass (boolean)>, |
| // SetBooleanArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jbyte, JvPrimClass (byte)>, |
| // SetByteArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jchar, JvPrimClass (char)>, |
| // SetCharArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jshort, JvPrimClass (short)>, |
| // SetShortArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jint, JvPrimClass (int)>, |
| // SetIntArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jlong, JvPrimClass (long)>, |
| // SetLongArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jfloat, JvPrimClass (float)>, |
| // SetFloatArrayRegion |
| _Jv_JNI_SetPrimitiveArrayRegion<jdouble, JvPrimClass (double)>, |
| // SetDoubleArrayRegion |
| _Jv_JNI_RegisterNatives, // RegisterNatives |
| _Jv_JNI_UnregisterNatives, // UnregisterNatives |
| _Jv_JNI_MonitorEnter, // MonitorEnter |
| _Jv_JNI_MonitorExit, // MonitorExit |
| _Jv_JNI_GetJavaVM, // GetJavaVM |
| |
| _Jv_JNI_GetStringRegion, // GetStringRegion |
| _Jv_JNI_GetStringUTFRegion, // GetStringUTFRegion |
| _Jv_JNI_GetPrimitiveArrayCritical, // GetPrimitiveArrayCritical |
| _Jv_JNI_ReleasePrimitiveArrayCritical, // ReleasePrimitiveArrayCritical |
| _Jv_JNI_GetStringCritical, // GetStringCritical |
| _Jv_JNI_ReleaseStringCritical, // ReleaseStringCritical |
| |
| _Jv_JNI_NewWeakGlobalRef, // NewWeakGlobalRef |
| _Jv_JNI_DeleteWeakGlobalRef, // DeleteWeakGlobalRef |
| |
| _Jv_JNI_ExceptionCheck, // ExceptionCheck |
| |
| _Jv_JNI_NewDirectByteBuffer, // NewDirectByteBuffer |
| _Jv_JNI_GetDirectBufferAddress, // GetDirectBufferAddress |
| _Jv_JNI_GetDirectBufferCapacity, // GetDirectBufferCapacity |
| |
| _Jv_JNI_GetObjectRefType // GetObjectRefType |
| }; |
| |
| struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions = |
| { |
| RESERVED, |
| RESERVED, |
| RESERVED, |
| |
| _Jv_JNI_DestroyJavaVM, |
| _Jv_JNI_AttachCurrentThread, |
| _Jv_JNI_DetachCurrentThread, |
| _Jv_JNI_GetEnv, |
| _Jv_JNI_AttachCurrentThreadAsDaemon |
| }; |