aboutsummaryrefslogtreecommitdiff
path: root/libjava/prims.cc
diff options
context:
space:
mode:
authorPer Bothner <per@bothner.com>2001-05-21 23:47:48 -0700
committerPer Bothner <bothner@gcc.gnu.org>2001-05-21 23:47:48 -0700
commitc93d7fae7b9825449c023d42eb40641c0ad80be2 (patch)
treeecfc0fb5d915f5f6596ef061114d1b6b7ec5270a /libjava/prims.cc
parentb4fbaca7cb5c6ff5fb5e24e554d510257cb488eb (diff)
downloadgcc-c93d7fae7b9825449c023d42eb40641c0ad80be2.zip
gcc-c93d7fae7b9825449c023d42eb40641c0ad80be2.tar.gz
gcc-c93d7fae7b9825449c023d42eb40641c0ad80be2.tar.bz2
Implement invocation interface; don't create new thread for main.
From-SVN: r42428
Diffstat (limited to 'libjava/prims.cc')
-rw-r--r--libjava/prims.cc240
1 files changed, 174 insertions, 66 deletions
diff --git a/libjava/prims.cc b/libjava/prims.cc
index 0fa42a4..6bcf646 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -36,6 +36,7 @@ details. */
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
+#include <java/lang/ThreadGroup.h>
#endif
#ifndef DISABLE_GETENV_PROPERTIES
@@ -62,6 +63,7 @@ details. */
#include <java/lang/System.h>
#include <java/lang/reflect/Modifier.h>
#include <java/io/PrintStream.h>
+#include <java/lang/UnsatisfiedLinkError.h>
#ifdef USE_LTDL
#include <ltdl.h>
@@ -74,8 +76,10 @@ static java::lang::OutOfMemoryError *no_memory;
// Largest representable size_t.
#define SIZE_T_MAX ((size_t) (~ (size_t) 0))
+static const char *no_properties[] = { NULL };
+
// Properties set at compile time.
-const char **_Jv_Compiler_Properties;
+const char **_Jv_Compiler_Properties = no_properties;
// The JAR file to add to the beginning of java.class.path.
const char *_Jv_Jar_Class_Path;
@@ -92,6 +96,8 @@ static char * _Jv_execName;
const char **_Jv_argv;
int _Jv_argc;
+typedef void main_func (jobject);
+
#ifdef ENABLE_JVMPI
// Pointer to JVMPI notification functions.
void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
@@ -640,51 +646,15 @@ win32_exception_handler (LPEXCEPTION_POINTERS e)
#endif
-static void
-main_init ()
+/* This will be non-NULL if the user has preloaded a JNI library, or
+ linked one into the executable. */
+extern "C"
{
- // Turn stack trace generation off while creating exception objects.
- _Jv_InitClass (&java::lang::Throwable::class$);
- java::lang::Throwable::trace_enabled = 0;
-
- INIT_SEGV;
-#ifdef HANDLE_FPE
- INIT_FPE;
-#else
- arithexception = new java::lang::ArithmeticException
- (JvNewStringLatin1 ("/ by zero"));
-#endif
-
- no_memory = new java::lang::OutOfMemoryError;
-
- java::lang::Throwable::trace_enabled = 1;
-
-#ifdef USE_LTDL
- LTDL_SET_PRELOADED_SYMBOLS ();
-#endif
-
-#ifdef USE_WINSOCK
- // Initialise winsock for networking
- WSADATA data;
- if (WSAStartup (MAKEWORD (1, 1), &data))
- MessageBox (NULL, "Error initialising winsock library.", "Error", MB_OK | MB_ICONEXCLAMATION);
-#endif /* USE_WINSOCK */
-
-#ifdef USE_WIN32_SIGNALLING
- // Install exception handler
- SetUnhandledExceptionFilter (win32_exception_handler);
-#else
- // We only want this on POSIX systems.
- struct sigaction act;
- act.sa_handler = SIG_IGN;
- sigemptyset (&act.sa_mask);
- act.sa_flags = 0;
- sigaction (SIGPIPE, &act, NULL);
-#endif /* USE_WIN32_SIGNALLING */
-
- _Jv_JNI_Init ();
+#pragma weak JNI_OnLoad
+ extern jint JNI_OnLoad (JavaVM *, void *) __attribute__((weak));
}
+
#ifndef DISABLE_GETENV_PROPERTIES
static char *
@@ -828,15 +798,162 @@ process_gcj_properties ()
}
#endif // DISABLE_GETENV_PROPERTIES
-void
-JvRunMain (jclass klass, int argc, const char **argv)
+jint
+_Jv_CreateJavaVM (void* /*vm_args*/)
{
PROCESS_GCJ_PROPERTIES;
+ // Turn stack trace generation off while creating exception objects.
+ _Jv_InitClass (&java::lang::Throwable::class$);
+ java::lang::Throwable::trace_enabled = 0;
+
+ INIT_SEGV;
+#ifdef HANDLE_FPE
+ INIT_FPE;
+#else
+ arithexception = new java::lang::ArithmeticException
+ (JvNewStringLatin1 ("/ by zero"));
+#endif
+
+ no_memory = new java::lang::OutOfMemoryError;
+
+ java::lang::Throwable::trace_enabled = 1;
+
+#ifdef USE_LTDL
+ LTDL_SET_PRELOADED_SYMBOLS ();
+#endif
+
+#ifdef USE_WINSOCK
+ // Initialise winsock for networking
+ WSADATA data;
+ if (WSAStartup (MAKEWORD (1, 1), &data))
+ MessageBox (NULL, "Error initialising winsock library.", "Error", MB_OK | MB_ICONEXCLAMATION);
+#endif /* USE_WINSOCK */
+
+#ifdef USE_WIN32_SIGNALLING
+ // Install exception handler
+ SetUnhandledExceptionFilter (win32_exception_handler);
+#else
+ // We only want this on POSIX systems.
+ struct sigaction act;
+ act.sa_handler = SIG_IGN;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGPIPE, &act, NULL);
+#endif /* USE_WIN32_SIGNALLING */
+
+ _Jv_JNI_Init ();
+
+ /* Some systems let you preload shared libraries before running a
+ program. Under Linux, this is done by setting the LD_PRELOAD
+ environment variable. We take advatage of this here to allow for
+ dynamically loading a JNI library into a fully linked executable. */
+
+ if (JNI_OnLoad != NULL)
+ {
+ JavaVM *vm = _Jv_GetJavaVM ();
+ if (vm == NULL)
+ {
+ // FIXME: what?
+ return -1;
+ }
+ jint vers = JNI_OnLoad (vm, NULL);
+ if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2)
+ {
+ // FIXME: unload the library.
+ _Jv_Throw (new java::lang::UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from preloaded JNI_OnLoad")));
+ }
+ }
+ return 0;
+}
+
+static void
+runFirst (::java::lang::Class *klass, ::java::lang::Object *args)
+{
+ Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22);
+ Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4);
+
+ _Jv_Method *meth = _Jv_GetMethodLocal (klass, main_name, main_signature);
+
+ // Some checks from Java Spec section 12.1.4.
+ const char *msg = NULL;
+ if (meth == NULL)
+ msg = "no suitable method `main' in class";
+ else if (! java::lang::reflect::Modifier::isStatic(meth->accflags))
+ msg = "`main' must be static";
+ else if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
+ msg = "`main' must be public";
+ if (msg != NULL)
+ {
+ fprintf (stderr, "%s\n", msg);
+ ::exit(1);
+ }
+
+#ifdef WITH_JVMPI
+ if (_Jv_JVMPI_Notify_THREAD_START)
+ {
+ JVMPI_Event event;
+
+ jstring thread_name = getName ();
+ jstring group_name = NULL, parent_name = NULL;
+ java::lang::ThreadGroup *group = getThreadGroup ();
+
+ if (group)
+ {
+ group_name = group->getName ();
+ group = group->getParent ();
+
+ if (group)
+ parent_name = group->getName ();
+ }
+
+ int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
+ int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
+ int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
+
+ char thread_chars[thread_len + 1];
+ char group_chars[group_len + 1];
+ char parent_chars[parent_len + 1];
+
+ if (thread_name)
+ JvGetStringUTFRegion (thread_name, 0,
+ thread_name->length(), thread_chars);
+ if (group_name)
+ JvGetStringUTFRegion (group_name, 0,
+ group_name->length(), group_chars);
+ if (parent_name)
+ JvGetStringUTFRegion (parent_name, 0,
+ parent_name->length(), parent_chars);
+
+ thread_chars[thread_len] = '\0';
+ group_chars[group_len] = '\0';
+ parent_chars[parent_len] = '\0';
+
+ event.event_type = JVMPI_EVENT_THREAD_START;
+ event.env_id = NULL;
+ event.u.thread_start.thread_name = thread_chars;
+ event.u.thread_start.group_name = group_chars;
+ event.u.thread_start.parent_name = parent_chars;
+ event.u.thread_start.thread_id = (jobjectID) this;
+ event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
+
+ _Jv_DisableGC ();
+ (*_Jv_JVMPI_Notify_THREAD_START) (&event);
+ _Jv_EnableGC ();
+ }
+#endif
+
+ main_func *real_main = (main_func *) meth->ncode;
+ (*real_main) (args);
+}
+
+void
+JvRunMain (jclass klass, int argc, const char **argv)
+{
_Jv_argv = argv;
_Jv_argc = argc;
- main_init ();
+ _Jv_CreateJavaVM (NULL);
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
sprintf (exec_name, "/proc/%d/exe", getpid ());
@@ -845,10 +962,9 @@ JvRunMain (jclass klass, int argc, const char **argv)
_Jv_ThisExecutable (argv[0]);
#endif
+ main_thread = _Jv_AttachCurrentThread (JvNewStringLatin1 ("main"), NULL);
arg_vec = JvConvertArgv (argc - 1, argv + 1);
- main_thread = new gnu::gcj::runtime::FirstThread (klass, arg_vec);
-
- main_thread->start();
+ runFirst (klass, arg_vec);
_Jv_ThreadWait ();
int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
@@ -860,9 +976,8 @@ void
_Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar)
{
jstring class_name;
- PROCESS_GCJ_PROPERTIES;
- main_init ();
+ _Jv_CreateJavaVM (NULL);
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
@@ -870,23 +985,17 @@ _Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar)
_Jv_ThisExecutable (exec_name);
#endif
+ main_thread = _Jv_AttachCurrentThread (JvNewStringLatin1 ("main"), NULL);
+
if (is_jar)
{
// name specifies a jar file. We must now extract the
- // Main-Class attribute from the jar's manifest file. This is
- // done by gnu.gcj.runtime.FirstThread.main.
+ // Main-Class attribute from the jar's manifest file.
+ // This is done by gnu.gcj.runtime.FirstThread.getMain.
_Jv_Jar_Class_Path = strdup (name);
- arg_vec = JvConvertArgv (1, &_Jv_Jar_Class_Path);
-
- main_thread =
- new gnu::gcj::runtime::FirstThread (&gnu::gcj::runtime::FirstThread::class$,
- arg_vec);
- main_thread->start();
- _Jv_ThreadWait ();
-
- // FirstThread.main extracts the main class name and stores it
- // here.
- class_name = gnu::gcj::runtime::FirstThread::jarMainClassName;
+ jstring jar_name = JvNewStringLatin1 (name);
+ // FirstThread.getMain extracts the main class name.
+ class_name = gnu::gcj::runtime::FirstThread::getMain (jar_name);
// We need a new ClassLoader because the classpath must be the
// jar file only. The easiest way to do this is to lose our
@@ -900,8 +1009,7 @@ _Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar)
if (class_name)
{
- main_thread = new gnu::gcj::runtime::FirstThread (class_name, arg_vec);
- main_thread->start();
+ runFirst(java::lang::Class::forName (class_name), arg_vec);
_Jv_ThreadWait ();
}