// jni.cc - JNI implementation, including the jump table.
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation
This file is part of libgcj.
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
#endif
+#include <jvmti.h>
#include <java/lang/Class.h>
#include <java/lang/ClassLoader.h>
static java::util::IdentityHashMap *global_ref_table;
// The only VM.
-static JavaVM *the_vm;
+JavaVM *_Jv_the_vm;
#ifdef ENABLE_JVMPI
// The only JVMPI interface description.
return reinterpret_cast<T *> (wr->get ());
}
+jobject
+_Jv_UnwrapJNIweakReference (jobject obj)
+{
+ return unwrap (obj);
+}
+
\f
static jobject JNICALL
{
// 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);
}
// 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)
static jboolean JNICALL
_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2)
{
- return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
+ return unwrap (clazz2)->isAssignableFrom (unwrap (clazz1));
}
static jint JNICALL
\f
+struct NativeMethodCacheEntry : public JNINativeMethod
+{
+ char *className;
+};
+
// Hash table of native methods.
-static JNINativeMethod *nathash;
+static NativeMethodCacheEntry *nathash;
// Number of slots used.
static int nathash_count = 0;
// Number of slots available. Must be power of 2.
// Compute a hash value for a native method descriptor.
static int
-hash (const JNINativeMethod *method)
+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++;
}
// Find the slot where a native method goes.
-static JNINativeMethod *
-nathash_find_slot (const JNINativeMethod *method)
+static NativeMethodCacheEntry *
+nathash_find_slot (const NativeMethodCacheEntry *method)
{
jint h = hash (method);
int step = (h ^ (h >> 16)) | 1;
for (;;)
{
- JNINativeMethod *slotp = &nathash[w];
+ NativeMethodCacheEntry *slotp = &nathash[w];
if (slotp->name == NULL)
{
if (del >= 0)
else if (slotp->name == DELETED_ENTRY)
del = w;
else if (! strcmp (slotp->name, method->name)
- && ! strcmp (slotp->signature, method->signature))
+ && ! 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 (JNINativeMethod *method)
+nathash_find (NativeMethodCacheEntry *method)
{
if (nathash == NULL)
return NULL;
- JNINativeMethod *slot = nathash_find_slot (method);
+ NativeMethodCacheEntry *slot = nathash_find_slot (method);
if (slot->name == NULL || slot->name == DELETED_ENTRY)
return NULL;
return slot->fnPtr;
{
nathash_size = 1024;
nathash =
- (JNINativeMethod *) _Jv_AllocBytes (nathash_size
- * sizeof (JNINativeMethod));
+ (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size
+ * sizeof (NativeMethodCacheEntry));
}
else
{
int savesize = nathash_size;
- JNINativeMethod *savehash = nathash;
+ NativeMethodCacheEntry *savehash = nathash;
nathash_size *= 2;
nathash =
- (JNINativeMethod *) _Jv_AllocBytes (nathash_size
- * sizeof (JNINativeMethod));
+ (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size
+ * sizeof (NativeMethodCacheEntry));
for (int i = 0; i < savesize; ++i)
{
if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY)
{
- JNINativeMethod *slot = nathash_find_slot (&savehash[i]);
+ NativeMethodCacheEntry *slot = nathash_find_slot (&savehash[i]);
*slot = savehash[i];
}
}
}
static void
-nathash_add (const JNINativeMethod *method)
+nathash_add (const NativeMethodCacheEntry *method)
{
if (3 * nathash_count >= 2 * nathash_size)
natrehash ();
- JNINativeMethod *slot = nathash_find_slot (method);
+ 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
+ // 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;
// the nathash table.
JvSynchronize sync (global_ref_table);
- JNINativeMethod dottedMethod;
+ NativeMethodCacheEntry dottedMethod;
// Look at each descriptor given us, and find the corresponding
// method in the class.
// 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)
{
buf[name_length] = '\0';
strncpy (buf + name_length + 1, signature->chars (), sig_length);
buf[name_length + sig_length + 1] = '\0';
- JNINativeMethod meth;
+ 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;
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);
}
// Attaching an already-attached thread is a no-op.
- if (_Jv_GetCurrentJNIEnv () != NULL)
- return 0;
+ JNIEnv *env = _Jv_GetCurrentJNIEnv ();
+ if (env != NULL)
+ {
+ *penv = reinterpret_cast<void *> (env);
+ return 0;
+ }
- JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
+ env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
if (env == NULL)
return JNI_ERR;
env->p = &_Jv_JNIFunctions;
}
// This is the one actually used by JNI.
-static jint JNICALL
+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_DestroyJavaVM (JavaVM *vm)
{
- JvAssert (the_vm && vm == the_vm);
+ JvAssert (_Jv_the_vm && vm == _Jv_the_vm);
+
+ union
+ {
+ JNIEnv *env;
+ void *env_p;
+ };
- JNIEnv *env;
if (_Jv_ThreadCurrent () != NULL)
{
jstring main_name;
return JNI_ERR;
}
- jint r = _Jv_JNI_AttachCurrentThread (vm, main_name,
- reinterpret_cast<void **> (&env),
+ jint r = _Jv_JNI_AttachCurrentThread (vm, main_name, &env_p,
NULL, false);
if (r < 0)
return r;
}
#endif
+ // Handle JVMTI requests
+ if (version == JVMTI_VERSION_1_0)
+ {
+ *penv = (void *) _Jv_GetJVMTIEnv ();
+ return 0;
+ }
+
// 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)
return 0;
}
-jint JNICALL
-JNI_GetDefaultJavaVMInitArgs (void *args)
-{
- jint version = * (jint *) args;
- // Here we only support 1.2 and 1.4.
- if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4)
- return JNI_EVERSION;
-
- JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
- ia->version = JNI_VERSION_1_4;
- ia->nOptions = 0;
- ia->options = NULL;
- ia->ignoreUnrecognized = true;
-
- return 0;
-}
-
-jint JNICALL
-JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
-{
- JvAssert (! the_vm);
-
- jint version = * (jint *) args;
- // We only support 1.2 and 1.4.
- if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4)
- return JNI_EVERSION;
-
- JvVMInitArgs* vm_args = reinterpret_cast<JvVMInitArgs *> (args);
-
- jint result = _Jv_CreateJavaVM (vm_args);
- if (result)
- return result;
-
- // FIXME: synchronize
- JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
- if (nvm == NULL)
- return JNI_ERR;
- nvm->functions = &_Jv_JNI_InvokeFunctions;
-
- jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL);
- if (r < 0)
- return r;
-
- the_vm = nvm;
- *vm = the_vm;
-
- return 0;
-}
-
-jint JNICALL
-JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms)
-{
- if (buf_len <= 0)
- return JNI_ERR;
-
- // We only support a single VM.
- if (the_vm != NULL)
- {
- vm_buffer[0] = the_vm;
- *n_vms = 1;
- }
- else
- *n_vms = 0;
- return 0;
-}
-
JavaVM *
_Jv_GetJavaVM ()
{
// FIXME: synchronize
- if (! the_vm)
+ if (! _Jv_the_vm)
{
JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
if (nvm != NULL)
nvm->functions = &_Jv_JNI_InvokeFunctions;
- the_vm = nvm;
+ _Jv_the_vm = nvm;
}
// If this is a Java thread, we want to make sure it has an
if (_Jv_ThreadCurrent () != NULL)
{
void *ignore;
- _Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL);
+ _Jv_JNI_AttachCurrentThread (_Jv_the_vm, &ignore, NULL);
}
- return the_vm;
+ return _Jv_the_vm;
}
static jint JNICALL