OSDN Git Service

2005-05-18 Thomas Koenig <Thomas.Koenig@online.de>
[pf3gnuchains/gcc-fork.git] / libjava / prims.cc
index e3d5750..af17724 100644 (file)
@@ -1,6 +1,6 @@
 // prims.cc - Code for core of runtime environment.
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -55,11 +55,12 @@ details.  */
 #include <java/lang/OutOfMemoryError.h>
 #include <java/lang/System.h>
 #include <java/lang/VMThrowable.h>
+#include <java/lang/VMClassLoader.h>
 #include <java/lang/reflect/Modifier.h>
 #include <java/io/PrintStream.h>
 #include <java/lang/UnsatisfiedLinkError.h>
 #include <java/lang/VirtualMachineError.h>
-#include <gnu/gcj/runtime/VMClassLoader.h>
+#include <gnu/gcj/runtime/ExtensionClassLoader.h>
 #include <gnu/gcj/runtime/FinalizerThread.h>
 #include <execution.h>
 #include <gnu/java/lang/MainThread.h>
@@ -80,13 +81,9 @@ static java::lang::OutOfMemoryError *no_memory;
 // functions are changed to take a size_t argument instead of jint.
 #define MAX_OBJECT_SIZE ((1<<31) - 1)
 
-static const char *no_properties[] = { NULL };
-
 // Properties set at compile time.
-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;
+const char **_Jv_Compiler_Properties = NULL;
+int _Jv_Properties_Count = 0;
 
 #ifndef DISABLE_GETENV_PROPERTIES
 // Property key/value pairs.
@@ -148,10 +145,10 @@ unblock_signal (int signum __attribute__ ((__unused__)))
 #ifdef HANDLE_SEGV
 SIGNAL_HANDLER (catch_segv)
 {
-  java::lang::NullPointerException *nullp 
-    = new java::lang::NullPointerException;
   unblock_signal (SIGSEGV);
   MAKE_THROW_FRAME (nullp);
+  java::lang::NullPointerException *nullp 
+    = new java::lang::NullPointerException;
   throw nullp;
 }
 #endif
@@ -159,14 +156,14 @@ SIGNAL_HANDLER (catch_segv)
 #ifdef HANDLE_FPE
 SIGNAL_HANDLER (catch_fpe)
 {
-  java::lang::ArithmeticException *arithexception 
-    = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
   unblock_signal (SIGFPE);
 #ifdef HANDLE_DIVIDE_OVERFLOW
   HANDLE_DIVIDE_OVERFLOW;
 #else
   MAKE_THROW_FRAME (arithexception);
 #endif
+  java::lang::ArithmeticException *arithexception 
+    = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
   throw arithexception;
 }
 #endif
@@ -362,6 +359,22 @@ _Jv_ThrowNullPointerException ()
   throw new java::lang::NullPointerException;
 }
 
+// Resolve an entry in the constant pool and return the target
+// address.
+void *
+_Jv_ResolvePoolEntry (jclass this_class, jint index)
+{
+  _Jv_Constants *pool = &this_class->constants;
+
+  if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
+    return pool->data[index].field->u.addr;
+
+  JvSynchronize sync (this_class);
+  return (_Jv_Linker::resolve_pool_entry (this_class, index))
+    .field->u.addr;
+}
+
+
 // Explicitly throw a no memory exception.
 // The collector calls this when it encounters an out-of-memory condition.
 void _Jv_ThrowNoMemory()
@@ -678,46 +691,79 @@ _Jv_InitPrimClass (jclass cl, char *cname, char sig, int len)
 }
 
 jclass
