OSDN Git Service

* genpeep.c (main): Add toplev.h to included headers.
[pf3gnuchains/gcc-fork.git] / libjava / prims.cc
index fadc466..1ef5674 100644 (file)
@@ -1,6 +1,6 @@
 // prims.cc - Code for core of runtime environment.
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -49,8 +49,10 @@ details.  */
 #include <java/lang/ArrayIndexOutOfBoundsException.h>
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/ClassFormatError.h>
+#include <java/lang/ClassNotFoundException.h>
 #include <java/lang/InternalError.h>
 #include <java/lang/NegativeArraySizeException.h>
+#include <java/lang/NoClassDefFoundError.h>
 #include <java/lang/NullPointerException.h>
 #include <java/lang/OutOfMemoryError.h>
 #include <java/lang/System.h>
@@ -168,7 +170,6 @@ SIGNAL_HANDLER (catch_fpe)
 }
 #endif
 
-\f
 
 jboolean
 _Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b)
@@ -236,9 +237,123 @@ _Jv_equaln (Utf8Const *a, jstring str, jint n)
   return true;
 }
 
+// Determines whether the given Utf8Const object contains
+// a type which is primitive or some derived form of it, eg.
+// an array or multi-dimensional array variant.
+jboolean
+_Jv_isPrimitiveOrDerived(const Utf8Const *a)
+{
+  unsigned char *aptr = (unsigned char *) a->data;
+  unsigned char *alimit = aptr + a->length;
+  int ac = UTF8_GET(aptr, alimit);
+
+  // Skips any leading array marks.
+  while (ac == '[')
+    ac = UTF8_GET(aptr, alimit);
+
+  // There should not be another character. This implies that
+  // the type name is only one character long.
+  if (UTF8_GET(aptr, alimit) == -1)
+    switch ( ac )
+      {
+        case 'Z':
+        case 'B':
+        case 'C':
+        case 'S':
+        case 'I':
+        case 'J':
+        case 'F':
+        case 'D':
+          return true;
+        default:
+          break;
+       }
+
+   return false;
+}
+
+// Find out whether two _Jv_Utf8Const candidates contain the same
+// classname.
+// The method is written to handle the different formats of classnames.
+// Eg. "Ljava/lang/Class;", "Ljava.lang.Class;", "java/lang/Class" and
+// "java.lang.Class" will be seen as equal.
+// Warning: This function is not smart enough to declare "Z" and "boolean"
+// and similar cases as equal (and is not meant to be used this way)!
+jboolean
+_Jv_equalUtf8Classnames (const Utf8Const *a, const Utf8Const *b)
+{
+  // If the class name's length differs by two characters
+  // it is possible that we have candidates which are given
+  // in the two different formats ("Lp1/p2/cn;" vs. "p1/p2/cn")
+  switch (a->length - b->length)
+    {
+      case -2:
+      case 0:
+      case 2:
+        break;
+      default:
+        return false;
+    }
+
+  unsigned char *aptr = (unsigned char *) a->data;
+  unsigned char *alimit = aptr + a->length;
+  unsigned char *bptr = (unsigned char *) b->data;
+  unsigned char *blimit = bptr + b->length;
+
+  if (alimit[-1] == ';')
+    alimit--;
+
+  if (blimit[-1] == ';')
+    blimit--;
+
+  int ac = UTF8_GET(aptr, alimit);
+  int bc = UTF8_GET(bptr, blimit);
+
+  // Checks whether both strings have the same amount of leading [ characters.
+  while (ac == '[')
+    {
+      if (bc == '[')
+        {
+          ac = UTF8_GET(aptr, alimit);
+          bc = UTF8_GET(bptr, blimit);
+          continue;
+        }
+
+      return false;
+    }
+
+  // Skips leading L character.
+  if (ac == 'L')
+    ac = UTF8_GET(aptr, alimit);
+        
+  if (bc == 'L')
+    bc = UTF8_GET(bptr, blimit);
+
+  // Compares the remaining characters.
+  while (ac != -1 && bc != -1)
+    {
+      // Replaces package separating dots with slashes.
+      if (ac == '.')
+        ac = '/';
+
+      if (bc == '.')
+        bc = '/';
+      
+      // Now classnames differ if there is at least one non-matching
+      // character.
+      if (ac != bc)
+        return false;
+
+      ac = UTF8_GET(aptr, alimit);
+      bc = UTF8_GET(bptr, blimit);
+    }
+
+  return (ac == bc);
+}
+
 /* Count the number of Unicode chars encoded in a given Ut8 string. */
 int
