From bf1967d63c238862df52d7823dbfd4abc9d5c647 Mon Sep 17 00:00:00 2001 From: tromey Date: Thu, 10 Feb 2000 20:31:48 +0000 Subject: [PATCH] * 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 (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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31901 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 46 ++++++ libjava/Makefile.am | 12 ++ libjava/Makefile.in | 75 ++++++++-- libjava/gnu/gcj/jni/NativeThread.java | 28 ++++ libjava/gnu/gcj/jni/natNativeThread.cc | 24 +++ libjava/include/jni.h | 101 ++++++++++++- libjava/include/jvm.h | 4 + libjava/java/lang/Thread.java | 11 +- libjava/java/lang/natThread.cc | 30 +++- libjava/jni.cc | 259 ++++++++++++++++++++++++++++++++- 10 files changed, 560 insertions(+), 30 deletions(-) create mode 100644 libjava/gnu/gcj/jni/NativeThread.java create mode 100644 libjava/gnu/gcj/jni/natNativeThread.cc diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 159853c..91485fc 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,49 @@ +2000-02-10 Tom Tromey + + * 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 + (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. + 2000-02-10 Andrew Haley * interpret.cc: Don't include fdlibm.h. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 4abbeab..c22a2c8 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -221,6 +221,16 @@ java/lang/FirstThread.h: java/lang/FirstThread.class libgcj.zip -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 @@ built_java_source_files = java/lang/ConcreteProcess.java ## 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_EUCJIS.cc \ 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 \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index bf0ffec..dada6e9 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -326,6 +326,7 @@ java/awt/peer/WindowPeer.java built_java_source_files = java/lang/ConcreteProcess.java 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 \ @@ -610,6 +611,7 @@ gnu/gcj/convert/natInput_EUCJIS.cc \ 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 \ @@ -730,7 +732,8 @@ LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ DATA = $(data_DATA) $(toolexeclib_DATA) DIST_COMMON = README COPYING.LIB ChangeLog Makefile.am Makefile.in NEWS \ -THANKS acinclude.m4 aclocal.m4 configure configure.in libgcj.spec.in +THANKS acconfig.h acinclude.m4 aclocal.m4 configure configure.in \ +include/config.h.in include/stamp-h.in libgcj.spec.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) @@ -752,8 +755,8 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/gnu/gcj/convert/Output_JavaSrc.P \ .deps/gnu/gcj/convert/Output_SJIS.P .deps/gnu/gcj/convert/Output_UTF8.P \ .deps/gnu/gcj/convert/Output_iconv.P \ -.deps/gnu/gcj/convert/UnicodeToBytes.P .deps/gnu/gcj/math/MPN.P \ -.deps/gnu/gcj/protocol/file/Connection.P \ +.deps/gnu/gcj/convert/UnicodeToBytes.P .deps/gnu/gcj/jni/NativeThread.P \ +.deps/gnu/gcj/math/MPN.P .deps/gnu/gcj/protocol/file/Connection.P \ .deps/gnu/gcj/protocol/file/Handler.P \ .deps/gnu/gcj/protocol/http/Connection.P \ .deps/gnu/gcj/protocol/http/Handler.P \ @@ -955,6 +958,34 @@ config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) cd $(srcdir) && $(AUTOCONF) + +include/config.h: include/stamp-h + @if test ! -f $@; then \ + rm -f include/stamp-h; \ + $(MAKE) include/stamp-h; \ + else :; fi +include/stamp-h: $(srcdir)/include/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=include/config.h \ + $(SHELL) ./config.status + @echo timestamp > include/stamp-h 2> /dev/null +$(srcdir)/include/config.h.in: @MAINTAINER_MODE_TRUE@$(srcdir)/include/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/include/stamp-h.in; \ + $(MAKE) $(srcdir)/include/stamp-h.in; \ + else :; fi +$(srcdir)/include/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/include/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f include/config.h + +maintainer-clean-hdr: libgcj.spec: $(top_builddir)/config.status libgcj.spec.in cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status @@ -1393,31 +1424,33 @@ distclean-generic: -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: -mostlyclean-am: mostlyclean-toolexeclibLIBRARIES mostlyclean-compile \ - mostlyclean-libtool mostlyclean-toolexeclibLTLIBRARIES \ +mostlyclean-am: mostlyclean-hdr mostlyclean-toolexeclibLIBRARIES \ + mostlyclean-compile mostlyclean-libtool \ + mostlyclean-toolexeclibLTLIBRARIES \ mostlyclean-binPROGRAMS mostlyclean-noinstPROGRAMS \ mostlyclean-tags mostlyclean-depend mostlyclean-generic mostlyclean: mostlyclean-recursive -clean-am: clean-toolexeclibLIBRARIES clean-compile clean-libtool \ - clean-toolexeclibLTLIBRARIES clean-binPROGRAMS \ - clean-noinstPROGRAMS clean-tags clean-depend \ - clean-generic mostlyclean-am clean-local +clean-am: clean-hdr clean-toolexeclibLIBRARIES clean-compile \ + clean-libtool clean-toolexeclibLTLIBRARIES \ + clean-binPROGRAMS clean-noinstPROGRAMS clean-tags \ + clean-depend clean-generic mostlyclean-am clean-local clean: clean-recursive -distclean-am: distclean-toolexeclibLIBRARIES distclean-compile \ - distclean-libtool distclean-toolexeclibLTLIBRARIES \ - distclean-binPROGRAMS distclean-noinstPROGRAMS \ - distclean-tags distclean-depend distclean-generic \ - clean-am +distclean-am: distclean-hdr distclean-toolexeclibLIBRARIES \ + distclean-compile distclean-libtool \ + distclean-toolexeclibLTLIBRARIES distclean-binPROGRAMS \ + distclean-noinstPROGRAMS distclean-tags \ + distclean-depend distclean-generic clean-am -rm -f libtool distclean: distclean-recursive -rm -f config.status -maintainer-clean-am: maintainer-clean-toolexeclibLIBRARIES \ +maintainer-clean-am: maintainer-clean-hdr \ + maintainer-clean-toolexeclibLIBRARIES \ maintainer-clean-compile maintainer-clean-libtool \ maintainer-clean-toolexeclibLTLIBRARIES \ maintainer-clean-binPROGRAMS \ @@ -1430,7 +1463,8 @@ maintainer-clean-am: maintainer-clean-toolexeclibLIBRARIES \ maintainer-clean: maintainer-clean-recursive -rm -f config.status -.PHONY: mostlyclean-toolexeclibLIBRARIES distclean-toolexeclibLIBRARIES \ +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +mostlyclean-toolexeclibLIBRARIES distclean-toolexeclibLIBRARIES \ clean-toolexeclibLIBRARIES maintainer-clean-toolexeclibLIBRARIES \ uninstall-toolexeclibLIBRARIES install-toolexeclibLIBRARIES \ mostlyclean-compile distclean-compile clean-compile \ @@ -1514,6 +1548,15 @@ java/lang/FirstThread.h: java/lang/FirstThread.class libgcj.zip -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;' \ + -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);' \ diff --git a/libjava/gnu/gcj/jni/NativeThread.java b/libjava/gnu/gcj/jni/NativeThread.java new file mode 100644 index 0000000..9ed6d89 --- /dev/null +++ b/libjava/gnu/gcj/jni/NativeThread.java @@ -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 + * @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 (); +} diff --git a/libjava/gnu/gcj/jni/natNativeThread.cc b/libjava/gnu/gcj/jni/natNativeThread.cc new file mode 100644 index 0000000..b26c95d --- /dev/null +++ b/libjava/gnu/gcj/jni/natNativeThread.cc @@ -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 + +#include + +#include +#include +#include +#include + +void +gnu::gcj::jni::NativeThread::finish () +{ + finish_ (); +} diff --git a/libjava/include/jni.h b/libjava/include/jni.h index fa2fddc..3547779 100644 --- a/libjava/include/jni.h +++ b/libjava/include/jni.h @@ -23,6 +23,7 @@ details. */ #include typedef struct _Jv_JNIEnv JNIEnv; +typedef struct _Jv_JavaVM JavaVM; #define JNI_TRUE true #define JNI_FALSE false @@ -59,6 +60,7 @@ typedef void *jfieldID; 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 @@ typedef jobject jweak; #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 @@ typedef struct void *fnPtr; /* Sigh. */ } JNINativeMethod; -/* FIXME: this is just a placeholder. */ -typedef int JavaVM; - struct JNINativeInterface { _Jv_func reserved0; @@ -1402,4 +1427,74 @@ public: }; #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__ */ diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 325fe93..d21da78 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -207,4 +207,8 @@ void *_Jv_FindSymbolInExecutable (const char *); /* 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__ */ diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java index 3492167..7dbabcf 100644 --- a/libjava/java/lang/Thread.java +++ b/libjava/java/lang/Thread.java @@ -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 @@ details. */ package java.lang; +import gnu.gcj.RawData; + /** * @author Tom Tromey * @date August 24, 1998 @@ -297,11 +299,8 @@ public class Thread implements Runnable 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; diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc index 6870f02..741f2b5 100644 --- a/libjava/java/lang/natThread.cc +++ b/libjava/java/lang/natThread.cc @@ -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,6 +23,9 @@ details. */ #include #include #include +#include + +#include @@ -40,6 +43,9 @@ struct natThread // 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 @@ java::lang::Thread::initialize_native (void) // 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 (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; } @@ -324,3 +333,20 @@ 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; +} diff --git a/libjava/jni.cc b/libjava/jni.cc index b6728e5..6beb6f7 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -36,6 +36,7 @@ details. */ #include #include #include +#include #include #include @@ -51,6 +52,10 @@ extern java::lang::Class ObjectClass; 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 @@ enum invocation_type 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 @@ struct _Jv_JNI_LocalFrame // 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 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) { // FIXME: exception processing. env->ex = new java::lang::OutOfMemoryError; - return -1; + return JNI_ERR; } frame->marker = true; @@ -1380,6 +1389,238 @@ _Jv_JNIMethod::call (ffi_cif *cif, void *ret, ffi_raw *args, void *__this) +// +// Invocation API. +// + +// An internal helper function. +static jint +_Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args) +{ + JavaVMAttachArgs *attach = reinterpret_cast (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 (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 (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 (&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 (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 (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 (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 @@ struct JNINativeInterface _Jv_JNIFunctions = NOT_IMPL /* UnregisterNatives */, _Jv_JNI_MonitorEnter, _Jv_JNI_MonitorExit, - NOT_IMPL /* GetJavaVM */, + _Jv_JNI_GetJavaVM, _Jv_JNI_GetStringRegion, _Jv_JNI_GetStringUTFRegion, @@ -1628,3 +1869,15 @@ struct JNINativeInterface _Jv_JNIFunctions = _Jv_JNI_ExceptionCheck }; + +struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = +{ + RESERVED, + RESERVED, + RESERVED, + + _Jv_JNI_DestroyJavaVM, + _Jv_JNI_AttachCurrentThread, + _Jv_JNI_DetachCurrentThread, + _Jv_JNI_GetEnv +}; -- 2.7.4