jni.h (_Jv_JNIEnv::bottom_locals): New field.
authorGraydon Hoare <graydon@redhat.com>
Fri, 14 Jan 2005 07:36:27 +0000 (07:36 +0000)
committerGraydon Hoare <graydon@gcc.gnu.org>
Fri, 14 Jan 2005 07:36:27 +0000 (07:36 +0000)
2005-01-13  Graydon Hoare  <graydon@redhat.com>

* include/jni.h (_Jv_JNIEnv::bottom_locals): New field.
* include/jvm.h (_Jv_FreeJNIEnv): Declare.
* java/lang/natThread.cc (finalize_native): Call _Jv_FreeJNIEnv.
* jni.cc: Reuse bottom frame between calls, avoid clearing
frame when no local references are made.

From-SVN: r93632

libjava/ChangeLog
libjava/include/jni.h
libjava/include/jvm.h
libjava/java/lang/natThread.cc
libjava/jni.cc

index 151ee65..40b9998 100644 (file)
@@ -1,3 +1,11 @@
+2005-01-13  Graydon Hoare  <graydon@redhat.com>
+
+       * include/jni.h (_Jv_JNIEnv::bottom_locals): New field.
+       * include/jvm.h (_Jv_FreeJNIEnv): Declare.
+       * java/lang/natThread.cc (finalize_native): Call _Jv_FreeJNIEnv.
+       * jni.cc: Reuse bottom frame between calls, avoid clearing
+       frame when no local references are made.
+
 2005-01-13  Michael Koch  <konqueror@gmx.de>
 
        PR libgcj/17784
index acffa97..c1b6e20 100644 (file)
@@ -693,6 +693,10 @@ private:
   /* The chain of local frames.  */
   struct _Jv_JNI_LocalFrame *locals;
 
+  /* The bottom-most element of the chain, initialized with the env and
+     reused between non-nesting JNI calls.  */
+  struct _Jv_JNI_LocalFrame *bottom_locals;
+
 public:
   jint GetVersion ()
   { return p->GetVersion (this); }
index d45ef25..67a4b18 100644 (file)
@@ -522,6 +522,9 @@ extern void _Jv_JNI_Init (void);
 _Jv_JNIEnv *_Jv_GetCurrentJNIEnv ();
 void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *);
 
+/* Free a JNIEnv. */
+void _Jv_FreeJNIEnv (_Jv_JNIEnv *);
+
 struct _Jv_JavaVM;
 _Jv_JavaVM *_Jv_GetJavaVM (); 
 
index af33b0d..e79ab11 100644 (file)
@@ -84,6 +84,7 @@ finalize_native (jobject ptr)
 #ifdef _Jv_HaveMutexDestroy
   _Jv_MutexDestroy (&nt->join_mutex);
 #endif
+  _Jv_FreeJNIEnv(nt->jni_env);
 }
 
 jint
index 2f4c3e4..6e0ab89 100644 (file)
@@ -71,7 +71,7 @@ extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
 
 // Number of slots in the default frame.  The VM must allow at least
 // 16.
-#define FRAME_SIZE 32
+#define FRAME_SIZE 16
 
 // Mark value indicating this is an overflow frame.
 #define MARK_NONE    0
@@ -85,10 +85,13 @@ struct _Jv_JNI_LocalFrame
 {
   // This is true if this frame object represents a pushed frame (eg
   // from PushLocalFrame).
-  int marker :  2;
+  int marker;
+
+  // Flag to indicate some locals were allocated.
+  int allocated_p;
 
   // Number of elements in frame.
-  int size   : 30;
+  int size;
 
   // Next frame in chain.
   _Jv_JNI_LocalFrame *next;
@@ -289,6 +292,7 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
 
   frame->marker = MARK_NONE;
   frame->size = size;
+  frame->allocated_p = 0;
   memset (&frame->vec[0], 0, size * sizeof (jobject));
   frame->next = env->locals;
   env->locals = frame;
@@ -327,6 +331,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
              set = true;
              done = true;
              frame->vec[i] = obj;
+             frame->allocated_p = 1;
              break;
            }
        }
@@ -344,6 +349,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
       _Jv_JNI_EnsureLocalCapacity (env, 16);
       // We know the first element of the new frame will be ok.
       env->locals->vec[0] = obj;
+      env->locals->allocated_p = 1;
     }
 
   mark_for_gc (obj, local_ref_table);
@@ -366,12 +372,14 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
       done = (rf->marker == stop);
 
       _Jv_JNI_LocalFrame *n = rf->next;
