PR libgcj/12016, PR libgcj/18405, PR libgcj/17738:
authorTom Tromey <tromey@redhat.com>
Mon, 10 Jan 2005 19:39:26 +0000 (19:39 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Mon, 10 Jan 2005 19:39:26 +0000 (19:39 +0000)
* java/lang/Package.java (getPackages): Use VMClassLoader when
appropriate.
(getPackage): Likewise.
* prims.cc (_Jv_CreateJavaVM): Call
_Jv_RegisterBootstrapPackages.
* include/jvm.h (_Jv_RegisterBootstrapPackages): Declare.
* java/lang/VMClassLoader.java (getPackage): Rewrote.
(getPackages): Likewise.
(definedPackages): New field.
(definePackageForNative): New method.
* java/lang/Class.h (_Jv_FindClassInCache): Updated.
* java/lang/natVMClassLoader.cc (loadClass): Updated.
* defineclass.cc (handleClassBegin): Use
ClassLoader.findLoadedClass.
* java/lang/natClassLoader.cc (_Jv_RegisterInitiatingLoader):
Rewrote.
(struct _Jv_LoaderInfo): Removed.
(initiated_classes): Likewise.
(_Jv_UnregisterClass): Don't use initiated_classes.
(_Jv_FindClassInCache): Likewise.  Removed 'loader' argument.
(_Jv_FindClass): Register classes found during boostrap.
(BOOTSTRAP_CLASS_LIST_SIZE): New define.
(bootstrap_class_list): New global.
(bootstrap_index): Likewise.
(_Jv_RegisterBootstrapPackages): New function.
* gnu/gcj/runtime/natVMClassLoader.cc (findClass): Call
definePackageForNative.
(findClass): Updated.
* gnu/gcj/runtime/VMClassLoader.java (definePackageForNative):
New method.

From-SVN: r93155

libjava/ChangeLog
libjava/defineclass.cc
libjava/gnu/gcj/runtime/VMClassLoader.java
libjava/gnu/gcj/runtime/natVMClassLoader.cc
libjava/include/jvm.h
libjava/java/lang/Class.h
libjava/java/lang/Package.java
libjava/java/lang/VMClassLoader.java
libjava/java/lang/natClassLoader.cc
libjava/java/lang/natVMClassLoader.cc
libjava/prims.cc

index 17f4d64cf2242e8f3f7caf672f8987bdfa14e913..a1b28a63546ed316142bb8d76ef2a57126aacb26 100644 (file)
@@ -1,3 +1,37 @@
+2005-01-10  Tom Tromey  <tromey@redhat.com>
+
+       PR libgcj/12016, PR libgcj/18405, PR libgcj/17738:
+       * java/lang/Package.java (getPackages): Use VMClassLoader when
+       appropriate.
+       (getPackage): Likewise.
+       * prims.cc (_Jv_CreateJavaVM): Call
+       _Jv_RegisterBootstrapPackages.
+       * include/jvm.h (_Jv_RegisterBootstrapPackages): Declare.
+       * java/lang/VMClassLoader.java (getPackage): Rewrote.
+       (getPackages): Likewise.
+       (definedPackages): New field.
+       (definePackageForNative): New method.
+       * java/lang/Class.h (_Jv_FindClassInCache): Updated.
+       * java/lang/natVMClassLoader.cc (loadClass): Updated.
+       * defineclass.cc (handleClassBegin): Use
+       ClassLoader.findLoadedClass.
+       * java/lang/natClassLoader.cc (_Jv_RegisterInitiatingLoader):
+       Rewrote.
+       (struct _Jv_LoaderInfo): Removed.
+       (initiated_classes): Likewise.
+       (_Jv_UnregisterClass): Don't use initiated_classes.
+       (_Jv_FindClassInCache): Likewise.  Removed 'loader' argument.
+       (_Jv_FindClass): Register classes found during boostrap.
+       (BOOTSTRAP_CLASS_LIST_SIZE): New define.
+       (bootstrap_class_list): New global.
+       (bootstrap_index): Likewise.
+       (_Jv_RegisterBootstrapPackages): New function.
+       * gnu/gcj/runtime/natVMClassLoader.cc (findClass): Call
+       definePackageForNative.
+       (findClass): Updated.
+       * gnu/gcj/runtime/VMClassLoader.java (definePackageForNative):
+       New method.
+
 2005-01-10  Tom Tromey  <tromey@redhat.com>
 
        PR libgcj/18868:
index 1a0c4e4da603988e22e36e072070c2b964872429..a40bff1758e89fe4c9ed44a7b4603e6c70e2ac4e 100644 (file)
@@ -1,6 +1,6 @@
 // defineclass.cc - defining a class from .class format.
 
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -868,7 +868,7 @@ _Jv_ClassReader::handleClassBegin (int access_flags, int this_class, int super_c
   // was ClassLoader.defineClass called with an expected class name?
   if (def->name == 0)
     {
-      jclass orig = _Jv_FindClassInCache (loadedName, def->loader);
+      jclass orig = def->loader->findLoadedClass(loadedName->toString());
 
       if (orig == 0)
        {
index f9ef872b30a5c5e1309a1fdd842ff7a39527b7b0..2d46ebcb770dfaf17f4f93d50fdc7785e565e3ab 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -118,6 +118,27 @@ public final class VMClassLoader extends java.net.URLClassLoader
     instance.init();
   }
 
+  // Define a package for something loaded natively.
+  void definePackageForNative(String className)
+  {
+    int lastDot = className.lastIndexOf('.');
+    if (lastDot != -1)
+      {
+       String packageName = className.substring(0, lastDot);
+       if (getPackage(packageName) == null)
+         {
+           // FIXME: this assumes we're defining the core, which
+           // isn't necessarily so.  We could detect this and set up
+           // appropriately.  We could also look at a manifest file
+           // compiled into the .so.
+           definePackage(packageName, "Java Platform API Specification",
+                         "GNU", "1.4", "gcj", "GNU",
+                         null, // FIXME: gcj version.
+                         null);
+         }
+      }
+  }
+
   // This keeps track of shared libraries we've already tried to load.
   private HashSet tried_libraries = new HashSet();
 
index 42ac2a02107b2f41cf9bb029bfd2582575084737..7f2ee34eb32d219898a26f765895e28a2dc2bc38 100644 (file)
@@ -1,6 +1,6 @@
 // Native code for VMClassLoader
 
-/* Copyright (C) 2002, 2003  Free Software Foundation
+/* Copyright (C) 2002, 2003, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -24,7 +24,7 @@ jclass
 gnu::gcj::runtime::VMClassLoader::findClass (jstring name)
 {
   _Jv_Utf8Const *name_u = _Jv_makeUtf8Const (name);
-  jclass klass = _Jv_FindClassInCache (name_u, 0);
+  jclass klass = _Jv_FindClassInCache (name_u);
 
   if (! klass && lib_control != LIB_NEVER)
     {
@@ -65,12 +65,14 @@ gnu::gcj::runtime::VMClassLoader::findClass (jstring name)
            so_base_name = so_base_name->substring (0, nd);
 
          if (loaded)
-           klass = _Jv_FindClassInCache (name_u, 0);
+           klass = _Jv_FindClassInCache (name_u);
        }
     }
 
-  // Now try loading using the interpreter.
-  if (! klass)
+  // Either define the package, or try loading using the interpreter.
+  if (klass)
+    definePackageForNative(name);
+  else
     klass = java::net::URLClassLoader::findClass (name);
 
   return klass;
index 52471bfac9a75bb5bb6bc583c9d678a33d0aecf1..d45ef25b6997e962edddb45586f55b4795f6ed29 100644 (file)
@@ -561,4 +561,6 @@ extern void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event);
 /* FIXME: this should really be defined in some more generic place */
 #define ROUND(V, A) (((((unsigned) (V))-1) | ((A)-1))+1)
 
+extern void _Jv_RegisterBootstrapPackages ();
+
 #endif /* __JAVA_JVM_H__ */
index f38f16f680eeced188a1e30f6880f151aaa4db40..cea1c13a8e2edbe42ff562517be74fb9bdb6a2cb 100644 (file)
@@ -1,6 +1,6 @@
 // Class.h - Header file for java.lang.Class.  -*- c++ -*-
 
-/* 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.
 
@@ -215,8 +215,7 @@ void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*);
 void _Jv_UnregisterClass (jclass);
 jclass _Jv_FindClass (_Jv_Utf8Const *name,
                      java::lang::ClassLoader *loader);
-jclass _Jv_FindClassInCache (_Jv_Utf8Const *name,
-                            java::lang::ClassLoader *loader);
+jclass _Jv_FindClassInCache (_Jv_Utf8Const *name);
 jclass _Jv_PopClass (void);
 void _Jv_PushClass (jclass k);
 void _Jv_NewArrayClass (jclass element,
@@ -440,8 +439,7 @@ private:
   friend void ::_Jv_UnregisterClass (jclass);
   friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name,
                                   java::lang::ClassLoader *loader);
-  friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name,
-                                         java::lang::ClassLoader *loader);
+  friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name);
   friend jclass (::_Jv_PopClass) (void);
   friend void ::_Jv_PushClass (jclass k);
   friend void ::_Jv_NewArrayClass (jclass element,
index 89945cadd8a15638539e7a7cd3dc2f51c6b0b6dd..29b42b63cf12a92d09aef78f627dfe6858d25711 100644 (file)
@@ -1,5 +1,5 @@
 /* Package.java -- information about a package
-   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -274,7 +274,7 @@ public class Package
   {
     // Get the caller's classloader
     ClassLoader cl = VMSecurityManager.currentClassLoader();
-    return cl != null ? cl.getPackage(name) : null;
+    return cl != null ? cl.getPackage(name) : VMClassLoader.getPackage(name);
   }
 
   /**
@@ -288,10 +288,7 @@ public class Package
     // Get the caller's classloader
     Class c = VMSecurityManager.getClassContext()[1];
     ClassLoader cl = c.getClassLoader();
-    // Sun's implementation returns the packages loaded by the bootstrap
-    // classloader if cl is null, but right now our bootstrap classloader
-    // does not create any Packages.
-    return cl != null ? cl.getPackages() : new Package[0];
+    return cl != null ? cl.getPackages() : VMClassLoader.getPackages();
   }
 
   /**
index 8f78f9bb6666cb562a6df11410cac41a7ac8fd1e..1afda4570ea363d32a5ab5c2fb47abb0cc385cd2 100644 (file)
@@ -1,6 +1,6 @@
 /* VMClassLoader.java -- Reference implementation of native interface
    required by ClassLoader
-   Copyright (C) 1998, 2001, 2002, 2003, 2004 Free Software Foundation
+   Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
 
 This file is part of GNU Classpath.
 
@@ -76,6 +76,8 @@ final class VMClassLoader
     unknownProtectionDomain = new ProtectionDomain(null, permissions);  
   }
 
+  static final HashMap definedPackages = new HashMap();
+
   /**
    * Helper to define a class using a string of bytes. This assumes that
    * the security checks have already been performed, if necessary.
@@ -173,9 +175,9 @@ final class VMClassLoader
    * @param name the name to find
    * @return the named package, if it exists
    */
-  static Package getPackage(String name)
+  static synchronized Package getPackage(String name)
   {
-    return null;
+    return (Package) definedPackages.get(name);
   }
 
   /**
@@ -185,9 +187,33 @@ final class VMClassLoader
    *
    * @return all named packages, if any exist
    */
-  static Package[] getPackages()
+  static synchronized Package[] getPackages()
+  {
+    Package[] packages = new Package[definedPackages.size()];
+    return (Package[]) definedPackages.values().toArray(packages);
+  }
+
+  // Define a package for something loaded natively.
+  static synchronized void definePackageForNative(String className)
   {
-    return new Package[0];
+    int lastDot = className.lastIndexOf('.');
+    if (lastDot != -1)
+      {
+       String packageName = className.substring(0, lastDot);
+       if (getPackage(packageName) == null)
+         {
+           // FIXME: this assumes we're defining the core, which
+           // isn't necessarily so.  We could detect this and set up
+           // appropriately.  We could also look at a manifest file
+           // compiled into the .so.
+           Package p = new Package(packageName,
+                                   "Java Platform API Specification",
+                                   "GNU", "1.4", "gcj", "GNU",
+                                   null, // FIXME: gcj version.
+                                   null);
+           definedPackages.put(packageName, p);
+         }
+      }
   }
 
   /**
index f6571bd66bacc463d7d8344aed8d4200dc2d3743..b05c1dd0a5bb9fe40b8d33d79e814d8d22e61185 100644 (file)
@@ -1,6 +1,6 @@
 // natClassLoader.cc - Implementation of java.lang.ClassLoader native methods.
 
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -42,19 +42,7 @@ details.  */
 #include <java/lang/StringBuffer.h>
 #include <java/io/Serializable.h>
 #include <java/lang/Cloneable.h>
-
-//
-//  A single class can have many "initiating" class loaders,
-//  and a single "defining" class loader.  The Defining
-//  class loader is what is returned from Class.getClassLoader()
-//  and is used when loading dependent classes during resolution.
-//  The set of initiating class loaders are used to ensure
-//  safety of linking, and is maintained in the hash table
-//  "initiated_classes".  A defining classloader is by definition also
-//  initiating, so we only store classes in this table if they have more
-//  than one class loader associated.
-//
-
+#include <java/util/HashMap.h>
 
 // Size of local hash table.
 #define HASH_LEN 1013
@@ -62,56 +50,37 @@ details.  */
 // Hash function for Utf8Consts.
 #define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN)
 
-struct _Jv_LoaderInfo
-{
-  _Jv_LoaderInfo          *next;
-  java::lang::Class       *klass;
-  java::lang::ClassLoader *loader;
-};
-
-static _Jv_LoaderInfo *initiated_classes[HASH_LEN];
 static jclass loaded_classes[HASH_LEN];
 
 // This is the root of a linked list of classes
 static jclass stack_head;
 
+// While bootstrapping we keep a list of classes we found, so that we
+// can register their packages.  There aren't many of these so we
+// just keep a small buffer here and abort if we overflow.
+#define BOOTSTRAP_CLASS_LIST_SIZE 20
+static jclass bootstrap_class_list[BOOTSTRAP_CLASS_LIST_SIZE];
+static int bootstrap_index;
+
 
 \f
 
+// This tries to find a class in our built-in cache.  This cache is
+// used only for classes which are linked in to the executable or
+// loaded via dlopen().
 jclass
-_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
+_Jv_FindClassInCache (_Jv_Utf8Const *name)
 {
   JvSynchronize sync (&java::lang::Class::class$);
   jint hash = HASH_UTF (name);
 
-  if (loader && loader == java::lang::ClassLoader::getSystemClassLoader())
-    loader = NULL;
-
-  // first, if LOADER is a defining loader, then it is also initiating
   jclass klass;
   for (klass = loaded_classes[hash]; klass; klass = klass->next)
     {
-      if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name))
+      if (_Jv_equalUtf8Consts (name, klass->name))
        break;
     }
 
-  // otherwise, it may be that the class in question was defined
-  // by some other loader, but that the loading was initiated by 
-  // the loader in question.
-  if (!klass)
-    {
-      _Jv_LoaderInfo *info;
-      for (info = initiated_classes[hash]; info; info = info->next)
-       {
-         if (loader == info->loader
-             && _Jv_equalUtf8Consts (name, info->klass->name))
-           {
-             klass = info->klass;
-             break;
-           }
-       }
-    }
-
   return klass;
 }
 
@@ -130,38 +99,15 @@ _Jv_UnregisterClass (jclass the_class)
          break;
        }
     }
