Path: FYI: Fix several libgcj PRs

Tom Tromey tromey@redhat.com
Mon Jan 10 19:37:00 GMT 2005


I'm checking this in.

This fixes PRs 12016, 17738, and 18405.

Basically this changes how we register classes.  We no longer keep
track of initiating class loaders in C++; instead, we store them
directly in the ClassLoader (this is safe as there is no way for user
code to modify the map).  _Jv_FindClassInCache is no longer used to
search both classes loaded by dlopen (or linked in) and the initiating
loaders map; only the former.  This patch also includes some code to
register Packages for classes loaded by the bootstrap loader.  In
particular, "java.lang" will always be defined as a Package (jonas
needs this).

Tested as usual: x86 FC2, plus running Eclipse.  There is a new mauve
test for the Package functionality.

Tom

Index: ChangeLog
from  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.

Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.42
diff -u -r1.42 defineclass.cc
--- defineclass.cc 25 Nov 2004 03:46:56 -0000 1.42
+++ defineclass.cc 10 Jan 2005 19:27:14 -0000
@@ -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 @@
   // 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: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.100
diff -u -r1.100 prims.cc
--- prims.cc 25 Nov 2004 03:46:56 -0000 1.100
+++ prims.cc 10 Jan 2005 19:27:14 -0000
@@ -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 @@
   // 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;
Index: gnu/gcj/runtime/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/VMClassLoader.java,v
retrieving revision 1.16
diff -u -r1.16 VMClassLoader.java
--- gnu/gcj/runtime/VMClassLoader.java 25 Nov 2004 03:46:59 -0000 1.16
+++ gnu/gcj/runtime/VMClassLoader.java 10 Jan 2005 19:27:14 -0000
@@ -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 @@
     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: gnu/gcj/runtime/natVMClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/natVMClassLoader.cc,v
retrieving revision 1.2
diff -u -r1.2 natVMClassLoader.cc
--- gnu/gcj/runtime/natVMClassLoader.cc 20 Aug 2003 15:32:23 -0000 1.2
+++ gnu/gcj/runtime/natVMClassLoader.cc 10 Jan 2005 19:27:14 -0000
@@ -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 @@
 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 @@
 	    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: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.72
diff -u -r1.72 jvm.h
--- include/jvm.h 10 Jan 2005 19:21:46 -0000 1.72
+++ include/jvm.h 10 Jan 2005 19:27:15 -0000
@@ -561,4 +561,6 @@
 /* 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: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.74
diff -u -r1.74 Class.h
--- java/lang/Class.h 26 Nov 2004 02:27:54 -0000 1.74
+++ java/lang/Class.h 10 Jan 2005 19:27:15 -0000
@@ -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_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 @@
   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: java/lang/Package.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Package.java,v
retrieving revision 1.9
diff -u -r1.9 Package.java
--- java/lang/Package.java 18 Oct 2004 10:41:55 -0000 1.9
+++ java/lang/Package.java 10 Jan 2005 19:27:15 -0000
@@ -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 @@
   {
     // 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 @@
     // 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: java/lang/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMClassLoader.java,v
retrieving revision 1.11
diff -u -r1.11 VMClassLoader.java
--- java/lang/VMClassLoader.java 25 Nov 2004 03:47:04 -0000 1.11
+++ java/lang/VMClassLoader.java 10 Jan 2005 19:27:15 -0000
@@ -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 @@
     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 @@
    * @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 @@
    *
    * @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: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.73
diff -u -r1.73 natClassLoader.cc
--- java/lang/natClassLoader.cc 21 Dec 2004 01:03:55 -0000 1.73
+++ java/lang/natClassLoader.cc 10 Jan 2005 19:27:16 -0000
@@ -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 @@
 #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 @@
 // 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;
+
 
 
 
+// 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 @@
 	  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 @@
 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 @@
 	  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 @@
 	  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 @@
   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: java/lang/natVMClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natVMClassLoader.cc,v
retrieving revision 1.3
diff -u -r1.3 natVMClassLoader.cc
--- java/lang/natVMClassLoader.cc 25 Nov 2004 03:47:05 -0000 1.3
+++ java/lang/natVMClassLoader.cc 10 Jan 2005 19:27:16 -0000
@@ -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 @@
 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 @@
 	_Jv_InitClass (klass);
       else
 	_Jv_Linker::wait_for_state (klass, JV_STATE_LOADING);
+
+      definePackageForNative(name);
     }
+
   return klass;
 }



More information about the Java-patches mailing list