This is the mail archive of the java-patches@sourceware.cygnus.com 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]

Patch: restructure JNI method finding


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 */

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