-
-  _Jv_LoaderInfo **info = &(initiated_classes[hash]);
-  for ( ; ; info = &((*info)->next))
-    {
-      while (*info && (*info)->klass == the_class)
-       {
-         _Jv_LoaderInfo *old = *info;
-         *info = (*info)->next;
-         _Jv_Free (old);
-       }
-
-      if (*info == NULL)
-       break;
-    }
 }
 
+// Register an initiating class loader for a given class.
 void
 _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
 {
-  if (loader && loader == java::lang::ClassLoader::getSystemClassLoader())
-    loader = NULL;
-
-  // This information can't be visible to the GC.
-  _Jv_LoaderInfo *info
-    = (_Jv_LoaderInfo *) _Jv_Malloc (sizeof(_Jv_LoaderInfo));
-  jint hash = HASH_UTF(klass->name);
-
-  JvSynchronize sync (&java::lang::Class::class$);
-  info->loader = loader;
-  info->klass  = klass;
-  info->next   = initiated_classes[hash];
-  initiated_classes[hash] = info;
+  if (! loader)
+    loader = java::lang::ClassLoader::getSystemClassLoader();
+  loader->loadedClasses->put(klass->name->toString(), klass);
 }
 
 // This function is called many times during startup, before main() is
@@ -254,15 +200,21 @@ _Jv_RegisterClass (jclass klass)
 jclass
 _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
 {
-  jclass klass = _Jv_FindClassInCache (name, loader);
+  // See if the class was already loaded by this loader.  This handles
+  // initiating loader checks, as we register classes with their
+  // initiating loaders.
+  java::lang::ClassLoader *sys
+    = java::lang::ClassLoader::getSystemClassLoader ();
+  java::lang::ClassLoader *real = loader;
+  if (! real)
+    real = sys;
+  jstring sname = name->toString();
+  // We might still be bootstrapping the VM, in which case there
+  // won't be a system class loader yet.
+  jclass klass = real ? real->findLoadedClass (sname) : NULL;
 
   if (! klass)
     {
-      jstring sname = name->toString();
-
-      java::lang::ClassLoader *sys
-       = java::lang::ClassLoader::getSystemClassLoader ();
-
       if (loader)
        {
          // Load using a user-defined loader, jvmspec 5.3.2
@@ -277,7 +229,7 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
          if (klass && klass->getClassLoaderInternal () != delegate)
            _Jv_RegisterInitiatingLoader (klass, loader);
        }
-      else 
+      else if (sys)
        {
          // Load using the bootstrap loader jvmspec 5.3.1.
          klass = sys->loadClass (sname, false); 
@@ -286,6 +238,15 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
          if (klass)
            _Jv_RegisterInitiatingLoader (klass, 0);
        }
+      else
+       {
+         // Not even a bootstrap loader, try the built-in cache.
+         klass = _Jv_FindClassInCache (name);
+
+         if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE)
+           abort ();
+         bootstrap_class_list[bootstrap_index++] = klass;
+       }
     }
   else
     {
@@ -297,6 +258,13 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
   return klass;
 }
 
