This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

strict jni checking


Hi,

This implements a couple of ideas from bug #19512 (Optional JNI error
checking). When enabled by setting the system property
gnu.gcj.jni=strict you will get output like this when some strict JNI
constraint fails:

Enabling strict (slow) JNI checks
java.lang.IllegalStateException: ! env->ex
   at Java_Native_a (/tmp/invbench/libNativeJNI.so)
   at Native.a(int, java.lang.Class) (Unknown Source)
   at Bench.Bench() (Unknown Source)
   at Bench.main(java.lang.String[]) (Unknown Source)
JNI check failure : ! env->ex
   in function _Jv_JNI_GetAnyMethodID, file /home/mark/src/gcc/libjava/jni.cc, line 803
Aborted

The checks implemented are:
- Check that the JNIEnv* used belongs to the current thread
- Check that no exception is pending when a JNI method is called that
  isn't a cleanup method.
- Check that '.' is not used in method and field descriptors.
- Check that the JNI localref frame isn't expanded automatically when
  not enough space is reserved by EnsureLocalCapacity().
- And the various assert check that were already in jni.cc.
  (They have been converted to the new JvJNIAssert macro.)

Not implemented is strict local ref checking (making sure that local
refs are only used when they are registered in the JNI frame of the
current thread). I did implement bits of it. We need to actually
register the arguments of the jni method. I added example code to do
this for the interpreted case. But we also need it for the native case.
In that case gcj compiles code to call _Jv_LookupJNIMethod() and then
jumps directly into that method. We could probably return a trampoline
when strict_jni is enabled that extracts and registers the method
arguments before calling into the actual function. Volunteers welcome!

I ran various programs with and without strict checking enabled to check
that it works like intended. Enabling checking makes some JNI methods a
little slower, but not really noticeable.

It also catches the buggy JNIEnv* usage in libgcj. There is a patch for
that on the gui branch and in GNU Classpath, but that hasn't been merged
to the trunk. So you cannot use -Dgnu.gcj.jni=strict with gtk+ AWT
programs currently.

Also included are some small fixlets. The important one is for
DeleteLocalRef(). This method should only delete the local ref from the
top frame. And it is a noop when the local ref isn't in the top frame.

2005-01-23  Mark Wielaard  <mark@klomp.org>

        * jni.cc: Add JvJNIAssert where appropriate. Consistently use JNI_OK.
        (strict_jni): New static bool.
        (_Jv_JNI_Init): Take bool argument, initialize strict_jni.
        (JvJNIAssert): New macro.
        (unwrap): Add comment and example about checking local refs.
        (_Jv_JNI_DeleteLocalRef): Only remove obj from top-frame.
        (_Jv_JNI_NewLocalRef): Return NULL when _Jv_JNI_EnsureLocalCapacity
        fails.
        (_Jv_JNI_PopLocalFrame): Not a JNICALL function.
        (_Jv_JNI_GetAnyMethodID): Improve NoSuchMethodException message.
        (_Jv_JNI_GetAnyFieldID): Improve NoSuchFieldException message.
        (_Jv_JNIMethod::call): Add comment and example for adding local refs
        to the JNI frame.
        * prims.cc (_Jv_CreateJavaVM): Call _Jv_JNI_Init() depending on
        gnu.gcj.jni system property being set.
        * include/jvm.h (_Jv_JNI_Init): Add bool argument to prototype.

OK to commit?

Cheers,

Mark
? include/semantic.cache
Index: jni.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni.cc,v
retrieving revision 1.93
diff -u -r1.93 jni.cc
--- jni.cc	14 Jan 2005 07:36:26 -0000	1.93
+++ jni.cc	22 Jan 2005 23:42:44 -0000
@@ -1,6 +1,6 @@
 // jni.cc - JNI implementation, including the jump table.
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation
 
    This file is part of libgcj.
@@ -13,6 +13,7 @@
 
 #include <stdio.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <gcj/cni.h>
@@ -40,6 +41,7 @@
 #include <java/lang/Integer.h>
 #include <java/lang/ThreadGroup.h>
 #include <java/lang/Thread.h>
+#include <java/lang/IllegalStateException.h>
 #include <java/lang/IllegalAccessError.h>
 #include <java/nio/Buffer.h>
 #include <java/nio/DirectByteBufferImpl.h>
@@ -108,6 +110,9 @@
 // The only VM.
 static JavaVM *the_vm;
 
+// Whether to check lots of things
+static bool strict_jni;
+
 #ifdef ENABLE_JVMPI
 // The only JVMPI interface description.
 static JVMPI_Interface _Jv_JVMPI_Interface;
