From 84973b27e8283fa75075f124ad4e6e14dc7726a4 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 14 Jan 2005 07:36:27 +0000 Subject: [PATCH] jni.h (_Jv_JNIEnv::bottom_locals): New field. 2005-01-13 Graydon Hoare * 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 | 8 ++++ libjava/include/jni.h | 4 ++ libjava/include/jvm.h | 3 ++ libjava/java/lang/natThread.cc | 1 + libjava/jni.cc | 103 ++++++++++++++++++++++++++++++++--------- 5 files changed, 98 insertions(+), 21 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 151ee65..40b9998 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,11 @@ +2005-01-13 Graydon Hoare + + * 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 PR libgcj/17784 diff --git a/libjava/include/jni.h b/libjava/include/jni.h index acffa97..c1b6e20 100644 --- a/libjava/include/jni.h +++ b/libjava/include/jni.h @@ -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); } diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index d45ef25..67a4b18 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -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 (); diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc index af33b0d..e79ab11 100644 --- a/libjava/java/lang/natThread.cc +++ b/libjava/java/lang/natThread.cc @@ -84,6 +84,7 @@ finalize_native (jobject ptr) #ifdef _Jv_HaveMutexDestroy _Jv_MutexDestroy (&nt->join_mutex); #endif + _Jv_FreeJNIEnv(nt->jni_env); } jint diff --git a/libjava/jni.cc b/libjava/jni.cc index 2f4c3e4..6e0ab89 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -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 *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; -- 2.7.4