+void
+_Jv_RegisterBootstrapPackages ()
+{
+  for (int i = 0; i < bootstrap_index; ++i)
+    java::lang::VMClassLoader::definePackageForNative(bootstrap_class_list[i]->getName());
+}
+
 jclass
 _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
              java::lang::ClassLoader *loader)
index 841b3e0789e1d60ef630ce0425a5915e3511f722..e34be99296dee8771a867d2c2560446e7c3bd435 100644 (file)
@@ -1,6 +1,6 @@
 // natVMClassLoader.cc - VMClassLoader native methods
 
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -130,7 +130,7 @@ jclass
 java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve)
 {
   _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name);
-  jclass klass = _Jv_FindClassInCache (utf, NULL);
+  jclass klass = _Jv_FindClassInCache (utf);
   if (klass)
     {
       // We never want to return a class without its supers linked.
@@ -140,6 +140,9 @@ java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve)
        _Jv_InitClass (klass);
       else
        _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING);
+
+      definePackageForNative(name);
     }
+
   return klass;
 }
index e3d5750cd1ce002e0a43ece024967c0ec05053ea..ac48d0dd9e3b32564eff4001dfc5e3b9bdd392eb 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.
 
@@ -968,6 +968,8 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
   // system loader, by having it read the class path.
   gnu::gcj::runtime::VMClassLoader::initialize();
 
+  _Jv_RegisterBootstrapPackages();
+
   no_memory = new java::lang::OutOfMemoryError;
 
   java::lang::VMThrowable::trace_enabled = 1;