jni.h (_Jv_JNIEnv::bottom_locals): New field.

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
This commit is contained in:
Graydon Hoare 2005-01-14 07:36:27 +00:00 committed by Graydon Hoare
parent a0ee8b5f99
commit 84973b27e8
5 changed files with 98 additions and 21 deletions

View 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

View 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); }

View 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 ();

View File

@ -84,6 +84,7 @@ finalize_native (jobject ptr)
#ifdef _Jv_HaveMutexDestroy
_Jv_MutexDestroy (&nt->join_mutex);
#endif
_Jv_FreeJNIEnv(nt->jni_env);
}
jint

View 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;