-_Jv_strLengthUtf8(char* str, int len)
+_Jv_strLengthUtf8(const char* str, int len)
 {
   unsigned char* ptr;
   unsigned char* limit;
@@ -259,7 +374,7 @@ _Jv_strLengthUtf8(char* str, int len)
  * This returns the same hash value as specified or java.lang.String.hashCode.
  */
 jint
-_Jv_hashUtf8String (char* str, int len)
+_Jv_hashUtf8String (const char* str, int len)
 {
   unsigned char* ptr = (unsigned char*) str;
   unsigned char* limit = ptr + len;
@@ -276,7 +391,7 @@ _Jv_hashUtf8String (char* str, int len)
 }
 
 void
-_Jv_Utf8Const::init(char *s, int len)
+_Jv_Utf8Const::init(const char *s, int len)
 {
   ::memcpy (data, s, len);
   data[len] = 0;
@@ -285,7 +400,7 @@ _Jv_Utf8Const::init(char *s, int len)
 }
 
 _Jv_Utf8Const *
-_Jv_makeUtf8Const (char* s, int len)
+_Jv_makeUtf8Const (const char* s, int len)
 {
   if (len < 0)
     len = strlen (s);
@@ -359,6 +474,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()
@@ -418,6 +549,9 @@ _Jv_AllocObjectNoInitNoFinalizer (jclass klass)
 jobject
 _Jv_AllocObjectNoFinalizer (jclass klass)
 {
+  if (_Jv_IsPhantomClass(klass) )
+    throw new java::lang::NoClassDefFoundError(klass->getName());
+
   _Jv_InitClass (klass);
   jint size = klass->size ();
   jobject obj = (jobject) _Jv_AllocObj (size, klass);
@@ -496,6 +630,11 @@ _Jv_AllocPtrFreeObject (jclass klass)
 jobjectArray
 _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
 {
+  // Creating an array of an unresolved type is impossible. So we throw
+  // the NoClassDefFoundError.
+  if ( _Jv_IsPhantomClass(elementClass) )
+    throw new java::lang::NoClassDefFoundError(elementClass->getName());
+
   if (__builtin_expect (count < 0, false))
     throw new java::lang::NegativeArraySizeException;
 
@@ -655,7 +794,7 @@ DECLARE_PRIM_TYPE(double)
 DECLARE_PRIM_TYPE(void)
 
 void
-_Jv_InitPrimClass (jclass cl, char *cname, char sig, int len)
+_Jv_InitPrimClass (jclass cl, const char *cname, char sig, int len)
 {    
   using namespace java::lang::reflect;
 
@@ -750,7 +889,28 @@ _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader,
   return result;
 }
 
-\f
+
+jclass
+_Jv_FindClassFromSignatureNoException (char *sig, java::lang::ClassLoader *loader,
+                                       char **endp)
+{
+  jclass klass;
+
+  try
+    {
+      klass = _Jv_FindClassFromSignature(sig, loader, endp);
+    }
+  catch (java::lang::NoClassDefFoundError *ncdfe)
+    {
+      return NULL;
+    }
+  catch (java::lang::ClassNotFoundException *cnfe)
+    {
+      return NULL;
+    }
+
+  return klass;
+}
 
 JArray<jstring> *
 JvConvertArgv (int argc, const char **argv)
@@ -841,10 +1001,6 @@ next_property_value (char *s, size_t *length)
   while (isspace (*s))
     s++;
 
-  // If we've reached the end, return NULL.
-  if (*s == 0)
-    return NULL;
-
   // Determine the length of the property value.
   while (s[l] != 0
         && ! isspace (s[l])
@@ -867,13 +1023,18 @@ static void
 process_gcj_properties ()
 {
   char *props = getenv("GCJ_PROPERTIES");
-  char *p = props;
-  size_t length;
-  size_t property_count = 0;
 
   if (NULL == props)
     return;
 
+  // Later on we will write \0s into this string.  It is simplest to
+  // just duplicate it here.
+  props = strdup (props);
+
+  char *p = props;
+  size_t length;
+  size_t property_count = 0;
+
   // Whip through props quickly in order to count the number of
   // property values.
   while (p && (p = next_property_key (p, &length)))
@@ -937,6 +1098,15 @@ 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;
+
+  // Thread stack size specified by the -Xss runtime argument.
+  size_t stack_size = 0;
 }
 
 // We accept all non-standard options accepted by Sun's java command,
@@ -1023,7 +1193,7 @@ parse_x_arg (char* option_string)
     }
   else if (! strncmp (option_string, "ss", 2))
     {
-      // FIXME: set thread stack size
+      _Jv_SetStackSize (option_string + 2);
     }
   else if (! strcmp (option_string, "X:+UseAltSigs"))
     {
@@ -1049,7 +1219,7 @@ static jint
 parse_verbose_args (char* option_string,
                     bool ignore_unrecognized)
 {
-  size_t len = sizeof ("-verbose");
+  size_t len = sizeof ("-verbose") - 1;
 
   if (strlen (option_string) < len)
     return -1;
@@ -1058,69 +1228,72 @@ parse_verbose_args (char* option_string,
       && option_string[len + 1] != '\0')
     {
       char* verbose_args = option_string + len + 1;
-      size_t last = 0;
 
       do
        {
          if (! strncmp (verbose_args,
-                        "gc", (last = sizeof ("gc")) - 1)
-             && (verbose_args[last] == '\0'
-                 || verbose_args[last] == ','))
-           {
-             // FIXME: we should add functions to boehm-gc that
-             // toggle GC_print_stats, GC_PRINT_ADDRESS_MAP and
-             // GC_print_back_height.
-
-           }
+                        "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",
-                             (last = sizeof ("class")) - 1)
-                  && (verbose_args[last] == '\0'
-                      || verbose_args[last] == ','))
-           {
-             gcj::verbose_class_flag = true;
-           }
+                             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",
-                             (last = sizeof ("jni")) - 1)
-                  && (verbose_args[last] == '\0'
-                      || verbose_args[last] == ','))
-           {
-             // FIXME: enable JNI messages.
-           }
+                             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
-             last = 0;
-             while (verbose_args[last] != '\0'
-                    && verbose_args[last++] != ',');
-           }
-
-         if (strlen (verbose_args) >= last)
-           {
-             if (verbose_args[last] == ',')
-               {
-                 if (verbose_args[last + 1] == '\0')
-                   // trailing comma
-                   return -1;
-                 else
-                   {
-                     verbose_args = verbose_args + last + 1;
-                     last = 0;
-                   }
-               }
-             // here verbose_args[last] is either '\0' or
-             // the first character in the next verbose
-             // argument.
+             while (verbose_args[0] != '\0'
+                    && verbose_args[0] != ',')
+                verbose_args++;
            }
-         else
-           // partial option
-           return -1;
+          else if (verbose_args[0] == ',')
+            {
+              verbose_args++;
+            }
+          else
+            goto verbose_arg_err;
 
-         // verbose_args[last] will be '\0' here if we're
-         // done.
+          if (verbose_args[0] == ',')
+            verbose_args++;
        }
-      while (verbose_args[last] != '\0');
+      while (verbose_args[0] != '\0');
     }
   else if (option_string[len] == 'g'
           && option_string[len + 1] == 'c'
@@ -1359,10 +1532,10 @@ _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc,
 
   _Jv_AttachCurrentThread (main_thread);
   _Jv_ThreadRun (main_thread);
-  _Jv_ThreadWait ();
 
-  int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
-  runtime->exit (status);
+  // If we got here then something went wrong, as MainThread is not
+  // supposed to terminate.
+  ::exit (1);
 }
 
 void
@@ -1382,7 +1555,7 @@ JvRunMain (jclass klass, int argc, const char **argv)
 
 // Parse a string and return a heap size.
 static size_t
-parse_heap_size (const char *spec)
+parse_memory_size (const char *spec)
 {
   char *end;
   unsigned long val = strtoul (spec, &end, 10);
@@ -1398,7 +1571,7 @@ parse_heap_size (const char *spec)
 void
 _Jv_SetInitialHeapSize (const char *arg)
 {
-  size_t size = parse_heap_size (arg);
+  size_t size = parse_memory_size (arg);
   _Jv_GCSetInitialHeapSize (size);
 }
 
@@ -1407,11 +1580,16 @@ _Jv_SetInitialHeapSize (const char *arg)
 void
 _Jv_SetMaximumHeapSize (const char *arg)
 {
-  size_t size = parse_heap_size (arg);
+  size_t size = parse_memory_size (arg);
   _Jv_GCSetMaximumHeapSize (size);
 }
 
-\f
+void
+_Jv_SetStackSize (const char *arg)
+{
+  size_t size = parse_memory_size (arg);
+  gcj::stack_size = size;
+}
 
 void *
 _Jv_Malloc (jsize size)
@@ -1532,7 +1710,7 @@ _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags)
   return ((self_klass == other_klass)
          || ((flags & Modifier::PUBLIC) != 0)
          || (((flags & Modifier::PROTECTED) != 0)
-             && _Jv_IsAssignableFromSlow (other_klass, self_klass))
+             && _Jv_IsAssignableFromSlow (self_klass, other_klass))
          || (((flags & Modifier::PRIVATE) == 0)
              && _Jv_ClassNameSamePackage (self_klass->name,
                                           other_klass->name)));