@@ -156,11 +161,15 @@
 
 
 void
-_Jv_JNI_Init (void)
+_Jv_JNI_Init (bool strict)
 {
   local_ref_table = new java::util::IdentityHashMap;
   global_ref_table = new java::util::IdentityHashMap;
 
+  strict_jni = strict;
+  if (strict_jni)
+    fprintf(stderr, "Enabling strict (slow) JNI checks\n");
+
 #ifdef ENABLE_JVMPI
   _Jv_JVMPI_Interface.version = 1;
   _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent;
@@ -171,6 +180,23 @@
 #endif
 }
 
+#define JvJNIAssert(Expr) \
+do \
+  { \
+    if (__builtin_expect (strict_jni, false) && ! (Expr)) \
+      { \
+	using namespace java::lang; \
+	String *message = JvNewStringUTF (# Expr); \
+	Throwable *ex = new IllegalStateException (message); \
+	ex->printStackTrace (); \
+	fprintf (stderr, \
+	   "JNI check failure : %s\n   in function %s, file %s, line %d\n", \
+	   # Expr, __FUNCTION__, __FILE__, __LINE__); \
+	abort (); \
+      } \
+  } \
+while (0)
+
 // Tell the GC that a certain pointer is live.
 static void
 mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table)
@@ -192,9 +218,9 @@
 
   using namespace java::lang;
   Integer *refcount = (Integer *) ref_table->get (obj);
-  JvAssert (refcount);
+  JvJNIAssert (refcount);
   jint val = refcount->intValue () - 1;
-  JvAssert (val >= 0);
+  JvJNIAssert (val >= 0);
   if (val == 0)
     ref_table->remove (obj);
   else
@@ -216,6 +242,25 @@
 static T *
 unwrap (T *obj)
 {
+  // Make sure the reference is from either the local or global
+  // reference pool.
+  // XXX - We cannot currently enable this check since we don't
+  // register arguments to the native jni methods.
+#if 0
+  if (__builtin_expect (strict_jni, false) && obj != NULL)
+    {
+      bool local_ref_found = false;
+      _Jv_JNI_LocalFrame *frame;
+      JNIEnv *env = _Jv_GetCurrentJNIEnv ();
+      for (frame = env->locals; frame != NULL; frame = frame->next)
+	for (int i = 0; i < frame->size; ++i)
+	  if (frame->vec[i] == obj)
+	    local_ref_found = true;
+      
+      JvJNIAssert (local_ref_found || global_ref_table->containsKey (obj));
+    }
+#endif
+
   using namespace gnu::gcj::runtime;
   // We can compare the class directly because JNIWeakRef is `final'.
   // Doing it this way is much faster.
@@ -228,8 +273,11 @@
 
 
 static jobject JNICALL
-_Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj)
+_Jv_JNI_NewGlobalRef (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // This seems weird but I think it is correct.
   obj = unwrap (obj);
   mark_for_gc (obj, global_ref_table);
@@ -237,8 +285,11 @@
 }
 
 static void JNICALL
-_Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj)
+_Jv_JNI_DeleteGlobalRef (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   // This seems weird but I think it is correct.
   obj = unwrap (obj);
   unmark_for_gc (obj, global_ref_table);
@@ -247,33 +298,32 @@
 static void JNICALL
 _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj)
 {
-  _Jv_JNI_LocalFrame *frame;
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
 
   // This seems weird but I think it is correct.
   obj = unwrap (obj);
 
-  for (frame = env->locals; frame != NULL; frame = frame->next)
+  // Deletes the reference only from the top frame
+  // (if it is in that frame, otherwise this operation does nothing).
+  _Jv_JNI_LocalFrame *frame = env->locals;
+  for (int i = 0; i < frame->size; ++i)
     {
-      for (int i = 0; i < frame->size; ++i)
+      if (frame->vec[i] == obj)
 	{
-	  if (frame->vec[i] == obj)
-	    {
-	      frame->vec[i] = NULL;
-	      unmark_for_gc (obj, local_ref_table);
-	      return;
-	    }
+	  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)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // 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.
@@ -297,25 +347,31 @@
   frame->next = env->locals;
   env->locals = frame;
 
-  return 0;
+  return JNI_OK;
 }
 
 static jint JNICALL
 _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   jint r = _Jv_JNI_EnsureLocalCapacity (env, size);
-  if (r < 0)
+  if (r != JNI_OK)
     return r;
 
   // The new frame is on top.
   env->locals->marker = MARK_USER;
 
-  return 0;
+  return JNI_OK;
 }
 
 static jobject JNICALL
 _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // This seems weird but I think it is correct.
   obj = unwrap (obj);
 