-_Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader)
+_Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader,
+                           char **endp)
 {
+  // First count arrays.
+  int array_count = 0;
+  while (*sig == '[')
+    {
+      ++sig;
+      ++array_count;
+    }
+
+  jclass result = NULL;
   switch (*sig)
     {
     case 'B':
-      return JvPrimClass (byte);
+      result = JvPrimClass (byte);
+      break;
     case 'S':
-      return JvPrimClass (short);
+      result = JvPrimClass (short);
+      break;
     case 'I':
-      return JvPrimClass (int);
+      result = JvPrimClass (int);
+      break;
     case 'J':
-      return JvPrimClass (long);
+      result = JvPrimClass (long);
+      break;
     case 'Z':
-      return JvPrimClass (boolean);
+      result = JvPrimClass (boolean);
+      break;
     case 'C':
-      return JvPrimClass (char);
+      result = JvPrimClass (char);
+      break;
     case 'F':
-      return JvPrimClass (float);
+      result = JvPrimClass (float);
+      break;
     case 'D':
-      return JvPrimClass (double);
+      result = JvPrimClass (double);
+      break;
     case 'V':
-      return JvPrimClass (void);
+      result = JvPrimClass (void);
+      break;
     case 'L':
       {
-       int i;
-       for (i = 1; sig[i] && sig[i] != ';'; ++i)
-         ;
-       _Jv_Utf8Const *name = _Jv_makeUtf8Const (&sig[1], i - 1);
-       return _Jv_FindClass (name, loader);
-      }
-    case '[':
-      {
-       jclass klass = _Jv_FindClassFromSignature (&sig[1], loader);
-       if (! klass)
-         return NULL;
-       return _Jv_GetArrayClass (klass, loader);
+       char *save = ++sig;
+       while (*sig && *sig != ';')
+         ++sig;
+       // Do nothing if signature appears to be malformed.
+       if (*sig == ';')
+         {
+           _Jv_Utf8Const *name = _Jv_makeUtf8Const (save, sig - save);
+           result = _Jv_FindClass (name, loader);
+         }
+       break;
       }
+    default:
+      // Do nothing -- bad signature.
+      break;
     }
 
-  return NULL;                 // Placate compiler.
+  if (endp)
+    {
+      // Not really the "end", but the last valid character that we
+      // looked at.
+      *endp = sig;
+    }
+
+  if (! result)
+    return NULL;
+
+  // Find arrays.
+  while (array_count-- > 0)
+    result = _Jv_GetArrayClass (result, loader);
+  return result;
 }
 
 \f
@@ -907,20 +953,311 @@ namespace gcj
   _Jv_Utf8Const *finit_name;
   
   bool runtimeInitialized = false;
