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