@@ -342,11 +398,14 @@
 	break;
     }
 
+  // In strict mode we don't like the LocalRefs overflowing.
+  JvJNIAssert (set);
   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);
+      // No slots, so we allocate a new frame.
+      jint r = _Jv_JNI_EnsureLocalCapacity (env, 16);
+      if (r != JNI_OK)
+	return NULL;
       // We know the first element of the new frame will be ok.
       env->locals->vec[0] = obj;
       env->locals->allocated_p = 1;
@@ -356,7 +415,7 @@
   return obj;
 }
 
-static jobject JNICALL
+static jobject
 _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
 {
   _Jv_JNI_LocalFrame *rf = env->locals;
@@ -396,6 +455,9 @@
 static jobject JNICALL
 _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
 }
 
@@ -474,8 +536,11 @@
 
 
 static jint JNICALL
-_Jv_JNI_GetVersion (JNIEnv *)
+_Jv_JNI_GetVersion (JNIEnv *env)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return JNI_VERSION_1_4;
 }
 
@@ -483,6 +548,9 @@
 _Jv_JNI_DefineClass (JNIEnv *env, const char *name, jobject loader,
 		     const jbyte *buf, jsize bufLen)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       loader = unwrap (loader);
@@ -509,6 +577,9 @@
 static jclass JNICALL
 _Jv_JNI_FindClass (JNIEnv *env, const char *name)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // FIXME: assume that NAME isn't too long.
   int len = strlen (name);
   char s[len + 1];
@@ -545,32 +616,44 @@
 static jclass JNICALL
 _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ());
 }
 
 static jboolean JNICALL
-_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2)
+_Jv_JNI_IsAssignableFrom (JNIEnv *env, jclass clazz1, jclass clazz2)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
 }
 
 static jint JNICALL
 _Jv_JNI_Throw (JNIEnv *env, jthrowable obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // We check in case the user did some funky cast.
   obj = unwrap (obj);
-  JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
+  JvJNIAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
   env->ex = obj;
-  return 0;
+  return JNI_OK;
 }
 
 static jint JNICALL
 _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::lang::reflect;
 
   clazz = unwrap (clazz);
-  JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
+  JvJNIAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
 
   int r = JNI_OK;
   try
@@ -605,12 +688,18 @@
 static jthrowable JNICALL
 _Jv_JNI_ExceptionOccurred (JNIEnv *env)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   return (jthrowable) wrap_value (env, env->ex);
 }
 
 static void JNICALL
 _Jv_JNI_ExceptionDescribe (JNIEnv *env)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   if (env->ex != NULL)
     env->ex->printStackTrace();
 }
@@ -618,39 +707,54 @@
 static void JNICALL
 _Jv_JNI_ExceptionClear (JNIEnv *env)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   env->ex = NULL;
 }
 
 static jboolean JNICALL
 _Jv_JNI_ExceptionCheck (JNIEnv *env)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   return env->ex != NULL;
 }
 
 static void JNICALL
-_Jv_JNI_FatalError (JNIEnv *, const char *message)
+_Jv_JNI_FatalError (JNIEnv *env, const char *message)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be "safely" called when an exception is pending.
+
   JvFail (message);
 }
 
 
 
 static jboolean JNICALL
-_Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2)
+_Jv_JNI_IsSameObject (JNIEnv *env, jobject obj1, jobject obj2)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return unwrap (obj1) == unwrap (obj2);
 }
 
 static jobject JNICALL
 _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   jobject obj = NULL;
   using namespace java::lang::reflect;
 
   try
     {
       clazz = unwrap (clazz);
-      JvAssert (clazz && ! clazz->isArray ());
+      JvJNIAssert (clazz && ! clazz->isArray ());
       if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers()))
 	env->ex = new java::lang::InstantiationException ();
       else
@@ -667,14 +771,20 @@
 static jclass JNICALL
 _Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
-  JvAssert (obj);
+  JvJNIAssert (obj);
   return (jclass) wrap_value (env, obj->getClass());
 }
 
 static jboolean JNICALL
-_Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz)
+_Jv_JNI_IsInstanceOf (JNIEnv *env, jobject obj, jclass clazz)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return unwrap (clazz)->isInstance(unwrap (obj));
 }
 
@@ -689,21 +799,29 @@
 _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz,
 			const char *name, const char *sig)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       clazz = unwrap (clazz);
       _Jv_InitClass (clazz);
 
