Patch: restructure JNI method finding

Tom Tromey tromey@cygnus.com
Mon Mar 6 16:10:00 GMT 2000


I'm committing this patch.  It changes how JNI methods are found.  It
separates the functionality into several different functions, and it
changes the JNI implementation to always keep a single JNIEnv per
thread.  These changes are going to be used by the compiler when we
change it to generate stubs for JNI methods.

2000-03-06  Tom Tromey  <tromey@cygnus.com>

	* jni.cc (MARK_NONE): New define.
	(MARK_USER): Likewise.
	(MARK_SYSTEM): Likewise.
	(struct _Jv_JNI_LocalFrame): Made `marker' bigger and `size'
	smaller.
	(_Jv_JNI_DeleteLocalRef): Use MARK_NONE in assert.
	(_Jv_JNI_EnsureLocalCapacity): Use MARK_NONE.
	(_Jv_JNI_PushLocalFrame): Use MARK_USER.
	(_Jv_JNI_PopLocalFrame): New version with additional `stop'
	argument.
	(call): Use MARK_SYSTEM.
	(_Jv_GetJNIEnvNewFrame): New function.
	(_Jv_LookupJNIMethod): New function.
	(_Jv_JNI_PopSystemFrame): New function.
	(call): Use _Jv_JNI_PopSystemFrame and _Jv_LookupJNIMethod.

Tom

Index: jni.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/jni.cc,v
retrieving revision 1.24
diff -u -r1.24 jni.cc
--- jni.cc	2000/03/02 20:25:20	1.24
+++ jni.cc	2000/03/07 00:08:15
@@ -75,15 +75,22 @@
 // 16.
 #define FRAME_SIZE 32
 
+// 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 true if this frame object represents a pushed frame (eg
   // from PushLocalFrame).
-  int marker :  1;
+  int marker :  2;
 
   // Number of elements in frame.
-  int size   : 31;
+  int size   : 30;
 
   // Next frame in chain.
   _Jv_JNI_LocalFrame *next;
@@ -169,7 +176,7 @@
 	}
 
       // Don't go past a marked frame.
-      JvAssert (! frame->marker);
+      JvAssert (frame->marker == MARK_NONE);
     }
 
   JvAssert (0);
@@ -194,7 +201,7 @@
       return JNI_ERR;
     }
 
-  frame->marker = true;
+  frame->marker = MARK_NONE;
   frame->size = size;
   memset (&frame->vec[0], 0, size * sizeof (jobject));
   frame->next = env->locals;
@@ -211,7 +218,7 @@
     return r;
 
   // The new frame is on top.
-  env->locals->marker = true;
+  env->locals->marker = MARK_USER;
 
   return 0;
 }
@@ -248,7 +255,7 @@
 }
 
 static jobject
-_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
+_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
 {
   _Jv_JNI_LocalFrame *rf = env->locals;
 
@@ -260,7 +267,7 @@
 	  unmark_for_gc (rf->vec[i]);
 
       // If the frame we just freed is the marker frame, we are done.
-      done = rf->marker;
+      done = (rf->marker == stop);
 
       _Jv_JNI_LocalFrame *n = rf->next;
       // When N==NULL, we've reached the stack-allocated frame, and we
@@ -279,6 +286,20 @@
   return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result);
 }
 
+static jobject
+_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
+{
+  return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
+}
+
+// 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)
+{
+  _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
+}
+
 // 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.
@@ -1598,29 +1619,78 @@
   buf[here] = '\0';
 }
 
+// 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)
+{
+  JNIEnv *env = _Jv_GetCurrentJNIEnv ();
+  if (env == NULL)
+    {
+      env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
+      env->p = &_Jv_JNIFunctions;
+      env->ex = NULL;
+      env->klass = klass;
+      env->locals = NULL;
+
+      _Jv_SetCurrentJNIEnv (env);
+    }
+
+  _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->next = env->locals;
+  env->locals = frame;
+
+  for (int i = 0; i < frame->size; ++i)
+    frame->vec[i] = NULL;
+
+  return 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)
+{
+  char buf[10 + 6 * (name->length + signature->length)];
+  int long_start;
+  void *function;
+
+  mangled_name (klass, name, signature, buf, &long_start);
+  char c = buf[long_start];
+  buf[long_start] = '\0';
+  function = _Jv_FindSymbolInExecutable (buf);
+  if (function == NULL)
+    {
+      buf[long_start] = c;
+      function = _Jv_FindSymbolInExecutable (buf);
+      if (function == NULL)
+	{
+	  jstring str = JvNewStringUTF (name->data);
+	  JvThrow (new java::lang::AbstractMethodError (str));
+	}
+    }
+
+  return function;
+}
+
 // 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, ffi_raw *args, void *__this)
 {
   _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this;
-
-  JNIEnv env;
-  _Jv_JNI_LocalFrame *frame
-    = (_Jv_JNI_LocalFrame *) alloca (sizeof (_Jv_JNI_LocalFrame)
-				     + FRAME_SIZE * sizeof (jobject));
 
-  env.p = &_Jv_JNIFunctions;
-  env.ex = NULL;
-  env.klass = _this->defining_class;
-  env.locals = frame;
+  JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class);
 
-  frame->marker = true;
-  frame->next = NULL;
-  frame->size = FRAME_SIZE;
-  for (int i = 0; i < frame->size; ++i)
-    frame->vec[i] = NULL;
-
   // 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.
@@ -1629,33 +1699,16 @@
   // a value we don't cache that fact -- we might subsequently load a
   // library which finds the function in question.
   if (_this->function == NULL)
-    {
-      char buf[10 + 6 * (_this->self->name->length
-			 + _this->self->signature->length)];
-      int long_start;
-      mangled_name (_this->defining_class, _this->self->name,
-		    _this->self->signature, buf, &long_start);
-      char c = buf[long_start];
-      buf[long_start] = '\0';
-      _this->function = _Jv_FindSymbolInExecutable (buf);
-      if (_this->function == NULL)
-	{
-	  buf[long_start] = c;
-	  _this->function = _Jv_FindSymbolInExecutable (buf);
-	  if (_this->function == NULL)
-	    {
-	      jstring str = JvNewStringUTF (_this->self->name->data);
-	      JvThrow (new java::lang::AbstractMethodError (str));
-	    }
-	}
-    }
+    _this->function = _Jv_LookupJNIMethod (_this->defining_class,
+					   _this->self->name,
+					   _this->self->signature);
 
   JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
   ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)];
   int offset = 0;
 
   // First argument is always the environment pointer.
-  real_args[offset++].ptr = &env;
+  real_args[offset++].ptr = env;
 
   // For a static method, we pass in the Class.  For non-static
   // methods, the `this' argument is already handled.
@@ -1669,14 +1722,10 @@
   ffi_raw_call (&_this->jni_cif, (void (*) (...)) _this->function,
 		ret, real_args);
 
-  do
-    {
-      _Jv_JNI_PopLocalFrame (&env, NULL);
-    }
-  while (env.locals != frame);
+  _Jv_JNI_PopSystemFrame (env);
 
-  if (env.ex)
-    JvThrow (env.ex);
+  if (env->ex)
+    JvThrow (env->ex);
 }
 
 #endif /* INTERPRETER */


More information about the Java-patches mailing list