Patch: invocation API
Tom Tromey
tromey@cygnus.com
Thu Feb 10 12:30:00 GMT 2000
I'm committing the appended patch. It implements most of the
invocation API, which is part of JNI.
JNI *still* doesn't work, but I'm reaching testing range at long last,
I think.
2000-02-10 Tom Tromey <tromey@cygnus.com>
* gnu/gcj/jni/natNativeThread.cc: New file.
* gnu/gcj/jni/NativeThread.java: New file.
* java/lang/Thread.java (data): Now a RawData.
* include/jvm.h (_Jv_GetCurrentJNIEnv, _Jv_SetCurrentJNIEnv):
Declare.
* Makefile.in: Rebuilt.
* Makefile.am (java/lang/Thread.h): New target.
(ordinary_java_source_files): Added NativeThread.java.
(nat_source_files): Added natNativeThread.cc.
* java/lang/natThread.cc: Include <jni.h>
(struct natThread): Added `jni_env' field.
(_Jv_GetCurrentJNIEnv): New function.
(_Jv_SetCurrentJNIEnv): Likewise.
(initialize_native): Initialize jni_env.
Include RawData.h.
* jni.cc (ThreadGroupClass): New define.
(_Jv_JNI_InvokeFunctions): New structure.
(JNI_GetCreatedJavaVMs): New function.
(the_vm): New global.
(JNI_GetDefaultJavaVMInitArgs): New function.
Include NativeThread.h.
(NativeThreadClass): New define.
(_Jv_JNI_EnsureLocalCapacity): Return JNI_ERR, not -1.
(_Jv_JNI_DestroyJavaVM): New function.
(_Jv_JNI_AttachCurrentThread): New function.
(_Jv_JNI_DetachCurrentThread): New function.
(_Jv_JNI_GetEnv): New function.
(JNI_CreateJavaVM): New function.
(_Jv_JNI_GetJavaVM): New function.
(_Jv_JNIFunctions): Added entry for GetJavaVM.
* include/jni.h (JavaVMAttachArgs): New structure.
(JNI_EDETACHED): New define.
(JNI_EVERSION): Likewise.
(JavaVM): Define properly.
(struct JNIInvokeInterface): New structure.
(class _Jv_JavaVM): New class.
(JNI_OnLoad, JNI_OnUnload): Declare.
(JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM,
JNI_GetCreatedJavaVMs): Declare.
(JavaVMInitArgs): New typedef.
(JavaVMOption): Likewise.
(JNI_ERR): New define.
(JNI_OK): Likewise.
Tom
Index: Makefile.am
===================================================================
RCS file: /cvs/java/libgcj/libjava/Makefile.am,v
retrieving revision 1.46
diff -u -r1.46 Makefile.am
--- Makefile.am 2000/02/04 22:00:35 1.46
+++ Makefile.am 2000/02/10 20:19:35
@@ -221,6 +221,16 @@
-friend 'void _Jv_RunMain (const char*, int, const char **);' \
$(basename $<)
+java/lang/Thread.h: java/lang/Thread.class libgcj.zip
+ $(GCJH) -classpath $(top_builddir) \
+ -prepend 'class _Jv_JNIEnv;' \
+## Eww.
+ -prepend 'extern "Java" { namespace gnu { namespace gcj { namespace jni { class NativeThread; } } } };' \
+ -friend '_Jv_JNIEnv * _Jv_GetCurrentJNIEnv ();' \
+ -friend 'void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env);' \
+ -friend 'class gnu::gcj::jni::NativeThread;' \
+ $(basename $<)
+
java/lang/String.h: java/lang/String.class libgcj.zip
$(GCJH) -classpath $(top_builddir) \
-friend 'jchar* _Jv_GetStringChars (jstring str);' \
@@ -512,6 +522,7 @@
## convert_source_files. If the .java file has a hand-maintained
## header, please list it in special_java_source_files.
ordinary_java_source_files = $(convert_source_files) \
+gnu/gcj/jni/NativeThread.java \
gnu/gcj/runtime/MethodInvocation.java \
gnu/gcj/runtime/VMClassLoader.java \
gnu/gcj/text/BaseBreakIterator.java \
@@ -796,6 +807,7 @@
gnu/gcj/convert/natInput_SJIS.cc \
gnu/gcj/convert/natOutput_EUCJIS.cc \
gnu/gcj/convert/natOutput_SJIS.cc \
+gnu/gcj/jni/natNativeThread.cc \
java/io/natFile.cc \
java/io/natFileDescriptor.cc \
java/lang/natCharacter.cc \
Index: jni.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/jni.cc,v
retrieving revision 1.12
diff -u -r1.12 jni.cc
--- jni.cc 2000/02/08 00:23:09 1.12
+++ jni.cc 2000/02/10 20:19:52
@@ -36,6 +36,7 @@
#include <java/lang/OutOfMemoryError.h>
#include <java/util/Hashtable.h>
#include <java/lang/Integer.h>
+#include <gnu/gcj/jni/NativeThread.h>
#include <gcj/method.h>
#include <gcj/field.h>
@@ -51,6 +52,10 @@
extern java::lang::Class ThrowableClass;
#define MethodClass _CL_Q44java4lang7reflect6Method
extern java::lang::Class MethodClass;
+#define ThreadGroupClass _CL_Q34java4lang11ThreadGroup
+extern java::lang::Class ThreadGroupClass;
+#define NativeThreadClass _CL_Q43gnu3gcj3jni12NativeThread
+extern java::lang::Class ThreadGroupClass;
// This enum is used to select different template instantiations in
// the invocation code.
@@ -62,8 +67,9 @@
constructor
};
-// Forward declaration.
+// Forward declarations.
extern struct JNINativeInterface _Jv_JNIFunctions;
+extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
// Number of slots in the default frame. The VM must allow at least
// 16.
@@ -89,6 +95,9 @@
// This holds a reference count for all local and global references.
static java::util::Hashtable *ref_table;
+// The only VM.
+static JavaVM *the_vm;
+
void
@@ -178,7 +187,7 @@
{
// FIXME: exception processing.
env->ex = new java::lang::OutOfMemoryError;
- return -1;
+ return JNI_ERR;
}
frame->marker = true;
@@ -1380,6 +1389,238 @@
+//
+// Invocation API.
+//
+
+// An internal helper function.
+static jint
+_Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args)
+{
+ JavaVMAttachArgs *attach = reinterpret_cast<JavaVMAttachArgs *> (args);
+ java::lang::ThreadGroup *group = NULL;
+
+ if (attach)
+ {
+ // FIXME: do we really want to support 1.1?
+ if (attach->version != JNI_VERSION_1_2
+ && attach->version != JNI_VERSION_1_1)
+ return JNI_EVERSION;
+
+ JvAssert ((&ThreadGroupClass)->isInstance (attach->group));
+ group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group);
+ }
+
+ // Attaching an already-attached thread is a no-op.
+ if (_Jv_ThreadCurrent () != NULL)
+ return 0;
+
+ // FIXME: NULL return?
+ JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
+ env->p = &_Jv_JNIFunctions;
+ env->ex = NULL;
+ env->klass = NULL;
+ // FIXME: NULL return?
+ env->locals
+ = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ + (FRAME_SIZE
+ * sizeof (jobject)));
+ *penv = reinterpret_cast<void *> (env);
+
+ java::lang::Thread *t = new gnu::gcj::jni::NativeThread (group, name);
+ t = t; // Avoid compiler warning. Eww.
+ _Jv_SetCurrentJNIEnv (env);
+
+ return 0;
+}
+
+// This is the one actually used by JNI.
+static jint
+_Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args)
+{
+ return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args);
+}
+
+static jint
+_Jv_JNI_DestroyJavaVM (JavaVM *vm)
+{
+ JvAssert (the_vm && vm == the_vm);
+
+ JNIEnv *env;
+ if (_Jv_ThreadCurrent () != NULL)
+ {
+ jint r = _Jv_JNI_AttachCurrentThread (vm,
+ JvNewStringLatin1 ("main"),
+ reinterpret_cast<void **> (&env),
+ NULL);
+ if (r < 0)
+ return r;
+ }
+ else
+ env = _Jv_GetCurrentJNIEnv ();
+
+ _Jv_ThreadWait ();
+
+ // Docs say that this always returns an error code.
+ return JNI_ERR;
+}
+
+static jint
+_Jv_JNI_DetachCurrentThread (JavaVM *)
+{
+ java::lang::Thread *t = _Jv_ThreadCurrent ();
+ if (t == NULL)
+ return JNI_EDETACHED;
+
+ // FIXME: we only allow threads attached via AttachCurrentThread to
+ // be detached. I have no idea how we could implement detaching
+ // other threads, given the requirement that we must release all the
+ // monitors. That just seems evil.
+ JvAssert ((&NativeThreadClass)->isInstance (t));
+
+ // FIXME: release the monitors. We'll take this to mean all
+ // monitors acquired via the JNI interface. This means we have to
+ // keep track of them.
+
+ gnu::gcj::jni::NativeThread *nt
+ = reinterpret_cast<gnu::gcj::jni::NativeThread *> (t);
+ nt->finish ();
+
+ return 0;
+}
+
+static jint
+_Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
+{
+ if (_Jv_ThreadCurrent () == NULL)
+ {
+ *penv = NULL;
+ return JNI_EDETACHED;
+ }
+
+ // FIXME: do we really want to support 1.1?
+ if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1)
+ {
+ *penv = NULL;
+ return JNI_EVERSION;
+ }
+
+ *penv = (void *) _Jv_GetCurrentJNIEnv ();
+ return 0;
+}
+
+jint
+JNI_GetDefaultJavaVMInitArgs (void *args)
+{
+ jint version = * (jint *) args;
+ // Here we only support 1.2.
+ if (version != JNI_VERSION_1_2)
+ return JNI_EVERSION;
+
+ JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
+ ia->version = JNI_VERSION_1_2;
+ ia->nOptions = 0;
+ ia->options = NULL;
+ ia->ignoreUnrecognized = true;
+
+ return 0;
+}
+
+jint
+JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
+{
+ JvAssert (! the_vm);
+ // FIXME: synchronize
+ JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
+ if (nvm == NULL)
+ return JNI_ERR;
+ nvm->functions = &_Jv_JNI_InvokeFunctions;
+
+ // Parse the arguments.
+ if (args != NULL)
+ {
+ jint version = * (jint *) args;
+ // We only support 1.2.
+ if (version != JNI_VERSION_1_2)
+ return JNI_EVERSION;
+ JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
+ for (int i = 0; i < ia->nOptions; ++i)
+ {
+ if (! strcmp (ia->options[i].optionString, "vfprintf")
+ || ! strcmp (ia->options[i].optionString, "exit")
+ || ! strcmp (ia->options[i].optionString, "abort"))
+ {
+ // We are required to recognize these, but for now we
+ // don't handle them in any way. FIXME.
+ continue;
+ }
+ else if (! strncmp (ia->options[i].optionString,
+ "-verbose", sizeof ("-verbose") - 1))
+ {
+ // We don't do anything with this option either. We
+ // might want to make sure the argument is valid, but we
+ // don't really care all that much for now.
+ continue;
+ }
+ else if (! strncmp (ia->options[i].optionString, "-D", 2))
+ {
+ // FIXME.
+ continue;
+ }
+ else if (ia->ignoreUnrecognized)
+ {
+ if (ia->options[i].optionString[0] == '_'
+ || ! strncmp (ia->options[i].optionString, "-X", 2))
+ continue;
+ }
+
+ return JNI_ERR;
+ }
+ }
+
+ jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL);
+ if (r < 0)
+ return r;
+
+ the_vm = nvm;
+ *vm = the_vm;
+ return 0;
+}
+
+jint
+JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms)
+{
+ JvAssert (buf_len > 0);
+ // We only support a single VM.
+ if (the_vm != NULL)
+ {
+ vm_buffer[0] = the_vm;
+ *n_vms = 1;
+ }
+ else
+ *n_vms = 0;
+ return 0;
+}
+
+jint
+_Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm)
+{
+ // FIXME: synchronize
+ if (! the_vm)
+ {
+ JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
+ if (nvm == NULL)
+ return JNI_ERR;
+ nvm->functions = &_Jv_JNI_InvokeFunctions;
+ the_vm = nvm;
+ }
+
+ *vm = the_vm;
+ return 0;
+}
+
+
+
#define NOT_IMPL NULL
#define RESERVED NULL
@@ -1614,7 +1855,7 @@
NOT_IMPL /* UnregisterNatives */,
_Jv_JNI_MonitorEnter,
_Jv_JNI_MonitorExit,
- NOT_IMPL /* GetJavaVM */,
+ _Jv_JNI_GetJavaVM,
_Jv_JNI_GetStringRegion,
_Jv_JNI_GetStringUTFRegion,
@@ -1627,4 +1868,16 @@
NOT_IMPL /* deleteweakglobalref */,
_Jv_JNI_ExceptionCheck
+};
+
+struct JNIInvokeInterface _Jv_JNI_InvokeFunctions =
+{
+ RESERVED,
+ RESERVED,
+ RESERVED,
+
+ _Jv_JNI_DestroyJavaVM,
+ _Jv_JNI_AttachCurrentThread,
+ _Jv_JNI_DetachCurrentThread,
+ _Jv_JNI_GetEnv
};
Index: gnu/gcj/jni/NativeThread.java
===================================================================
RCS file: NativeThread.java
diff -N NativeThread.java
--- /dev/null Tue May 5 13:32:27 1998
+++ NativeThread.java Thu Feb 10 12:19:57 2000
@@ -0,0 +1,28 @@
+// NativeThread.java - Wrapper for attached user threads.
+
+/* Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.jni;
+
+/**
+ * @author Tom Tromey <tromey@cygnus.com>
+ * @date February 9, 2000
+ */
+
+public class NativeThread extends Thread
+{
+ public NativeThread (ThreadGroup g, String name)
+ {
+ super (g, null, name);
+ alive_flag = true;
+ }
+
+ // Call this to mark the thread as finished.
+ public native void finish ();
+}
Index: gnu/gcj/jni/natNativeThread.cc
===================================================================
RCS file: natNativeThread.cc
diff -N natNativeThread.cc
--- /dev/null Tue May 5 13:32:27 1998
+++ natNativeThread.cc Thu Feb 10 12:19:57 2000
@@ -0,0 +1,24 @@
+// natNativeThread.cc - Native side of attached threads.
+
+/* Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+// Written by Tom Tromey <tromey@cygnus.com>
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <gnu/gcj/jni/NativeThread.h>
+#include <java/lang/Thread.h>
+
+void
+gnu::gcj::jni::NativeThread::finish ()
+{
+ finish_ ();
+}
Index: include/jni.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/jni.h,v
retrieving revision 1.9
diff -u -r1.9 jni.h
--- jni.h 2000/02/02 01:47:01 1.9
+++ jni.h 2000/02/10 20:20:13
@@ -23,6 +23,7 @@
#include <gcj/javaprims.h>
typedef struct _Jv_JNIEnv JNIEnv;
+typedef struct _Jv_JavaVM JavaVM;
#define JNI_TRUE true
#define JNI_FALSE false
@@ -59,6 +60,7 @@
typedef void *jmethodID;
typedef const struct JNINativeInterface *JNIEnv;
+typedef const struct JNIInvokeInterface *JavaVM;
#define JNI_TRUE 1
#define JNI_TRUE 0
@@ -76,6 +78,32 @@
#define JNI_COMMIT 1
#define JNI_ABORT 2
+/* Error codes */
+#define JNI_OK 0
+#define JNI_ERR -1
+#define JNI_EDETACHED -2
+#define JNI_EVERSION -3
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/* These functions might be defined in libraries which we load; the
+ JNI implementation calls them at the appropriate times. */
+extern jint JNI_OnLoad (JavaVM *, void *);
+extern void JNI_OnUnload (JavaVM *, void *);
+
+/* These functions are called by user code to start using the
+ invocation API. */
+extern jint JNI_GetDefaultJavaVMInitArgs (void *);
+extern jint JNI_CreateJavaVM (JavaVM **, void **, void *);
+extern jint JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
+
+#ifdef __cplusplus
+};
+#endif /* __cplusplus */
+
typedef union jvalue
{
jboolean z;
@@ -99,9 +127,6 @@
void *fnPtr; /* Sigh. */
} JNINativeMethod;
-/* FIXME: this is just a placeholder. */
-typedef int JavaVM;
-
struct JNINativeInterface
{
_Jv_func reserved0;
@@ -1401,5 +1426,75 @@
{ return p->ExceptionCheck (this); }
};
#endif /* __cplusplus */
+
+/*
+ * Invocation API.
+ */
+
+struct JNIInvokeInterface
+{
+ _Jv_func reserved0;
+ _Jv_func reserved1;
+ _Jv_func reserved2;
+
+ jint (*DestroyJavaVM) (JavaVM *);
+ jint (*AttachCurrentThread) (JavaVM *, void **, void *);
+ jint (*DetachCurrentThread) (JavaVM *);
+ jint (*GetEnv) (JavaVM *, void **, jint);
+};
+
+#ifdef __cplusplus
+
+class _Jv_JavaVM
+{
+public:
+ const struct JNIInvokeInterface *functions;
+
+private:
+ /* FIXME: other fields. */
+
+public:
+ jint DestroyJavaVM ()
+ { return functions->DestroyJavaVM (this); }
+
+ jint AttachCurrentThread (void **penv, void *args)
+ { return functions->AttachCurrentThread (this, penv, args); }
+
+ jint DetachCurrentThread ()
+ { return functions->DetachCurrentThread (this); }
+
+ jint GetEnv (void **penv, jint version)
+ { return functions->GetEnv (this, penv, version); }
+};
+#endif /* __cplusplus */
+
+typedef struct JavaVMAttachArgs
+{
+ jint version; /* Must be JNI_VERSION_1_2. */
+ char *name; /* The name of the thread (or NULL). */
+ jobject group; /* Global ref of a ThreadGroup object
+ (or NULL). */
+} JavaVMAttachArgs;
+
+typedef struct JavaVMOption
+{
+ char *optionString;
+ void *extraInfo;
+} JavaVMOption;
+
+typedef struct JavaVMInitArgs
+{
+ /* Must be JNI_VERSION_1_2. */
+ jint version;
+
+ /* Number of options. */
+ jint nOptions;
+
+ /* Options to the VM. */
+ JavaVMOption *options;
+
+ /* Whether we should ignore unrecognized options. */
+ jboolean ignoreUnrecognized;
+} JavaVMInitArgs;
#endif /* __GCJ_JNI_H__ */
Index: include/jvm.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/jvm.h,v
retrieving revision 1.15
diff -u -r1.15 jvm.h
--- jvm.h 2000/02/04 20:49:27 1.15
+++ jvm.h 2000/02/10 20:20:13
@@ -207,4 +207,8 @@
/* Initialize JNI. */
extern void _Jv_JNI_Init (void);
+/* Get or set the per-thread JNIEnv used by the invocation API. */
+_Jv_JNIEnv *_Jv_GetCurrentJNIEnv ();
+void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *);
+
#endif /* __JAVA_JVM_H__ */
Index: java/lang/Thread.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/Thread.java,v
retrieving revision 1.4
diff -u -r1.4 Thread.java
--- Thread.java 2000/01/19 18:39:26 1.4
+++ Thread.java 2000/02/10 20:20:13
@@ -1,6 +1,6 @@
// Thread.java - Thread class.
-/* Copyright (C) 1998, 1999 Red Hat, Inc.
+/* Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
This file is part of libgcj.
@@ -10,6 +10,8 @@
package java.lang;
+import gnu.gcj.RawData;
+
/**
* @author Tom Tromey <tromey@cygnus.com>
* @date August 24, 1998
@@ -297,11 +299,8 @@
private boolean interrupt_flag;
private boolean alive_flag;
- // This is a bit odd. We need a way to represent some data that is
- // manipulated only by the native side of this class. We represent
- // it as a Java object reference. However, it is not actually a
- // Java object.
- private Object data;
+ // Our native data.
+ private RawData data;
// Next thread number to assign.
private static int nextThreadNumber = 0;
Index: java/lang/natThread.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natThread.cc,v
retrieving revision 1.11
diff -u -r1.11 natThread.cc
--- natThread.cc 2000/02/10 17:15:22 1.11
+++ natThread.cc 2000/02/10 20:20:14
@@ -1,6 +1,6 @@
// natThread.cc - Native part of Thread class.
-/* Copyright (C) 1998, 1999 Red Hat, Inc.
+/* Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
This file is part of libgcj.
@@ -23,7 +23,10 @@
#include <java/lang/IllegalThreadStateException.h>
#include <java/lang/InterruptedException.h>
#include <java/lang/NullPointerException.h>
+#include <gnu/gcj/RawData.h>
+#include <jni.h>
+
// This structure is used to represent all the data the native side
@@ -40,6 +43,9 @@
// This is private data for the thread system layer.
_Jv_Thread_t *thread;
+ // Each thread has its own JNI object.
+ JNIEnv *jni_env;
+
// All threads waiting to join this thread are linked together and
// waiting on their respective `interrupt' condition variables.
// When this thread exits, it notifies each such thread by
@@ -83,10 +89,13 @@
// own finalizer then we will need to reinitialize this structure at
// any "interesting" point.
natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
- data = (jobject) nt;
+ data = reinterpret_cast<gnu::gcj::RawData *> (nt);
_Jv_MutexInit (&nt->interrupt_mutex);
_Jv_CondInit (&nt->interrupt_cond);
_Jv_ThreadInitData (&nt->thread, this);
+ // FIXME: if JNI_ENV is set we will want to free it. It is
+ // malloc()d.
+ nt->jni_env = NULL;
nt->joiner = 0;
nt->next = 0;
}
@@ -323,4 +332,21 @@
java::lang::Thread::yield (void)
{
_Jv_ThreadYield ();
+}
+
+JNIEnv *
+_Jv_GetCurrentJNIEnv ()
+{
+ java::lang::Thread *t = _Jv_ThreadCurrent ();
+ if (t == NULL)
+ return NULL;
+ return ((natThread *) t->data)->jni_env;
+}
+
+void
+_Jv_SetCurrentJNIEnv (JNIEnv *env)
+{
+ java::lang::Thread *t = _Jv_ThreadCurrent ();
+ JvAssert (t != NULL);
+ ((natThread *) t->data)->jni_env = env;
}
More information about the Java-patches
mailing list