+      jclass method_clazz = 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];
+	{
+	  JvJNIAssert (sig[i] != '.');
+	  s[i] = (sig[i] == '/') ? '.' : sig[i];
+	}
       _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1);
 
-      JvAssert (! clazz->isPrimitive());
+      JvJNIAssert (! clazz->isPrimitive());
 
       using namespace java::lang::reflect;
 
@@ -727,7 +845,8 @@
 	}
 
       java::lang::StringBuffer *name_sig =
-        new java::lang::StringBuffer (JvNewStringUTF (name));
+        new java::lang::StringBuffer (method_clazz->toString ());
+      name_sig->append ((jchar) '.')->append (JvNewStringUTF (name));
       name_sig->append ((jchar) ' ')->append (JvNewStringUTF (s));
       env->ex = new java::lang::NoSuchMethodError (name_sig->toString ());
     }
@@ -753,10 +872,10 @@
       // 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));
+      JvJNIAssert (sizeof (int) >= sizeof (jint));
+      JvJNIAssert (sizeof (jlong) >= sizeof (int));
+      JvJNIAssert (sizeof (double) >= sizeof (jfloat));
+      JvJNIAssert (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))
@@ -788,11 +907,14 @@
 _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass,
 			jmethodID id, va_list vargs)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
   klass = unwrap (klass);
 
   jclass decl_class = klass ? klass : obj->getClass ();
-  JvAssert (decl_class != NULL);
+  JvJNIAssert (decl_class != NULL);
 
   jclass return_type;
   JArray<jclass> *arg_types;
@@ -845,11 +967,14 @@
 _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass,
 			jmethodID id, jvalue *args)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
   klass = unwrap (klass);
 
   jclass decl_class = klass ? klass : obj->getClass ();
-  JvAssert (decl_class != NULL);
+  JvJNIAssert (decl_class != NULL);
 
   jclass return_type;
   JArray<jclass> *arg_types;
@@ -894,11 +1019,14 @@
 _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass,
 			    jmethodID id, va_list vargs)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
   klass = unwrap (klass);
 
   jclass decl_class = klass ? klass : obj->getClass ();
-  JvAssert (decl_class != NULL);
+  JvJNIAssert (decl_class != NULL);
 
   jclass return_type;
   JArray<jclass> *arg_types;
@@ -942,8 +1070,11 @@
 _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass,
 			    jmethodID id, jvalue *args)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   jclass decl_class = klass ? klass : obj->getClass ();
-  JvAssert (decl_class != NULL);
+  JvJNIAssert (decl_class != NULL);
 
   jclass return_type;
   JArray<jclass> *arg_types;
@@ -1041,8 +1172,8 @@
 _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)));
+  JvJNIAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
+  JvJNIAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
 
   return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args);
 }
@@ -1057,8 +1188,8 @@
   va_list args;
   T result;
 
-  JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
-  JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
+  JvJNIAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
+  JvJNIAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
 
   va_start (args, id);
   result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass,
@@ -1075,8 +1206,8 @@
 _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id,
 			   jvalue *args)
 {
-  JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
-  JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
+  JvJNIAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
+  JvJNIAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
 
   return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args);
 }