-      // When N==NULL, we've reached the stack-allocated frame, and we
-      // must not free it.  However, we must be sure to clear all its
-      // elements, since we might conceivably reuse it.
+      // When N==NULL, we've reached the reusable bottom_locals, and we must
+      // not free it.  However, we must be sure to clear all its elements.
       if (n == NULL)
        {
-         memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
+         if (rf->allocated_p)
+           memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
+         rf->allocated_p = 0;
+         rf = NULL;
          break;
        }
 
@@ -412,9 +420,17 @@ _Jv_JNI_check_types (JNIEnv *env, JArray<T> *array, jclass K)
 extern "C" void
 _Jv_JNI_PopSystemFrame (JNIEnv *env)
 {
-  _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
+  // Only enter slow path when we're not at the bottom, or there have been
+  // allocations. Usually this is false and we can just null out the locals
+  // field.
 
-  if (env->ex)
+  if (__builtin_expect ((env->locals->next 
+                        || env->locals->allocated_p), false))
+    _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
+  else
+    env->locals = NULL;
+  
+  if (__builtin_expect (env->ex != NULL, false))
     {
       jthrowable t = env->ex;
       env->ex = NULL;
@@ -2030,7 +2046,7 @@ extern "C" JNIEnv *
 _Jv_GetJNIEnvNewFrame (jclass klass)
 {
   JNIEnv *env = _Jv_GetCurrentJNIEnv ();
-  if (env == NULL)
+  if (__builtin_expect (env == NULL, false))
     {
       env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
       env->p = &_Jv_JNIFunctions;
@@ -2038,27 +2054,70 @@ _Jv_GetJNIEnvNewFrame (jclass klass)
       env->locals = NULL;
       // We set env->ex below.
 
+      // Set up the bottom, reusable frame.
+      env->bottom_locals = (_Jv_JNI_LocalFrame *) 
+       _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+                            + (FRAME_SIZE
+                               * sizeof (jobject)));
+      
+      env->bottom_locals->marker = MARK_SYSTEM;
+      env->bottom_locals->size = FRAME_SIZE;
+      env->bottom_locals->next = NULL;
+      env->bottom_locals->allocated_p = 0;
+      memset (&env->bottom_locals->vec[0], 0, 
+             env->bottom_locals->size * sizeof (jobject));
+
       _Jv_SetCurrentJNIEnv (env);
     }
 
-  _Jv_JNI_LocalFrame *frame
-    = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
-                                                 + (FRAME_SIZE
-                                                    * sizeof (jobject)));
+  // If we're in a simple JNI call (non-nested), we can just reuse the
+  // locals frame we allocated many calls ago, back when the env was first
+  // built, above.
 
-  frame->marker = MARK_SYSTEM;
-  frame->size = FRAME_SIZE;
-  frame->next = env->locals;
+  if (__builtin_expect (env->locals == NULL, true))
+    env->locals = env->bottom_locals;
 
-  for (int i = 0; i < frame->size; ++i)
-    frame->vec[i] = NULL;
+  else
+    {
+      // Alternatively, we might be re-entering JNI, in which case we can't
+      // reuse the bottom_locals frame, because it is already underneath
+      // us. So we need to make a new one.
+
+      _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->allocated_p = 0;
+      frame->next = env->locals;
+
+      memset (&frame->vec[0], 0, 
+             frame->size * sizeof (jobject));
+
+      env->locals = frame;
+    }
 
-  env->locals = frame;
   env->ex = NULL;
 
   return env;
 }
 
+// Destroy the env's reusable resources. This is called from the thread
+// destructor "finalize_native" in natThread.cc
+void 
+_Jv_FreeJNIEnv (_Jv_JNIEnv *env)
+{
+  if (env == NULL)
+    return;
+
+  if (env->bottom_locals != NULL)
+    _Jv_Free (env->bottom_locals);
+
+  _Jv_Free (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.
@@ -2274,16 +2333,18 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
   env->p = &_Jv_JNIFunctions;
   env->ex = NULL;
   env->klass = NULL;
-  env->locals
+  env->bottom_locals
     = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
                                                  + (FRAME_SIZE
                                                     * sizeof (jobject)));
+  env->locals = env->bottom_locals;
   if (env->locals == NULL)
     {
       _Jv_Free (env);
       return JNI_ERR;
     }
 
+  env->locals->allocated_p = 0;
   env->locals->marker = MARK_SYSTEM;
   env->locals->size = FRAME_SIZE;
   env->locals->next = NULL;