+  
+  // When true, print debugging information about class loading.
+  bool verbose_class_flag;
+  
+  // When true, enable the bytecode verifier and BC-ABI type verification. 
+  bool verifyClasses = true;
+}
+
+// We accept all non-standard options accepted by Sun's java command,
+// for compatibility with existing application launch scripts.
+static jint
+parse_x_arg (char* option_string)
+{
+  if (strlen (option_string) <= 0)
+    return -1;
+
+  if (! strcmp (option_string, "int"))
+    {
+      // FIXME: this should cause the vm to never load shared objects
+    }
+  else if (! strcmp (option_string, "mixed"))
+    {
+      // FIXME: allow interpreted and native code
+    }
+  else if (! strcmp (option_string, "batch"))
+    {
+      // FIXME: disable background JIT'ing
+    }
+  else if (! strcmp (option_string, "debug"))
+    {
+      // FIXME: add JDWP/JVMDI support
+    }
+  else if (! strncmp (option_string, "bootclasspath:", 14))
+    {
+      // FIXME: add a parse_bootclasspath_arg function
+    }
+  else if (! strncmp (option_string, "bootclasspath/a:", 16))
+    {
+    }
+  else if (! strncmp (option_string, "bootclasspath/p:", 16))
+    {
+    }
+  else if (! strcmp (option_string, "check:jni"))
+    {
+      // FIXME: enable strict JNI checking
+    }
+  else if (! strcmp (option_string, "future"))
+    {
+      // FIXME: enable strict class file format checks
+    }
+  else if (! strcmp (option_string, "noclassgc"))
+    {
+      // FIXME: disable garbage collection for classes
+    }
+  else if (! strcmp (option_string, "incgc"))
+    {
+      // FIXME: incremental garbage collection
+    }
+  else if (! strncmp (option_string, "loggc:", 6))
+    {
+      if (option_string[6] == '\0')
+        {
+          fprintf (stderr,
+                   "libgcj: filename argument expected for loggc option\n");
+          return -1;
+        }
+      // FIXME: set gc logging filename
+    }
+  else if (! strncmp (option_string, "ms", 2))
+    {
+      // FIXME: ignore this option until PR 20699 is fixed.
+      // _Jv_SetInitialHeapSize (option_string + 2);
+    }
+  else if (! strncmp (option_string, "mx", 2))
+    _Jv_SetMaximumHeapSize (option_string + 2);
+  else if (! strcmp (option_string, "prof"))
+    {
+      // FIXME: enable profiling of program running in vm
+    }
+  else if (! strncmp (option_string, "runhprof:", 9))
+    {
+      // FIXME: enable specific type of vm profiling.  add a
+      // parse_runhprof_arg function
+    }
+  else if (! strcmp (option_string, "rs"))
+    {
+      // FIXME: reduced system signal usage.  disable thread dumps,
+      // only terminate in response to user-initiated calls,
+      // e.g. System.exit()
+    }
+  else if (! strncmp (option_string, "ss", 2))
+    {
+      // FIXME: set thread stack size
+    }
+  else if (! strcmp (option_string, "X:+UseAltSigs"))
+    {
+      // FIXME: use signals other than SIGUSR1 and SIGUSR2
+    }
+  else if (! strcmp (option_string, "share:off"))
+    {
+      // FIXME: don't share class data
+    }
+  else if (! strcmp (option_string, "share:auto"))
+    {
+      // FIXME: share class data where possible
+    }
+  else if (! strcmp (option_string, "share:on"))
+    {
+      // FIXME: fail if impossible to share class data
+    }
+
+  return 0;
+}
+
+static jint
+parse_verbose_args (char* option_string,
+                    bool ignore_unrecognized)
+{
+  size_t len = sizeof ("-verbose") - 1;
+
+  if (strlen (option_string) < len)
+    return -1;
+
+  if (option_string[len] == ':'
+      && option_string[len + 1] != '\0')
+    {
+      char* verbose_args = option_string + len + 1;
+
+      do
+       {
+         if (! strncmp (verbose_args,
+                        "gc", sizeof ("gc") - 1))
+            {
+              if (verbose_args[sizeof ("gc") - 1] == '\0'
+                  || verbose_args[sizeof ("gc") - 1] == ',')
+                {
+                  // FIXME: we should add functions to boehm-gc that
+                  // toggle GC_print_stats, GC_PRINT_ADDRESS_MAP and
+                  // GC_print_back_height.
+                  verbose_args += sizeof ("gc") - 1;
+                }
+              else
+                {
+                verbose_arg_err:
+                  fprintf (stderr, "libgcj: unknown verbose option: %s\n",
+                           option_string);
+                  return -1;
+                }
+            }
+         else if (! strncmp (verbose_args,
+                             "class",
+                             sizeof ("class") - 1))
+            {
+              if (verbose_args[sizeof ("class") - 1] == '\0'
+                  || verbose_args[sizeof ("class") - 1] == ',')
+                {
+                  gcj::verbose_class_flag = true;
+                  verbose_args += sizeof ("class") - 1;
+                }
+              else
+                goto verbose_arg_err;
+            }
+         else if (! strncmp (verbose_args, "jni",
+                             sizeof ("jni") - 1))
+            {
+              if (verbose_args[sizeof ("jni") - 1] == '\0'
+                  || verbose_args[sizeof ("jni") - 1] == ',')
+                {
+                  // FIXME: enable JNI messages.
+                  verbose_args += sizeof ("jni") - 1;
+                }
+              else
+                goto verbose_arg_err;
+            }
+         else if (ignore_unrecognized
+                  && verbose_args[0] == 'X')
+           {
+             // ignore unrecognized non-standard verbose option
+             while (verbose_args[0] != '\0'
+                    && verbose_args[0] != ',')
+                verbose_args++;
+           }
+          else if (verbose_args[0] == ',')
+            {
+              verbose_args++;
+            }
+          else
+            goto verbose_arg_err;
+
+          if (verbose_args[0] == ',')
+            verbose_args++;
+       }
+      while (verbose_args[0] != '\0');
+    }
+  else if (option_string[len] == 'g'
+          && option_string[len + 1] == 'c'
+          && option_string[len + 2] == '\0')
+    {
+      // FIXME: we should add functions to boehm-gc that
+      // toggle GC_print_stats, GC_PRINT_ADDRESS_MAP and
+      // GC_print_back_height.
+      return 0;
+    }
+  else if (option_string[len] == '\0')
+    {
+      gcj::verbose_class_flag = true;
+      return 0;
+    }
+  else
+    {
+      // unrecognized option beginning with -verbose
+      return -1;
+    }
+  return 0;
+}
+
+static jint
+parse_init_args (JvVMInitArgs* vm_args)
+{
+  // if _Jv_Compiler_Properties is non-NULL then it needs to be
+  // re-allocated dynamically.
+  if (_Jv_Compiler_Properties)
+    {
+      const char** props = _Jv_Compiler_Properties;
+      _Jv_Compiler_Properties = NULL;
+
+      for (int i = 0; props[i]; i++)
+       {
+         _Jv_Compiler_Properties = (const char**) _Jv_Realloc
+           (_Jv_Compiler_Properties,
+            (_Jv_Properties_Count + 1) * sizeof (const char*));
+         _Jv_Compiler_Properties[_Jv_Properties_Count++] = props[i];
+       }
+    }
+
+  if (vm_args == NULL)
+    return 0;
+
+  for (int i = 0; i < vm_args->nOptions; ++i)
+    {
+      char* option_string = vm_args->options[i].optionString;
+      if (! strcmp (option_string, "vfprintf")
+         || ! strcmp (option_string, "exit")
+         || ! strcmp (option_string, "abort"))
+       {
+         // FIXME: we are required to recognize these, but for
+         // now we don't handle them in any way.
+         continue;
+       }
+      else if (! strncmp (option_string,
+                         "-verbose", sizeof ("-verbose") - 1))
+       {
+         jint result = parse_verbose_args (option_string,
+                                            vm_args->ignoreUnrecognized);
+         if (result < 0)
+           return result;
+       }
+      else if (! strncmp (option_string, "-D", 2))
+       {
+         _Jv_Compiler_Properties = (const char**) _Jv_Realloc
+           (_Jv_Compiler_Properties,
+            (_Jv_Properties_Count + 1) * sizeof (char*));
+
+         _Jv_Compiler_Properties[_Jv_Properties_Count++] =
+           strdup (option_string + 2);
+
+         continue;
+       }
+      else if (vm_args->ignoreUnrecognized)
+        {
+          if (option_string[0] == '_')
+            parse_x_arg (option_string + 1);
+          else if (! strncmp (option_string, "-X", 2))
+            parse_x_arg (option_string + 2);
+          else
+            {
+            unknown_option:
+              fprintf (stderr, "libgcj: unknown option: %s\n", option_string);
+              return -1;
+            }
+       }
+      else
+        goto unknown_option;
+    }
+  return 0;
 }
 
 jint