@@ -1110,11 +1241,11 @@
 _Jv_JNI_NewObjectV (JNIEnv *env, jclass klass,
 		    jmethodID id, va_list args)
 {
-  JvAssert (klass && ! klass->isArray ());
-  JvAssert (! strcmp (id->name->data, "<init>")
-	    && id->signature->length > 2
-	    && id->signature->data[0] == '('
-	    && ! strcmp (&id->signature->data[id->signature->length - 2],
+  JvJNIAssert (klass && ! klass->isArray ());
+  JvJNIAssert (! strcmp (id->name->chars (), "<init>")
+	    && id->signature->len () > 2
+	    && id->signature->first () == '('
+	    && ! strcmp (&id->signature->chars ()[id->signature->len () - 2],
 			 ")V"));
 
   return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
@@ -1124,11 +1255,11 @@
 static jobject JNICALL
 _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...)
 {
-  JvAssert (klass && ! klass->isArray ());
-  JvAssert (! strcmp (id->name->data, "<init>")
-	    && id->signature->length > 2
-	    && id->signature->data[0] == '('
-	    && ! strcmp (&id->signature->data[id->signature->length - 2],
+  JvJNIAssert (klass && ! klass->isArray ());
+  JvJNIAssert (! strcmp (id->name->chars (), "<init>")
+	    && id->signature->len () > 2
+	    && id->signature->first () == '('
+	    && ! strcmp (&id->signature->chars ()[id->signature->len () - 2],
 			 ")V"));
 
   va_list args;
@@ -1146,11 +1277,11 @@
 _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id,
 		    jvalue *args)
 {
-  JvAssert (klass && ! klass->isArray ());
-  JvAssert (! strcmp (id->name->data, "<init>")
-	    && id->signature->length > 2
-	    && id->signature->data[0] == '('
-	    && ! strcmp (&id->signature->data[id->signature->length - 2],
+  JvJNIAssert (klass && ! klass->isArray ());
+  JvJNIAssert (! strcmp (id->name->chars (), "<init>")
+	    && id->signature->len () > 2
+	    && id->signature->first () == '('
+	    && ! strcmp (&id->signature->chars ()[id->signature->len () - 2],
 			 ")V"));
 
   return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
@@ -1163,20 +1294,26 @@
 static T JNICALL
 _Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
-  JvAssert (obj);
+  JvJNIAssert (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)
+_Jv_JNI_SetField (JNIEnv *env, jobject obj, jfieldID field, T value)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   obj = unwrap (obj);
   value = unwrap (value);
 
-  JvAssert (obj);
+  JvJNIAssert (obj);
   T *ptr = (T *) ((char *) obj + field->getOffset ());
   *ptr = value;
 }
@@ -1186,6 +1323,9 @@
 _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz,
 		       const char *name, const char *sig)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       clazz = unwrap (clazz);
@@ -1198,7 +1338,10 @@
       int len = strlen (sig);
       char s[len + 1];
       for (int i = 0; i <= len; ++i)
-	s[i] = (sig[i] == '/') ? '.' : sig[i];
+	{
+	  JvJNIAssert (sig[i] != '.');
+	  s[i] = (sig[i] == '/') ? '.' : sig[i];
+	}
       jclass field_class = _Jv_FindClassFromSignature ((char *) s, NULL);
 
       // FIXME: what if field_class == NULL?
@@ -1233,7 +1376,10 @@
 	  clazz = clazz->getSuperclass ();
 	}
 
-      env->ex = new java::lang::NoSuchFieldError ();
+      java::lang::StringBuffer *m = new java::lang::StringBuffer ();
+      m->append (field_class->toString ())->append (jchar (' '));
+      m->append (JvNewStringUTF (s));
+      env->ex = new java::lang::NoSuchFieldError (m->toString ());
     }
   catch (jthrowable t)
     {
@@ -1246,14 +1392,20 @@
 static T JNICALL
 _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   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)
+_Jv_JNI_SetStaticField (JNIEnv *env, jclass, jfieldID field, T value)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   value = unwrap (value);
   T *ptr = (T *) field->u.addr;
   *ptr = value;
@@ -1262,6 +1414,9 @@
 static jstring JNICALL
 _Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       jstring r = _Jv_NewString (unichars, len);
@@ -1275,14 +1430,20 @@
 }
 
 static jsize JNICALL
-_Jv_JNI_GetStringLength (JNIEnv *, jstring string)
+_Jv_JNI_GetStringLength (JNIEnv *env, jstring string)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return unwrap (string)->length();
 }
 
 static const jchar * JNICALL
-_Jv_JNI_GetStringChars (JNIEnv *, jstring string, jboolean *isCopy)
+_Jv_JNI_GetStringChars (JNIEnv *env, jstring string, jboolean *isCopy)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   string = unwrap (string);
   jchar *result = _Jv_GetStringChars (string);
   mark_for_gc (string, global_ref_table);
@@ -1292,14 +1453,20 @@
 }
 
 static void JNICALL
-_Jv_JNI_ReleaseStringChars (JNIEnv *, jstring string, const jchar *)
+_Jv_JNI_ReleaseStringChars (JNIEnv *env, jstring string, const jchar *)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   unmark_for_gc (unwrap (string), global_ref_table);
 }
 
 static jstring JNICALL
 _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       jstring result = JvNewStringUTF (bytes);
@@ -1313,8 +1480,11 @@
 }
 
 static jsize JNICALL
-_Jv_JNI_GetStringUTFLength (JNIEnv *, jstring string)
+_Jv_JNI_GetStringUTFLength (JNIEnv *env, jstring string)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return JvGetStringUTFLength (unwrap (string));
 }
 
@@ -1322,6 +1492,9 @@
 _Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, 
 			   jboolean *isCopy)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       string = unwrap (string);
@@ -1345,8 +1518,11 @@
 }
 
 static void JNICALL
