trans-stmt.c (compute_overall_iter_number): Enhance to precompute the number of inter...
[platform/upstream/gcc.git] / libjava / jni.cc
index 59b380c..c5c2b0f 100644 (file)
@@ -1,6 +1,6 @@
 // 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.
@@ -22,6 +22,7 @@ details.  */
 #ifdef ENABLE_JVMPI
 #include <jvmpi.h>
 #endif
+#include <jvmti.h>
 
 #include <java/lang/Class.h>
 #include <java/lang/ClassLoader.h>
@@ -107,7 +108,7 @@ static java::util::IdentityHashMap *local_ref_table;
 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.
@@ -226,6 +227,12 @@ unwrap (T *obj)
   return reinterpret_cast<T *> (wr->get ());
 }
 
+jobject
+_Jv_UnwrapJNIweakReference (jobject obj)
+{
+  return unwrap (obj);
+}
+
 \f
 
 static jobject JNICALL
@@ -242,6 +249,12 @@ _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);
 }
 
@@ -253,6 +266,11 @@ _Jv_JNI_DeleteLocalRef (JNIEnv *env, 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;
+
   for (frame = env->locals; frame != NULL; frame = frame->next)
     {
       for (int i = 0; i < frame->size; ++i)
@@ -552,7 +570,7 @@ _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
 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
@@ -1771,8 +1789,13 @@ _Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer)
 
 \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.
@@ -1782,11 +1805,15 @@ static int nathash_size = 0;
 
 // 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++;
@@ -1799,8 +1826,8 @@ hash (const JNINativeMethod *method)
 }
 
 // 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;
@@ -1809,7 +1836,7 @@ nathash_find_slot (const JNINativeMethod *method)
 
   for (;;)
     {
-      JNINativeMethod *slotp = &nathash[w];
+      NativeMethodCacheEntry *slotp = &nathash[w];
       if (slotp->name == NULL)
        {
          if (del >= 0)
@@ -1820,7 +1847,8 @@ nathash_find_slot (const JNINativeMethod *method)
       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);
     }
@@ -1828,11 +1856,11 @@ nathash_find_slot (const JNINativeMethod *method)
 
 // 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;
@@ -1845,23 +1873,23 @@ natrehash ()
     {
       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];
            }
        }
@@ -1869,16 +1897,17 @@ natrehash ()
 }
 
 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;
@@ -1894,7 +1923,7 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass,
   // 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.
@@ -1910,8 +1939,11 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass,
          // 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)
            {
@@ -2154,9 +2186,10 @@ _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name,
   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;
@@ -2304,6 +2337,13 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this)
                     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);
 
@@ -2339,10 +2379,14 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
     }
 
   // 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;
@@ -2391,7 +2435,7 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
 }
 
 // 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);
@@ -2407,9 +2451,14 @@ _Jv_JNI_AttachCurrentThreadAsDaemon (JavaVM *vm, void **penv,
 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;
@@ -2423,8 +2472,7 @@ _Jv_JNI_DestroyJavaVM (JavaVM *vm)
          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;
@@ -2463,6 +2511,13 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
     }
 #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)
@@ -2475,82 +2530,16 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
   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
@@ -2558,10 +2547,10 @@ _Jv_GetJavaVM ()
   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