-_Jv_CreateJavaVM (void* /*vm_args*/)
+_Jv_CreateJavaVM (JvVMInitArgs* vm_args)
 {
   using namespace gcj;
-  
+
   if (runtimeInitialized)
     return -1;
 
   runtimeInitialized = true;
 
+  jint result = parse_init_args (vm_args);
+  if (result < 0)
+    return -1;
+
   PROCESS_GCJ_PROPERTIES;
 
+  /* Threads must be initialized before the GC, so that it inherits the
+     signal mask.  */
   _Jv_InitThreads ();
   _Jv_InitGC ();
   _Jv_InitializeSyncMutex ();
@@ -964,9 +1301,11 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
   // of VMClassLoader.
   _Jv_InitClass (&java::lang::ClassLoader::class$);
 
-  // Once the bootstrap loader is in place, change it into a kind of
-  // system loader, by having it read the class path.
-  gnu::gcj::runtime::VMClassLoader::initialize();
+  // Set up the system class loader and the bootstrap class loader.
+  gnu::gcj::runtime::ExtensionClassLoader::initialize();
+  java::lang::VMClassLoader::initialize(JvNewStringLatin1(TOOLEXECLIBDIR));
+
+  _Jv_RegisterBootstrapPackages();
 
   no_memory = new java::lang::OutOfMemoryError;
 
@@ -998,8 +1337,8 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
 }
 
 void
-_Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, 
-            bool is_jar)
+_Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc,
+             const char **argv, bool is_jar)
 {
 #ifndef DISABLE_MAIN_ARGS
   _Jv_SetArgs (argc, argv);
@@ -1009,11 +1348,11 @@ _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv,
 
   try
     {
-      // Set this very early so that it is seen when java.lang.System
-      // is initialized.
-      if (is_jar)
-       _Jv_Jar_Class_Path = strdup (name);
-      _Jv_CreateJavaVM (NULL);
+      if (_Jv_CreateJavaVM (vm_args) < 0)
+       {
+         fprintf (stderr, "libgcj: couldn't create virtual machine\n");
+         exit (1);
+       }
 
       // Get the Runtime here.  We want to initialize it before searching
       // for `main'; that way it will be set up if `main' is a JNI method.
@@ -1037,7 +1376,10 @@ _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv,
       java::lang::System::err->println (JvNewStringLatin1 
         ("Exception during runtime initialization"));
       t->printStackTrace();
-      runtime->exit (1);
+      if (runtime)
+       runtime->exit (1);
+      // In case the runtime creation failed.
+      ::exit (1);
     }
 
   _Jv_AttachCurrentThread (main_thread);
@@ -1049,6 +1391,13 @@ _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv,
 }
 
 void
+_Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, 
+            bool is_jar)
+{
+  _Jv_RunMain (NULL, klass, name, argc, argv, is_jar);
+}
+
+void
 JvRunMain (jclass klass, int argc, const char **argv)
 {
   _Jv_RunMain (klass, NULL, argc, argv, false);