-_Jv_JNI_ReleaseStringUTFChars (JNIEnv *, jstring, const char *utf)
+_Jv_JNI_ReleaseStringUTFChars (JNIEnv *env, jstring, const char *utf)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   _Jv_Free ((void *) utf);
 }
 
@@ -1354,6 +1530,9 @@
 _Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, 
 			 jsize len, jchar *buf)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   string = unwrap (string);
   jchar *result = _Jv_GetStringChars (string);
   if (start < 0 || start > string->length ()
@@ -1376,6 +1555,9 @@
 _Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start,
 			    jsize len, char *buf)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   str = unwrap (str);
     
   if (start < 0 || start > str->length ()
@@ -1395,8 +1577,11 @@
 }
 
 static const jchar * JNICALL
-_Jv_JNI_GetStringCritical (JNIEnv *, jstring str, jboolean *isCopy)
+_Jv_JNI_GetStringCritical (JNIEnv *env, jstring str, jboolean *isCopy)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   jchar *result = _Jv_GetStringChars (unwrap (str));
   if (isCopy)
     *isCopy = false;
@@ -1404,14 +1589,20 @@
 }
 
 static void JNICALL
-_Jv_JNI_ReleaseStringCritical (JNIEnv *, jstring, const jchar *)
+_Jv_JNI_ReleaseStringCritical (JNIEnv *env, jstring, const jchar *)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   // Nothing.
 }
 
 static jsize JNICALL
-_Jv_JNI_GetArrayLength (JNIEnv *, jarray array)
+_Jv_JNI_GetArrayLength (JNIEnv *env, jarray array)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   return unwrap (array)->length;
 }
 
@@ -1419,6 +1610,9 @@
 _Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, 
 			jclass elementClass, jobject init)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       elementClass = unwrap (elementClass);
@@ -1439,6 +1633,9 @@
 _Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array, 
 			       jsize index)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   if ((unsigned) index >= (unsigned) array->length)
     _Jv_ThrowBadArrayIndex (index);
   jobject *elts = elements (unwrap (array));
@@ -1449,6 +1646,9 @@
 _Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, 
 			       jsize index, jobject value)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       array = unwrap (array);
@@ -1470,6 +1670,9 @@
 static JArray<T> * JNICALL
 _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       return (JArray<T> *) wrap_value (env, _Jv_NewPrimArray (K, length));
@@ -1486,6 +1689,9 @@
 _Jv_JNI_GetPrimitiveArrayElements (JNIEnv *env, JArray<T> *array,
 				   jboolean *isCopy)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   array = unwrap (array);
   if (! _Jv_JNI_check_types (env, array, K))
     return NULL;
@@ -1504,6 +1710,9 @@
 _Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *env, JArray<T> *array,
 				       T *, jint /* mode */)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   array = unwrap (array);
   _Jv_JNI_check_types (env, array, K);
   // Note that we ignore MODE.  We can do this because we never copy
@@ -1518,6 +1727,9 @@
 				 jsize start, jsize len,
 				 T *buf)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   array = unwrap (array);
   if (! _Jv_JNI_check_types (env, array, K))
     return;
@@ -1549,6 +1761,9 @@
 _Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array,
 				 jsize start, jsize len, T *buf)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   array = unwrap (array);
   if (! _Jv_JNI_check_types (env, array, K))
     return;
@@ -1575,13 +1790,16 @@
 }
 
 static void * JNICALL
-_Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array,
+_Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *env, jarray array,
 				   jboolean *isCopy)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   array = unwrap (array);
   // FIXME: does this work?
   jclass klass = array->getClass()->getComponentType();
-  JvAssert (klass->isPrimitive ());
+  JvJNIAssert (klass->isPrimitive ());
   char *r = _Jv_GetArrayElementFromElementType (array, klass);
   if (isCopy)
     *isCopy = false;
@@ -1589,18 +1807,24 @@
 }
 
 static void JNICALL
-_Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint)
+_Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *env, jarray, void *, jint)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   // Nothing.
 }
 
 static jint JNICALL
 _Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       _Jv_MonitorEnter (unwrap (obj));
-      return 0;
+      return JNI_OK;
     }
   catch (jthrowable t)
     {
@@ -1612,10 +1836,13 @@
 static jint JNICALL
 _Jv_JNI_MonitorExit (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   try
     {
       _Jv_MonitorExit (unwrap (obj));
-      return 0;
+      return JNI_OK;
     }
   catch (jthrowable t)
     {
@@ -1629,6 +1856,9 @@
 _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID,
 			  jboolean)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   try
     {
       cls = unwrap (cls);
@@ -1647,8 +1877,11 @@
 
 // JDK 1.2
 static jfieldID JNICALL
-_Jv_JNI_FromReflectedField (JNIEnv *, jobject f)
+_Jv_JNI_FromReflectedField (JNIEnv *env, jobject f)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::lang::reflect;
 
   f = unwrap (f);
@@ -1660,6 +1893,9 @@
 _Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id,
 			   jboolean)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::lang::reflect;
 
   jobject result = NULL;
@@ -1692,8 +1928,11 @@
 }
 
 static jmethodID JNICALL
-_Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method)
+_Jv_JNI_FromReflectedMethod (JNIEnv *env, jobject method)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::lang::reflect;
   method = unwrap (method);
   if (Method::class$.isInstance (method))
@@ -1706,6 +1945,9 @@
 jweak JNICALL
 _Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace gnu::gcj::runtime;
   JNIWeakRef *ref = NULL;
 
@@ -1725,8 +1967,11 @@
 }
 
 void JNICALL
-_Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj)
+_Jv_JNI_DeleteWeakGlobalRef (JNIEnv *env, jweak obj)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  // Can be safely called even when exception is pending.
+
   using namespace gnu::gcj::runtime;
   JNIWeakRef *ref = reinterpret_cast<JNIWeakRef *> (obj);
   unmark_for_gc (ref, global_ref_table);
@@ -1738,8 +1983,11 @@
 // Direct byte buffers.
 
 static jobject JNICALL
-_Jv_JNI_NewDirectByteBuffer (JNIEnv *, void *address, jlong length)
+_Jv_JNI_NewDirectByteBuffer (JNIEnv *env, void *address, jlong length)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace gnu::gcj;
   using namespace java::nio;
   return new DirectByteBufferImpl$ReadWrite
@@ -1747,8 +1995,11 @@
 }
 
 static void * JNICALL
-_Jv_JNI_GetDirectBufferAddress (JNIEnv *, jobject buffer)
+_Jv_JNI_GetDirectBufferAddress (JNIEnv *env, jobject buffer)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::nio;
   if (! _Jv_IsInstanceOf (buffer, &Buffer::class$))
     return NULL;
@@ -1757,8 +2008,11 @@
 }
 
 static jlong JNICALL
-_Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer)
+_Jv_JNI_GetDirectBufferCapacity (JNIEnv *env, jobject buffer)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   using namespace java::nio;
   if (! _Jv_IsInstanceOf (buffer, &Buffer::class$))
     return -1;
@@ -1889,6 +2143,9 @@
 			 const JNINativeMethod *methods,
 			 jint nMethods)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // Synchronize while we do the work.  This must match
   // synchronization in some other functions that manipulate or use
   // the nathash table.
@@ -1938,8 +2195,11 @@
 }
 
 static jint JNICALL
-_Jv_JNI_UnregisterNatives (JNIEnv *, jclass)
+_Jv_JNI_UnregisterNatives (JNIEnv *env, jclass)
 {
+  JvJNIAssert (env == _Jv_GetCurrentJNIEnv ());
+  JvJNIAssert (! env->ex);
+
   // FIXME -- we could implement this.
   return JNI_ERR;
 }
@@ -2026,7 +2286,7 @@
 
   const unsigned char *sig = (const unsigned char *) signature->chars ();
   limit = sig + signature->len ();
-  JvAssert (sig[0] == '(');
+  JvJNIAssert (sig[0] == '(');
   ++sig;
   while (1)
     {
@@ -2232,6 +2492,9 @@
   // now we assume a conservative GC, and we assume that the
   // references are on the stack somewhere.
 
+  // With strict_jni on, we do register all arguments explicitly below,
+  // but this is slow.
+
   // 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.
@@ -2254,7 +2517,7 @@
       }
   }
 
-  JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
+  JvJNIAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
   ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)];
   int offset = 0;
 
@@ -2280,6 +2543,29 @@
   // Copy over passed-in arguments.
   memcpy (&real_args[offset], args, _this->args_raw_size);
 
+  // For strict JNI checking we need all arguments in the local frame.
+  // Except the JNIEnv*.
+  // XXX - We don't enable this yet since we don't have a method yet
+  // for registering the arguments of JNI methods called directly from
+  // compiled code.  We could possibly handle those by making a
+  // trampoline in _Jv_LookupJNIMethod.
+#if 0
+  if (__builtin_expect (strict_jni, false))
+    {
+      ffi_cif cif = _this->jni_cif;
+      int pargs = 0;
+      for (unsigned int i = 1; i < cif.nargs; i++)
+	{
+	  if (cif.arg_types[i]->type == FFI_TYPE_POINTER)
+	    {
+	      jobject obj = (jobject) (real_args[i].ptr);
+	      env->locals->vec[pargs++] = obj;
+	      mark_for_gc (obj, local_ref_table);
+	    }
+	}
+    }
+#endif
+
   // The actual call to the JNI function.
 #if FFI_NATIVE_RAW_API
   ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function,
@@ -2319,13 +2605,13 @@
 	  && attach->version != JNI_VERSION_1_1)
 	return JNI_EVERSION;
 
-      JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group));
+      JvJNIAssert (java::lang::ThreadGroup::class$.isInstance (attach->group));
       group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group);
     }
 
   // Attaching an already-attached thread is a no-op.
   if (_Jv_GetCurrentJNIEnv () != NULL)
-    return 0;
+    return JNI_OK;
 
   JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
   if (env == NULL)
@@ -2372,7 +2658,7 @@
     }
   _Jv_SetCurrentJNIEnv (env);
 
-  return 0;
+  return JNI_OK;
 }
 
 // This is the one actually used by JNI.
@@ -2392,7 +2678,7 @@
 static jint JNICALL
 _Jv_JNI_DestroyJavaVM (JavaVM *vm)
 {
-  JvAssert (the_vm && vm == the_vm);
+  JvJNIAssert (the_vm && vm == the_vm);
 
   JNIEnv *env;
   if (_Jv_ThreadCurrent () != NULL)
@@ -2427,7 +2713,7 @@
 _Jv_JNI_DetachCurrentThread (JavaVM *)
 {
   jint code = _Jv_DetachCurrentThread ();
-  return code  ? JNI_EDETACHED : 0;
+  return code  ? JNI_EDETACHED : JNI_OK;
 }
 
 static jint JNICALL
@@ -2444,7 +2730,7 @@
   if (version == JVMPI_VERSION_1)
     {
       *penv = (void *) &_Jv_JVMPI_Interface;
-      return 0;
+      return JNI_OK;
     }
 #endif
 
@@ -2457,7 +2743,7 @@
     }
 
   *penv = (void *) _Jv_GetCurrentJNIEnv ();
-  return 0;
+  return JNI_OK;
 }
 
 jint JNICALL
@@ -2474,13 +2760,13 @@
   ia->options = NULL;
   ia->ignoreUnrecognized = true;
 
-  return 0;
+  return JNI_OK;
 }
 
 jint JNICALL
 JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
 {
-  JvAssert (! the_vm);
+  JvJNIAssert (! the_vm);
 
   _Jv_CreateJavaVM (NULL);
 
@@ -2539,7 +2825,7 @@
   the_vm = nvm;
   *vm = the_vm;
 
-  return 0;
+  return JNI_OK;
 }
 
 jint JNICALL
@@ -2556,7 +2842,7 @@
     }
   else
     *n_vms = 0;
-  return 0;
+  return JNI_OK;
 }
 
 JavaVM *
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.101
diff -u -r1.101 prims.cc
--- prims.cc	10 Jan 2005 19:39:25 -0000	1.101
+++ prims.cc	22 Jan 2005 23:42:44 -0000
@@ -980,7 +980,12 @@
 
   _Jv_platform_initialize ();
 
-  _Jv_JNI_Init ();
+  _Jv_InitClass (&java::lang::System::class$);
+  java::util::Properties *props = java::lang::System::properties;
+  if (props->get (JvNewStringLatin1 ("gnu.gcj.jni")))
+    _Jv_JNI_Init (true);
+  else
+    _Jv_JNI_Init (false);
 
   _Jv_GCInitializeFinalizers (&::gnu::gcj::runtime::FinalizerThread::finalizerReady);
 
Index: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.74
diff -u -r1.74 jvm.h
--- include/jvm.h	14 Jan 2005 07:36:27 -0000	1.74
+++ include/jvm.h	22 Jan 2005 23:42:44 -0000
@@ -515,8 +515,9 @@
 /* Return a pointer to a symbol in executable or loaded library.  */
 void *_Jv_FindSymbolInExecutable (const char *);
 
-/* Initialize JNI.  */
-extern void _Jv_JNI_Init (void);
+/* Initialize JNI.
+   If strict is true lots of extra (slow) checks are done.  */
+extern void _Jv_JNI_Init (bool strict);
 
 /* Get or set the per-thread JNIEnv used by the invocation API.  */
 _Jv_JNIEnv *_Jv_GetCurrentJNIEnv ();

Attachment: signature.asc
Description: This is a digitally signed message part


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]