This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: FYI: ClassLoader merge


I'm checking this in on the trunk.

Inspired by Nathanael's recent merging, I tackled the ClassLoader
merge, which has been pending a long time.

This provides the usual benefits of a merge, fixes at least one
ClassLoader bug, and adds support for the java.system.class.loader
property.

Tested on x86 Red Hat Linux 9, including jacks and mauve, with no
regressions.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* java/lang/reflect/Proxy.java (generate): Uncomment protection
	domain code.
	* java/lang/natClassLoader.cc (defineClass): Added `loader'
	argument.
	(linkClass0): Now in VMClassLoader.
	(markClassErrorState0): Likewise.
	(getSystemClassLoaderInternal): New method.
	* java/lang/natClass.cc (initializeClass): Use
	VMClassLoader::resolveClass.
	* java/lang/ClassLoader.java: New version, from Classpath.
	* java/lang/Class.java (getProtectionDomain):
	protectionDomainPermission and unknownProtectionDomain now in
	VMClassLoader.
	* java/lang/Class.h: VMClassLoader now a friend class.
	* gnu/gcj/runtime/VMClassLoader.java (instance): Now
	package-private.
	* gcj/javaprims.h: Regenerated class list.
	* resolve.cc (_Jv_PrepareClass): Use VMClassLoader::resolveClass.
	* java/lang/VMClassLoader.java: New version from Classpath;
	modified for libgcj use.

Index: resolve.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/resolve.cc,v
retrieving revision 1.41
diff -u -r1.41 resolve.cc
--- resolve.cc 21 Jul 2003 01:54:05 -0000 1.41
+++ resolve.cc 25 Sep 2003 07:36:47 -0000
@@ -32,6 +32,7 @@
 #include <java/lang/AbstractMethodError.h>
 #include <java/lang/NoClassDefFoundError.h>
 #include <java/lang/IncompatibleClassChangeError.h>
+#include <java/lang/VMClassLoader.h>
 #include <java/lang/reflect/Modifier.h>
 
 using namespace gcj;
@@ -435,7 +436,7 @@
   // resolved.
 
   if (klass->superclass)
-    java::lang::ClassLoader::resolveClass0 (klass->superclass);
+    java::lang::VMClassLoader::resolveClass (klass->superclass);
 
   _Jv_InterpClass *clz = (_Jv_InterpClass*)klass;
 
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.45
diff -u -r1.45 javaprims.h
--- gcj/javaprims.h 20 Jan 2003 06:46:28 -0000 1.45
+++ gcj/javaprims.h 25 Sep 2003 07:36:48 -0000
@@ -1,6 +1,6 @@
 // javaprims.h - Main external header file for libgcj.  -*- c++ -*-
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -371,6 +371,39 @@
         class JarInputStream;
         class JarOutputStream;
         class Manifest;
+      }
+
+      namespace logging
+      {
+        class ConsoleHandler;
+        class ErrorManager;
+        class FileHandler;
+        class Filter;
+        class Formatter;
+        class Handler;
+        class Level;
+        class LogManager;
+        class LogRecord;
+        class Logger;
+        class LoggingPermission;
+        class MemoryHandler;
+        class SimpleFormatter;
+        class SocketHandler;
+        class StreamHandler;
+        class XMLFormatter;
+      }
+
+      namespace prefs
+      {
+        class AbstractPreferences;
+        class BackingStoreException;
+        class InvalidPreferencesFormatException;
+        class NodeChangeEvent;
+        class NodeChangeListener;
+        class PreferenceChangeEvent;
+        class PreferenceChangeListener;
+        class Preferences;
+        class PreferencesFactory;
       }
 
       namespace regex
Index: gnu/gcj/runtime/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/VMClassLoader.java,v
retrieving revision 1.10
diff -u -r1.10 VMClassLoader.java
--- gnu/gcj/runtime/VMClassLoader.java 20 Aug 2003 15:32:23 -0000 1.10
+++ gnu/gcj/runtime/VMClassLoader.java 25 Sep 2003 07:36:48 -0000
@@ -90,7 +90,7 @@
   private int lib_control;
 
   // The only VMClassLoader that can exist.
-  public static VMClassLoader instance = new VMClassLoader();
+  static VMClassLoader instance = new VMClassLoader();
 
   private static final int LIB_FULL = 0;
   private static final int LIB_CACHE = 1;
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.57
diff -u -r1.57 Class.h
--- java/lang/Class.h 28 Aug 2003 22:17:37 -0000 1.57
+++ java/lang/Class.h 25 Sep 2003 07:36:48 -0000
@@ -290,6 +290,7 @@
 
   // Friends classes and functions to implement the ClassLoader
   friend class java::lang::ClassLoader;
+  friend class java::lang::VMClassLoader;
 
   friend class java::io::ObjectOutputStream;
   friend class java::io::ObjectInputStream;
Index: java/lang/Class.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.java,v
retrieving revision 1.16
diff -u -r1.16 Class.java
--- java/lang/Class.java 21 Jul 2003 01:54:05 -0000 1.16
+++ java/lang/Class.java 25 Sep 2003 07:36:48 -0000
@@ -227,12 +227,12 @@
   {
     SecurityManager sm = System.getSecurityManager();
     if (sm != null)
-      sm.checkPermission(ClassLoader.protectionDomainPermission);
+      sm.checkPermission(VMClassLoader.protectionDomainPermission);
     
     ProtectionDomain protectionDomain = getProtectionDomain0();
 
     if (protectionDomain == null)
-      return ClassLoader.unknownProtectionDomain;
+      return VMClassLoader.unknownProtectionDomain;
     else
       return protectionDomain;
   }
Index: java/lang/ClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/ClassLoader.java,v
retrieving revision 1.29
diff -u -r1.29 ClassLoader.java
--- java/lang/ClassLoader.java 21 Jul 2003 01:54:05 -0000 1.29
+++ java/lang/ClassLoader.java 25 Sep 2003 07:36:48 -0000
@@ -1,25 +1,56 @@
-// ClassLoader.java - Define policies for loading Java classes.
+/* ClassLoader.java -- responsible for loading classes into the VM
+   Copyright (C) 1998, 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Free Software Foundation
+This file is part of GNU Classpath.
 
-   This file is part of libgcj.
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
 
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
-details.  */
 
 package java.lang;
 
 import java.io.InputStream;
 import java.io.IOException;
+import java.lang.reflect.Constructor;
 import java.net.URL;
-import java.security.AllPermission;
 import java.security.CodeSource;
-import java.security.Permission;
-import java.security.Permissions;
+import java.security.PermissionCollection;
 import java.security.Policy;
 import java.security.ProtectionDomain;
-import java.util.*;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import gnu.java.util.DoubleEnumeration;
+import gnu.java.util.EmptyEnumeration;
 
 /**
  * The ClassLoader is a way of customizing the way Java gets its classes
@@ -30,11 +61,11 @@
  * modification!
  *
  * <p>Every classloader has a parent classloader that is consulted before
- * the 'child' classloader when classes or resources should be loaded.   
+ * the 'child' classloader when classes or resources should be loaded.
  * This is done to make sure that classes can be loaded from an hierarchy of
- * multiple classloaders and classloaders do not accidentially redefine   
+ * multiple classloaders and classloaders do not accidentially redefine
  * already loaded classes by classloaders higher in the hierarchy.
- *   
+ *
  * <p>The grandparent of all classloaders is the bootstrap classloader, which
  * loads all the standard system classes as implemented by GNU Classpath. The
  * other special classloader is the system classloader (also called
@@ -78,8 +109,7 @@
  *
  * @author John Keiser
  * @author Mark Wielaard
- * @author Eric Blake
- * @author Kresten Krab Thorup
+ * @author Eric Blake <ebb9@email.byu.edu>
  * @see Class
  * @since 1.0
  * @status still missing 1.4 functionality
@@ -95,6 +125,50 @@
   final Map loadedClasses = new HashMap();
 
   /**
+   * All packages defined by this classloader. It is not private in order to
+   * allow native code (and trusted subclasses) access to this field.
+   */
+  final Map definedPackages = new HashMap();
+
+  /**
+   * The classloader that is consulted before this classloader.
+   * If null then the parent is the bootstrap classloader.
+   */
+  private final ClassLoader parent;
+
+  /**
+   * This is true if this classloader was successfully initialized.
+   * This flag is needed to avoid a class loader attack: even if the
+   * security manager rejects an attempt to create a class loader, the
+   * malicious class could have a finalize method which proceeds to
+   * define classes.
+   */
+  private final boolean initialized;
+
+  /**
+   * System/Application classloader: defaults to an instance of
+   * gnu.java.lang.SystemClassLoader, unless the first invocation of
+   * getSystemClassLoader loads another class loader because of the
+   * java.system.class.loader property. The initialization of this field
+   * is somewhat circular - getSystemClassLoader() checks whether this
+   * field is null in order to bypass a security check.
+   */
+  static final ClassLoader systemClassLoader =
+    VMClassLoader.getSystemClassLoader();
+
+  /**
+   * The default protection domain, used when defining a class with a null
+   * paramter for the domain.
+   */
+  static final ProtectionDomain defaultProtectionDomain;
+  static
+  {
+    CodeSource cs = new CodeSource(null, null);
+    PermissionCollection perm = Policy.getPolicy().getPermissions(cs);
+    defaultProtectionDomain = new ProtectionDomain(cs, perm);
+  }
+
+  /**
    * The desired assertion status of classes loaded by this loader, if not
    * overridden by package or class instructions.
    */
@@ -136,157 +210,105 @@
   Map classAssertionStatus;
 
   /**
-   * The classloader that is consulted before this classloader.
-   * If null then the parent is the bootstrap classloader.
-   */
-  private final ClassLoader parent;
-
-  /**
-   * All packages defined by this classloader. It is not private in order to
-   * allow native code (and trusted subclasses) access to this field.
-   */
-  private HashMap definedPackages = new HashMap();
-
-  /**
-   * Returns the parent of this classloader. If the parent of this
-   * classloader is the bootstrap classloader then this method returns
-   * <code>null</code>. A security check may be performed on
-   * <code>RuntimePermission("getClassLoader")</code>.
+   * Create a new ClassLoader with as parent the system classloader. There
+   * may be a security check for <code>checkCreateClassLoader</code>.
    *
    * @throws SecurityException if the security check fails
-   * @since 1.2
    */
-  public final ClassLoader getParent ()
+  protected ClassLoader() throws SecurityException
   {
-    // Check if we may return the parent classloader
-    SecurityManager sm = System.getSecurityManager();
-    if (sm != null)
-      {
-	Class c = VMSecurityManager.getClassContext()[1];
-	ClassLoader cl = c.getClassLoader();
-	if (cl != null && ! cl.isAncestorOf(this))
-	  sm.checkPermission(new RuntimePermission("getClassLoader"));
-      }
-    return parent;
+    this(systemClassLoader);
   }
 
   /**
-   * Returns the system classloader. The system classloader (also called
-   * the application classloader) is the classloader that was used to
-   * load the application classes on the classpath (given by the system
-   * property <code>java.class.path</code>. This is set as the context
-   * class loader for a thread. The system property
-   * <code>java.system.class.loader</code>, if defined, is taken to be the
-   * name of the class to use as the system class loader, which must have
-   * a public constructor which takes a ClassLoader as a parent; otherwise this
-   * uses gnu.java.lang.SystemClassLoader.
-   *
-   * <p>Note that this is different from the bootstrap classloader that
-   * actually loads all the real "system" classes (the bootstrap classloader
-   * is the parent of the returned system classloader).
+   * Create a new ClassLoader with the specified parent. The parent will
+   * be consulted when a class or resource is requested through
+   * <code>loadClass()</code> or <code>getResource()</code>. Only when the
+   * parent classloader cannot provide the requested class or resource the
+   * <code>findClass()</code> or <code>findResource()</code> method
+   * of this classloader will be called. There may be a security check for
+   * <code>checkCreateClassLoader</code>.
    *
-   * <p>A security check will be performed for
-   * <code>RuntimePermission("getClassLoader")</code> if the calling class
-   * is not a parent of the system class loader.
-   *
-   * @return the system class loader
+   * @param parent the classloader's parent, or null for the bootstrap
+   *        classloader
    * @throws SecurityException if the security check fails
-   * @throws IllegalStateException if this is called recursively
-   * @throws Error if <code>java.system.class.loader</code> fails to load
    * @since 1.2
    */
-  public static ClassLoader getSystemClassLoader ()
+  protected ClassLoader(ClassLoader parent)
   {
-    return gnu.gcj.runtime.VMClassLoader.instance;
+    // May we create a new classloader?
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkCreateClassLoader();
+    this.parent = parent;
+    this.initialized = true;
   }
 
   /**
-   * Creates a <code>ClassLoader</code> with no parent.
-   * @exception java.lang.SecurityException if not allowed
+   * Load a class using this ClassLoader or its parent, without resolving
+   * it. Calls <code>loadClass(name, false)</code>.
+   *
+   * <p>Subclasses should not override this method but should override
+   * <code>findClass()</code> which is called by this method.
+   *
+   * @param name the name of the class relative to this ClassLoader
+   * @return the loaded class
+   * @throws ClassNotFoundException if the class cannot be found
    */
-  protected ClassLoader() 
+  public Class loadClass(String name) throws ClassNotFoundException
   {
-    this (null);
+    return loadClass(name, false);
   }
 
   /**
-   * Creates a <code>ClassLoader</code> with the given parent.   
-   * The parent may be <code>null</code>.
-   * The only thing this 
-   * constructor does, is to call
-   * <code>checkCreateClassLoader</code> on the current 
-   * security manager. 
-   * @exception java.lang.SecurityException if not allowed
-   * @since 1.2
+   * Load a class using this ClassLoader or its parent, possibly resolving
+   * it as well using <code>resolveClass()</code>. It first tries to find
+   * out if the class has already been loaded through this classloader by
+   * calling <code>findLoadedClass()</code>. Then it calls
+   * <code>loadClass()</code> on the parent classloader (or when there is
+   * no parent it uses the VM bootclassloader)</code>). If the class is still
+   * not loaded it tries to create a new class by calling
+   * <code>findClass()</code>. Finally when <code>resolve</code> is
+   * <code>true</code> it also calls <code>resolveClass()</code> on the
+   * newly loaded class.
+   *
+   * <p>Subclasses should not override this method but should override
+   * <code>findClass()</code> which is called by this method.
+   *
+   * @param name the fully qualified name of the class to load
+   * @param resolve whether or not to resolve the class
+   * @return the loaded class
+   * @throws ClassNotFoundException if the class cannot be found
    */
-  protected ClassLoader(ClassLoader parent) 
-  {
-    SecurityManager security = System.getSecurityManager ();
-    if (security != null)
-      security.checkCreateClassLoader ();
-    this.parent = parent;
-  }
-
-  /** 
-   * Loads and link the class by the given name.
-   * @param     name the name of the class.
-   * @return    the class loaded.
-   * @see       ClassLoader#loadClass(String,boolean)
-   * @exception java.lang.ClassNotFoundException 
-   */ 
-  public Class loadClass(String name)
-    throws java.lang.ClassNotFoundException
-  { 
-    return loadClass (name, false);
-  }
-  
-  /** 
-   * Loads the class by the given name.  The default implementation
-   * will search for the class in the following order (similar to jdk 1.2)
-   * <ul>
-   *  <li> First <code>findLoadedClass</code>.
-   *  <li> If parent is non-null, <code>parent.loadClass</code>;
-   *       otherwise <code>findSystemClass</code>.
-   *  <li> <code>findClass</code>.
-   * </ul>
-   * If <code>link</code> is true, <code>resolveClass</code> is then
-   * called.  <p> Normally, this need not be overridden; override
-   * <code>findClass</code> instead.
-   * @param     name the name of the class.
-   * @param     link if the class should be linked.
-   * @return    the class loaded.
-   * @exception java.lang.ClassNotFoundException 
-   */ 
-  protected Class loadClass(String name, boolean link)
-    throws java.lang.ClassNotFoundException
+  protected synchronized Class loadClass(String name, boolean resolve)
+    throws ClassNotFoundException
   {
-    Class c = findLoadedClass (name);
+    // Have we already loaded this class?
+    Class c = findLoadedClass(name);
+    if (c != null)
+      return c;
 
-    if (c == null)
+    // Can the class be loaded by a parent?
+    try
       {
-	try
+	if (parent == null)
 	  {
-	    ClassLoader cl = parent;
-	    if (parent == null)
-	      cl = gnu.gcj.runtime.VMClassLoader.instance;
-	    if (cl != this)
-	      c = cl.loadClass (name, link);
+	    c = VMClassLoader.loadClass(name, resolve);
+	    if (c != null)
+	      return c;
 	  }
-	catch (ClassNotFoundException ex)
+	else
 	  {
-	    /* ignore, we'll try findClass */;
+	    return parent.loadClass(name, resolve);
 	  }
       }
-
-    if (c == null)
-      c = findClass (name);
-
-    if (c == null)
-      throw new ClassNotFoundException (name);
-
-    if (link)
-      resolveClass (c);
-
+    catch (ClassNotFoundException e)
+      {
+      }
+    // Still not found, we have to do it ourself.
+    c = findClass(name);
+    if (resolve)
+      resolveClass(c);
     return c;
   }
 
@@ -331,59 +353,29 @@
    * @return the requested Class
    * @throws ClassNotFoundException when the class can not be found
    * @since 1.2
-   */   
-  protected Class findClass (String name)
-    throws ClassNotFoundException
-  {
-    throw new ClassNotFoundException (name);
-  }
-
-  // Protection Domain definitions 
-  // FIXME: should there be a special protection domain used for native code?
-  
-  // The permission required to check what a classes protection domain is.
-  static final Permission protectionDomainPermission
-    = new RuntimePermission("getProtectionDomain");
-  // The protection domain returned if we cannot determine it. 
-  static ProtectionDomain unknownProtectionDomain;
-  // Protection domain to use when a class is defined without one specified.
-  static ProtectionDomain defaultProtectionDomain;
-
-  static
+   */
+  protected Class findClass(String name) throws ClassNotFoundException
   {
-    Permissions permissions = new Permissions();
-    permissions.add(new AllPermission());
-    unknownProtectionDomain = new ProtectionDomain(null, permissions);  
-
-    CodeSource cs = new CodeSource(null, null);
-    defaultProtectionDomain =
-      new ProtectionDomain(cs, Policy.getPolicy().getPermissions(cs));
+    throw new ClassNotFoundException(name);
   }
 
-  /** 
-   * Defines a class, given the class-data.  According to the JVM, this
-   * method should not be used; instead use the variant of this method
-   * in which the name of the class being defined is specified
-   * explicitly.   
-   * <P>
-   * If the name of the class, as specified (implicitly) in the class
-   * data, denotes a class which has already been loaded by this class
-   * loader, an instance of
-   * <code>java.lang.ClassNotFoundException</code> will be thrown.
-   *
-   * @param     data    bytes in class file format.
-   * @param     off     offset to start interpreting data.
-   * @param     len     length of data in class file.
-   * @return    the class defined.
-   * @exception java.lang.ClassNotFoundException 
-   * @exception java.lang.LinkageError
-   * @see ClassLoader#defineClass(String,byte[],int,int)
+  /**
+   * Helper to define a class using a string of bytes. This version is not
+   * secure.
+   *
+   * @param data the data representing the classfile, in classfile format
+   * @param offset the offset into the data where the classfile starts
+   * @param len the length of the classfile data in the array
+   * @return the class that was defined
+   * @throws ClassFormatError if data is not in proper classfile format
+   * @throws IndexOutOfBoundsException if offset or len is negative, or
+   *         offset + len exceeds data
    * @deprecated use {@link #defineClass(String, byte[], int, int)} instead
    */
-  protected final Class defineClass(byte[] data, int off, int len) 
+  protected final Class defineClass(byte[] data, int offset, int len)
     throws ClassFormatError
   {
-    return defineClass (null, data, off, len, defaultProtectionDomain);
+    return defineClass(null, data, offset, len);
   }
 
   /**
@@ -405,351 +397,225 @@
    * @throws SecurityException if name starts with "java."
    * @since 1.1
    */
-  protected final Class defineClass(String name, byte[] data, int off, int len)
-    throws ClassFormatError
+  protected final Class defineClass(String name, byte[] data, int offset,
+                                    int len) throws ClassFormatError
   {
-    return defineClass (name, data, off, len, defaultProtectionDomain);
+    return defineClass(name, data, offset, len, null);
   }
-  
-  /** 
-   * Defines a class, given the class-data.  This is preferable
-   * over <code>defineClass(byte[],off,len)</code> since it is more
-   * secure.  If the expected name does not match that of the class
-   * file, <code>ClassNotFoundException</code> is thrown.  If
-   * <code>name</code> denotes the name of an already loaded class, a
-   * <code>LinkageError</code> is thrown.
-   * <p>
-   * 
-   * FIXME: How do we assure that the class-file data is not being
-   * modified, simultaneously with the class loader running!?  If this
-   * was done in some very clever way, it might break security.  
-   * Right now I am thinking that defineclass should make sure never to
-   * read an element of this array more than once, and that that would
-   * assure the ``immutable'' appearance.  It is still to be determined
-   * if this is in fact how defineClass operates.
-   *
-   * @param     name    the expected name.
-   * @param     data    bytes in class file format.
-   * @param     off     offset to start interpreting data.
-   * @param     len     length of data in class file.
-   * @param     protectionDomain security protection domain for the class.
-   * @return    the class defined.
-   * @exception java.lang.ClassNotFoundException 
-   * @exception java.lang.LinkageError
-   */
-  protected final synchronized Class defineClass(String name,
-						 byte[] data,
-						 int off,
-						 int len,
-						 ProtectionDomain protectionDomain)
-    throws ClassFormatError
-  {
-    if (data==null || data.length < off+len || off<0 || len<0)
-      throw new ClassFormatError ("arguments to defineClass "
-				  + "are meaningless");
-
-    // as per 5.3.5.1
-    if (name != null && findLoadedClass (name) != null)
-      throw new java.lang.LinkageError ("class " 
-					+ name 
-					+ " already loaded");
-
-    if (protectionDomain == null)
-      protectionDomain = defaultProtectionDomain;
 
-    try
-      {
-	Class retval = defineClass0 (name, data, off, len, protectionDomain);
-	loadedClasses.put(retval.getName(), retval);
-	return retval;
-      }
-    catch (LinkageError x)
-      {
-	throw x;		// rethrow
-      }
-    catch (VirtualMachineError x)
-      {
-	throw x;		// rethrow
-      }
-    catch (Throwable x)
-      {
-	// This should never happen, or we are beyond spec.  
-      	InternalError r = new InternalError ("Unexpected exception "
-					     + "while defining class "
-					     + name);
-	r.initCause(x);
-	throw r;
-      }
-  }
-
-  /** This is the entry point of defineClass into the native code */
-  private native Class defineClass0 (String name,
-				     byte[] data,
-				     int off,
-				     int len,
-				     ProtectionDomain protectionDomain)
-    throws ClassFormatError;
-
-  /** 
-   * Link the given class.  This will bring the class to a state where
-   * the class initializer can be run.  Linking involves the following
-   * steps: 
-   * <UL>
-   * <LI>  Prepare (allocate and internalize) the constant strings that
-   *       are used in this class.
-   * <LI>  Allocate storage for static fields, and define the layout
-   *       of instance fields.
-   * <LI>  Perform static initialization of ``static final'' int,
-   *       long, float, double and String fields for which there is a
-   *       compile-time constant initializer.
-   * <LI>  Create the internal representation of the ``vtable''.
-   * </UL>
-   * For <code>gcj</code>-compiled classes, only the first step is
-   * performed.  The compiler will have done the rest already.
-   * <P>
-   * This is called by the system automatically,
-   * as part of class initialization; there is no reason to ever call
-   * this method directly.  
-   * <P> 
-   * For historical reasons, this method has a name which is easily
-   * misunderstood.  Java classes are never ``resolved''.  Classes are
-   * linked; whereas method and field references are resolved.
-   *
-   * @param     clazz the class to link.
-   * @exception java.lang.LinkageError
-   */
-  protected final void resolveClass(Class clazz)
+  /**
+   * Helper to define a class using a string of bytes. Subclasses should call
+   * this method from their <code>findClass()</code> implementation. If the
+   * domain is null, the default of
+   * <code>Policy.getPolicy().getPermissions(new CodeSource(null, null))<code>
+   * is used. Once a class has been defined in a package, all further classes
+   * in that package must have the same set of certificates or a
+   * SecurityException is thrown.
+   *
+   * @param name the name to give the class.  null if unknown
+   * @param data the data representing the classfile, in classfile format
+   * @param offset the offset into the data where the classfile starts
+   * @param len the length of the classfile data in the array
+   * @param domain the ProtectionDomain to give to the class, null for the
+   *        default protection domain
+   * @return the class that was defined
+   * @throws ClassFormatError if data is not in proper classfile format
+   * @throws IndexOutOfBoundsException if offset or len is negative, or
+   *         offset + len exceeds data
+   * @throws SecurityException if name starts with "java.", or if certificates
+   *         do not match up
+   * @since 1.2
+   */
+  protected final synchronized Class defineClass(String name, byte[] data,
+						 int offset, int len,
+						 ProtectionDomain domain)
+    throws ClassFormatError
   {
-    resolveClass0(clazz);
+    if (domain == null)
+      domain = defaultProtectionDomain;
+    if (! initialized)
+      throw new SecurityException("attempt to define class from uninitialized class loader");
+    Class retval = VMClassLoader.defineClass(this, name, data,
+                                             offset, len, domain);
+    loadedClasses.put(retval.getName(), retval);
+    return retval;
   }
 
-  static void resolveClass0(Class clazz)
+  /**
+   * Links the class, if that has not already been done. Linking basically
+   * resolves all references to other classes made by this class.
+   *
+   * @param c the class to resolve
+   * @throws NullPointerException if c is null
+   * @throws LinkageError if linking fails
+   */
+  protected final void resolveClass(Class c)
   {
-    synchronized (clazz)
-      {
-	try
-	  {
-	    linkClass0 (clazz);
-	  }
-	catch (Throwable x)
-	  {
-	    markClassErrorState0 (clazz);
-
-	    LinkageError e;
-	    if (x instanceof LinkageError)
-	      e = (LinkageError)x;
-	    else if (x instanceof ClassNotFoundException)
-	      {
-		e = new NoClassDefFoundError("while resolving class: "
-					     + clazz.getName());
-		e.initCause (x);
-	      }
-	    else
-	      {
-		e = new LinkageError ("unexpected exception during linking: "
-				      + clazz.getName());
-		e.initCause (x);
-	      }
-	    throw e;
-	  }
-      }
+    VMClassLoader.resolveClass(c);
   }
 
-  /** Internal method.  Calls _Jv_PrepareClass and
-   * _Jv_PrepareCompiledClass.  This is only called from resolveClass.  */ 
-  private static native void linkClass0(Class clazz);
-
-  /** Internal method.  Marks the given clazz to be in an erroneous
-   * state, and calls notifyAll() on the class object.  This should only
-   * be called when the caller has the lock on the class object.  */
-  private static native void markClassErrorState0(Class clazz);
-
-  /**
-   * Defines a new package and creates a Package object.
-   * The package should be defined before any class in the package is
-   * defined with <code>defineClass()</code>. The package should not yet
-   * be defined before in this classloader or in one of its parents (which
-   * means that <code>getPackage()</code> should return <code>null</code>).
-   * All parameters except the <code>name</code> of the package may be
-   * <code>null</code>.
-   * <p>
-   * Subclasses should call this method from their <code>findClass()</code>
-   * implementation before calling <code>defineClass()</code> on a Class
-   * in a not yet defined Package (which can be checked by calling
-   * <code>getPackage()</code>).
-   *
-   * @param name The name of the Package
-   * @param specTitle The name of the specification
-   * @param specVendor The name of the specification designer
-   * @param specVersion The version of this specification
-   * @param implTitle The name of the implementation
-   * @param implVendor The vendor that wrote this implementation
-   * @param implVersion The version of this implementation
-   * @param sealed If sealed the origin of the package classes
-   * @return the Package object for the specified package
-   *
-   * @exception IllegalArgumentException if the package name is null or if
-   * it was already defined by this classloader or one of its parents.
+  /**
+   * Helper to find a Class using the system classloader, possibly loading it.
+   * A subclass usually does not need to call this, if it correctly
+   * overrides <code>findClass(String)</code>.
    *
-   * @see Package
-   * @since 1.2
+   * @param name the name of the class to find
+   * @return the found class
+   * @throws ClassNotFoundException if the class cannot be found
    */
-  protected Package definePackage(String name,
-				  String specTitle, String specVendor,
-				  String specVersion, String implTitle,
-				  String implVendor, String implVersion,
-				  URL sealed)
+  protected final Class findSystemClass(String name)
+    throws ClassNotFoundException
   {
-    if (getPackage(name) != null)
-      throw new IllegalArgumentException("Package " + name
-					 + " already defined");
-    Package p = new Package(name,
-			    specTitle, specVendor, specVersion,
-			    implTitle, implVendor, implVersion,
-			    sealed);
-    synchronized (definedPackages)
-    {
-      definedPackages.put(name, p);
-    }
-    return p;
+    return Class.forName(name, false, systemClassLoader);
   }
 
   /**
-   * Returns the Package object for the requested package name. It returns
-   * null when the package is not defined by this classloader or one of its
-   * parents.
+   * Returns the parent of this classloader. If the parent of this
+   * classloader is the bootstrap classloader then this method returns
+   * <code>null</code>. A security check may be performed on
+   * <code>RuntimePermission("getClassLoader")</code>.
    *
-   * @param name the package name to find
-   * @return the package, if defined
+   * @throws SecurityException if the security check fails
    * @since 1.2
    */
-  protected Package getPackage(String name)
+  public final ClassLoader getParent()
   {
-    Package p;
-    if (parent == null)
-      // XXX - Should we use the bootstrap classloader?
-      p = null;
-    else
-      p = parent.getPackage(name);
-
-    if (p == null)
+    // Check if we may return the parent classloader.
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
       {
-        synchronized (definedPackages)
-	{
-	  p = (Package) definedPackages.get(name);
-	}
+        Class c = VMSecurityManager.getClassContext()[1];
+        ClassLoader cl = c.getClassLoader();
+	if (cl != null && ! cl.isAncestorOf(this))
+          sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
-
-    return p;
+    return parent;
   }
 
   /**
-   * Returns all Package objects defined by this classloader and its parents.
+   * Helper to set the signers of a class. This should be called after
+   * defining the class.
    *
-   * @return an array of all defined packages
-   * @since 1.2
+   * @param c the Class to set signers of
+   * @param signers the signers to set
+   * @since 1.1
    */
-  protected Package[] getPackages()
+  protected final void setSigners(Class c, Object[] signers)
   {
-    Package[] allPackages;
-
-    // Get all our packages.
-    Package[] packages;
-    synchronized(definedPackages)
-    {
-      packages = new Package[definedPackages.size()];
-      definedPackages.values().toArray(packages);
-    }
-
-    // If we have a parent get all packages defined by our parents.
-    if (parent != null)
-      {
-	Package[] parentPackages = parent.getPackages();
-	allPackages = new Package[parentPackages.length + packages.length];
-	System.arraycopy(parentPackages, 0, allPackages, 0,
-			 parentPackages.length);
-	System.arraycopy(packages, 0, allPackages, parentPackages.length,
-			 packages.length);
-      }
-    else
-      // XXX - Should we use the bootstrap classloader?
-      allPackages = packages;
-
-    return allPackages;
+    //    c.setSigners(signers);
   }
 
   /**
-   * Called by <code>Runtime.loadLibrary()</code> to get an absolute path
-   * to a (system specific) library that was requested by a class loaded
-   * by this classloader. The default implementation returns
-   * <code>null</code>. It should be implemented by subclasses when they
-   * have a way to find the absolute path to a library. If this method
-   * returns null the library is searched for in the default locations
-   * (the directories listed in the <code>java.library.path</code> system
-   * property).
+   * Helper to find an already-loaded class in this ClassLoader.
    *
-   * @param name the (system specific) name of the requested library
-   * @return the full pathname to the requested library, or null
-   * @see Runtime#loadLibrary()
-   * @since 1.2
+   * @param name the name of the class to find
+   * @return the found Class, or null if it is not found
+   * @since 1.1
    */
-  protected String findLibrary(String name)
+  protected final synchronized Class findLoadedClass(String name)
   {
-    return null;
+    // NOTE: If the VM is keeping its own cache, it may make sense to have
+    // this method be native.
+    return (Class) loadedClasses.get(name);
   }
 
-  /** 
-   * Returns a class found in a system-specific way, typically
-   * via the <code>java.class.path</code> system property.  Loads the 
-   * class if necessary.
-   *
-   * @param     name the class to resolve.
-   * @return    the class loaded.
-   * @exception java.lang.LinkageError 
-   * @exception java.lang.ClassNotFoundException 
+  /**
+   * Get the URL to a resource using this classloader or one of its parents.
+   * First tries to get the resource by calling <code>getResource()</code>
+   * on the parent classloader. If the parent classloader returns null then
+   * it tries finding the resource by calling <code>findResource()</code> on
+   * this classloader. The resource name should be separated by '/' for path
+   * elements.
+   *
+   * <p>Subclasses should not override this method but should override
+   * <code>findResource()</code> which is called by this method.
+   *
+   * @param name the name of the resource relative to this classloader
+   * @return the URL to the resource or null when not found
    */
-  protected final Class findSystemClass(String name) 
-    throws java.lang.ClassNotFoundException
+  public URL getResource(String name)
   {
-    return gnu.gcj.runtime.VMClassLoader.instance.loadClass (name);
+    URL result;
+
+    if (parent == null)
+      result = VMClassLoader.getResource(name);
+    else
+      result = parent.getResource(name);
+
+    if (result == null)
+      result = findResource(name);
+    return result;
   }
 
   /**
-   * Helper to set the signers of a class. This should be called after
-   * defining the class.
+   * Returns an Enumeration of all resources with a given name that can
+   * be found by this classloader and its parents. Certain classloaders
+   * (such as the URLClassLoader when given multiple jar files) can have
+   * multiple resources with the same name that come from multiple locations.
+   * It can also occur that a parent classloader offers a resource with a
+   * certain name and the child classloader also offers a resource with that
+   * same name. <code>getResource() only offers the first resource (of the
+   * parent) with a given name. This method lists all resources with the
+   * same name. The name should use '/' as path separators.
    *
-   * @param c the Class to set signers of
-   * @param signers the signers to set
-   * @since 1.1
-   */   
-  protected final void setSigners(Class c, Object[] signers)
+   * <p>The Enumeration is created by first calling <code>getResources()</code>
+   * on the parent classloader and then calling <code>findResources()</code>
+   * on this classloader.
+   *
+   * @param name the resource name
+   * @return an enumaration of all resources found
+   * @throws IOException if I/O errors occur in the process
+   * @since 1.2
+   */
+  public final Enumeration getResources(String name) throws IOException
   {
-    /*
-     * Does currently nothing. FIXME.
-     */ 
+    Enumeration parentResources;
+    if (parent == null)
+      parentResources = VMClassLoader.getResources(name);
+    else
+      parentResources = parent.getResources(name);
+    return new DoubleEnumeration(parentResources, findResources(name));
   }
 
   /**
-   * If a class named <code>name</code> was previously loaded using
-   * this <code>ClassLoader</code>, then it is returned.  Otherwise
-   * it returns <code>null</code>.
-   * @param     name  class to find.
-   * @return    the class loaded, or null.
-   */ 
-  protected final synchronized Class findLoadedClass(String name)
+   * Called whenever all locations of a named resource are needed.
+   * It is called by <code>getResources()</code> after it has called
+   * <code>parent.getResources()</code>. The results are combined by
+   * the <code>getResources()</code> method.
+   *
+   * <p>The default implementation always returns an empty Enumeration.
+   * Subclasses should override it when they can provide an Enumeration of
+   * URLs (possibly just one element) to the named resource.
+   * The first URL of the Enumeration should be the same as the one
+   * returned by <code>findResource</code>.
+   *
+   * @param name the name of the resource to be found
+   * @return a possibly empty Enumeration of URLs to the named resource
+   * @throws IOException if I/O errors occur in the process
+   * @since 1.2
+   */
+  protected Enumeration findResources(String name) throws IOException
   {
-    return (Class) loadedClasses.get(name);
+    return EmptyEnumeration.getInstance();
   }
 
   /**
-   * Get a resource using the system classloader.
+   * Called whenever a resource is needed that could not be provided by
+   * one of the parents of this classloader. It is called by
+   * <code>getResource()</code> after <code>parent.getResource()</code>
+   * couldn't provide the requested resource.
    *
-   * @param name the name of the resource relative to the system classloader
-   * @return an input stream for the resource, or null
-   * @since 1.1
+   * <p>The default implementation always returns null. Subclasses should
+   * override this method when they can provide a way to return a URL
+   * to a named resource.
+   *
+   * @param name the name of the resource to be found
+   * @return a URL to the named resource or null when not found
+   * @since 1.2
    */
-  public static InputStream getSystemResourceAsStream(String name) {
-    return getSystemClassLoader().getResourceAsStream (name);
+  protected URL findResource(String name)
+  {
+    return null;
   }
 
   /**
@@ -759,8 +625,9 @@
    * @return the URL to the resource
    * @since 1.1
    */
-  public static URL getSystemResource(String name) {
-    return getSystemClassLoader().getResource (name);
+  public static final URL getSystemResource(String name)
+  {
+    return systemClassLoader.getResource(name);
   }
 
   /**
@@ -776,149 +643,221 @@
    */
   public static Enumeration getSystemResources(String name) throws IOException
   {
-    return getSystemClassLoader().getResources(name);
+    return systemClassLoader.getResources(name);
   }
 
   /**
-   *   Return an InputStream representing the resource name.  
-   *   This is essentially like 
-   *   <code>getResource(name).openStream()</code>, except
-   *   it masks out any IOException and returns null on failure.
-   * @param   name  resource to load
-   * @return  an InputStream, or null
-   * @see     java.lang.ClassLoader#getResource(String)
-   * @see     java.io.InputStream
+   * Get a resource as stream using this classloader or one of its parents.
+   * First calls <code>getResource()</code> and if that returns a URL to
+   * the resource then it calls and returns the InputStream given by
+   * <code>URL.openStream()</code>.
+   *
+   * <p>Subclasses should not override this method but should override
+   * <code>findResource()</code> which is called by this method.
+   *
+   * @param name the name of the resource relative to this classloader
+   * @return an InputStream to the resource, or null
+   * @since 1.1
    */
-  public InputStream getResourceAsStream(String name) 
+  public InputStream getResourceAsStream(String name)
   {
     try
       {
-	URL res = getResource (name);
-	if (res == null)
+        URL url = getResource(name);
+        if (url == null)
           return null;
-	return res.openStream ();
+        return url.openStream();
       }
-    catch (java.io.IOException x)
+    catch (IOException e)
       {
-	return null;
+        return null;
       }
   }
- 
+
   /**
-   * Return an java.io.URL representing the resouce <code>name</code>.  
-   * The default implementation just returns <code>null</code>.
-   * @param   name  resource to load
-   * @return  a URL, or null if there is no such resource.
-   * @see     java.lang.ClassLoader#getResourceAsBytes(String)
-   * @see     java.lang.ClassLoader#getResourceAsStream(String)
-   * @see     java.io.URL
+   * Get a resource using the system classloader.
+   *
+   * @param name the name of the resource relative to the system classloader
+   * @return an input stream for the resource, or null
+   * @since 1.1
    */
-  public URL getResource (String name) 
+  public static final InputStream getSystemResourceAsStream(String name)
   {
-    // The rules say search the parent class if non-null,
-    // otherwise search the built-in class loader (assumed to be
-    // the system ClassLoader).  If not found, call
-    // findResource().
-    URL result = null;
-
-    ClassLoader delegate = parent;
+    try
+      {
+        URL url = getSystemResource(name);
+        if (url == null)
+          return null;
+        return url.openStream();
+      }
+    catch (IOException e)
+      {
+        return null;
+      }
+  }
 
-    if (delegate == null)
-      delegate = getSystemClassLoader ();
-	
-    // Protect ourselves from looping.
-    if (this != delegate)
-      result = delegate.getResource (name);
+  /**
+   * Returns the system classloader. The system classloader (also called
+   * the application classloader) is the classloader that was used to
+   * load the application classes on the classpath (given by the system
+   * property <code>java.class.path</code>. This is set as the context
+   * class loader for a thread. The system property
+   * <code>java.system.class.loader</code>, if defined, is taken to be the
+   * name of the class to use as the system class loader, which must have
+   * a public constructor which takes a ClassLoader as a parent; otherwise this
+   * uses gnu.java.lang.SystemClassLoader.
+   *
+   * <p>Note that this is different from the bootstrap classloader that
+   * actually loads all the real "system" classes (the bootstrap classloader
+   * is the parent of the returned system classloader).
+   *
+   * <p>A security check will be performed for
+   * <code>RuntimePermission("getClassLoader")</code> if the calling class
+   * is not a parent of the system class loader.
+   *
+   * @return the system class loader
+   * @throws SecurityException if the security check fails
+   * @throws IllegalStateException if this is called recursively
+   * @throws Error if <code>java.system.class.loader</code> fails to load
+   * @since 1.2
+   */
+  public static ClassLoader getSystemClassLoader()
+  {
+    // Check if we may return the system classloader
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      {
+	Class c = VMSecurityManager.getClassContext()[1];
+	ClassLoader cl = c.getClassLoader();
+	if (cl != null && cl != systemClassLoader)
+	  sm.checkPermission(new RuntimePermission("getClassLoader"));
+      }
 
-    if (result != null)
-      return result;
-    else
-      return findResource (name);
+    return systemClassLoader;
   }
 
   /**
-   * Called whenever a resource is needed that could not be provided by
-   * one of the parents of this classloader. It is called by
-   * <code>getResource()</code> after <code>parent.getResource()</code>
-   * couldn't provide the requested resource.
+   * Defines a new package and creates a Package object. The package should
+   * be defined before any class in the package is defined with
+   * <code>defineClass()</code>. The package should not yet be defined
+   * before in this classloader or in one of its parents (which means that
+   * <code>getPackage()</code> should return <code>null</code>). All
+   * parameters except the <code>name</code> of the package may be
+   * <code>null</code>.
    *
-   * <p>The default implementation always returns null. Subclasses should
-   * override this method when they can provide a way to return a URL
-   * to a named resource.
+   * <p>Subclasses should call this method from their <code>findClass()</code>
+   * implementation before calling <code>defineClass()</code> on a Class
+   * in a not yet defined Package (which can be checked by calling
+   * <code>getPackage()</code>).
    *
-   * @param name the name of the resource to be found
-   * @return a URL to the named resource or null when not found
+   * @param name the name of the Package
+   * @param specTitle the name of the specification
+   * @param specVendor the name of the specification designer
+   * @param specVersion the version of this specification
+   * @param implTitle the name of the implementation
+   * @param implVendor the vendor that wrote this implementation
+   * @param implVersion the version of this implementation
+   * @param sealed if sealed the origin of the package classes
+   * @return the Package object for the specified package
+   * @throws IllegalArgumentException if the package name is null or it
+   *         was already defined by this classloader or one of its parents
+   * @see Package
    * @since 1.2
    */
-  protected URL findResource (String name)
+  protected Package definePackage(String name, String specTitle,
+                                  String specVendor, String specVersion,
+                                  String implTitle, String implVendor,
+                                  String implVersion, URL sealed)
   {
-    // Default to returning null.  Derived classes implement this.
-    return null;
+    if (getPackage(name) != null)
+      throw new IllegalArgumentException("Package " + name
+                                         + " already defined");
+    Package p = new Package(name, specTitle, specVendor, specVersion,
+                            implTitle, implVendor, implVersion, sealed);
+    synchronized (definedPackages)
+      {
+        definedPackages.put(name, p);
+      }
+    return p;
   }
 
   /**
-   * Returns an Enumeration of all resources with a given name that can
-   * be found by this classloader and its parents. Certain classloaders
-   * (such as the URLClassLoader when given multiple jar files) can have
-   * multiple resources with the same name that come from multiple locations.
-   * It can also occur that a parent classloader offers a resource with a
-   * certain name and the child classloader also offers a resource with that
-   * same name. <code>getResource() only offers the first resource (of the
-   * parent) with a given name. This method lists all resources with the
-   * same name. The name should use '/' as path separators.
+   * Returns the Package object for the requested package name. It returns
+   * null when the package is not defined by this classloader or one of its
+   * parents.
    *
-   * <p>The Enumeration is created by first calling <code>getResources()</code>
-   * on the parent classloader and then calling <code>findResources()</code>
-   * on this classloader.
+   * @param name the package name to find
+   * @return the package, if defined
+   * @since 1.2
+   */
+  protected Package getPackage(String name)
+  {
+    Package p;
+    if (parent == null)
+      p = VMClassLoader.getPackage(name);
+    else
+      p = parent.getPackage(name);
+
+    if (p == null)
+      {
+	synchronized (definedPackages)
+	  {
+	    p = (Package) definedPackages.get(name);
+	  }
+      }
+    return p;
+  }
+
+  /**
+   * Returns all Package objects defined by this classloader and its parents.
    *
-   * @param name the resource name
-   * @return an enumaration of all resources found
-   * @throws IOException if I/O errors occur in the process
+   * @return an array of all defined packages
    * @since 1.2
    */
-  public final Enumeration getResources(String name) throws IOException
+  protected Package[] getPackages()
   {
-    // The rules say search the parent class if non-null,
-    // otherwise search the built-in class loader (assumed to be
-    // the system ClassLoader).  If not found, call
-    // findResource().
-    Enumeration result = null;
-
-    ClassLoader delegate = parent;
-
-    if (delegate == null)
-      delegate = getSystemClassLoader ();
-	
-    // Protect ourselves from looping.
-    if (this != delegate)
-      result = delegate.getResources (name);
+    // Get all our packages.
+    Package[] packages;
+    synchronized(definedPackages)
+      {
+        packages = new Package[definedPackages.size()];
+        definedPackages.values().toArray(packages);
+      }
 
-    if (result != null)
-      return result;
+    // If we have a parent get all packages defined by our parents.
+    Package[] parentPackages;
+    if (parent == null)
+      parentPackages = VMClassLoader.getPackages();
     else
-      return findResources (name);
+      parentPackages = parent.getPackages();
+
+    Package[] allPackages = new Package[parentPackages.length
+					+ packages.length];
+    System.arraycopy(parentPackages, 0, allPackages, 0,
+                     parentPackages.length);
+    System.arraycopy(packages, 0, allPackages, parentPackages.length,
+                     packages.length);
+    return allPackages;
   }
 
   /**
-   * Called whenever all locations of a named resource are needed.
-   * It is called by <code>getResources()</code> after it has called
-   * <code>parent.getResources()</code>. The results are combined by
-   * the <code>getResources()</code> method.
-   *
-   * <p>The default implementation always returns an empty Enumeration.
-   * Subclasses should override it when they can provide an Enumeration of
-   * URLs (possibly just one element) to the named resource.
-   * The first URL of the Enumeration should be the same as the one
-   * returned by <code>findResource</code>.
+   * Called by <code>Runtime.loadLibrary()</code> to get an absolute path
+   * to a (system specific) library that was requested by a class loaded
+   * by this classloader. The default implementation returns
+   * <code>null</code>. It should be implemented by subclasses when they
+   * have a way to find the absolute path to a library. If this method
+   * returns null the library is searched for in the default locations
+   * (the directories listed in the <code>java.library.path</code> system
+   * property).
    *
-   * @param name the name of the resource to be found
-   * @return a possibly empty Enumeration of URLs to the named resource
-   * @throws IOException if I/O errors occur in the process
+   * @param name the (system specific) name of the requested library
+   * @return the full pathname to the requested library, or null
+   * @see Runtime#loadLibrary()
    * @since 1.2
    */
-  protected Enumeration findResources(String name) throws IOException
+  protected String findLibrary(String name)
   {
-    return Collections.enumeration(Collections.EMPTY_LIST);
+    return null;
   }
 
   /**
@@ -935,7 +874,7 @@
   {
     defaultAssertionStatus = enabled;
   }
-
+  
   /**
    * Set the default assertion status for packages, used unless overridden
    * by a class request. This default also covers subpackages, unless they
Index: java/lang/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMClassLoader.java,v
retrieving revision 1.7
diff -u -r1.7 VMClassLoader.java
--- java/lang/VMClassLoader.java 30 Sep 2002 05:19:09 -0000 1.7
+++ java/lang/VMClassLoader.java 25 Sep 2003 07:36:49 -0000
@@ -1,66 +1,237 @@
-/*
- * java.lang.ClassLoader: part of the Java Class Libraries project.
- * Copyright (C) 1998, 2001, 2002 Free Software Foundation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
- */
+/* VMClassLoader.java -- Reference implementation of native interface
+   required by ClassLoader
+   Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
 
 package java.lang;
 
-import java.util.*;
+import java.security.ProtectionDomain;
+import java.net.URL;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.reflect.Constructor;
+import java.security.AllPermission;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+
+import gnu.java.util.EmptyEnumeration;
 
 /**
  * java.lang.VMClassLoader is a package-private helper for VMs to implement
  * on behalf of java.lang.ClassLoader.
  *
  * @author John Keiser
- * @version 1.1.0, Sep 22 1998
- * @since CP1.1
+ * @author Mark Wielaard <mark@klomp.org>
+ * @author Eric Blake <ebb9@email.byu.edu>
  */
+final class VMClassLoader
+{
+  // Protection Domain definitions 
+  // FIXME: should there be a special protection domain used for native code?
+  
+  // The permission required to check what a classes protection domain is.
+  static final Permission protectionDomainPermission
+    = new RuntimePermission("getProtectionDomain");
+  // The protection domain returned if we cannot determine it. 
+  static ProtectionDomain unknownProtectionDomain;
+
+  static
+  {
+    Permissions permissions = new Permissions();
+    permissions.add(new AllPermission());
+    unknownProtectionDomain = new ProtectionDomain(null, permissions);  
+  }
+
+  /**
+   * Helper to define a class using a string of bytes. This assumes that
+   * the security checks have already been performed, if necessary.
+   *
+   * <strong>For backward compatibility, this just ignores the protection
+   * domain; that is the wrong behavior, and you should directly implement
+   * this method natively if you can.</strong>
+   *
+   * @param name the name to give the class, or null if unknown
+   * @param data the data representing the classfile, in classfile format
+   * @param offset the offset into the data where the classfile starts
+   * @param len the length of the classfile data in the array
+   * @param pd the protection domain
+   * @return the class that was defined
+   * @throws ClassFormatError if data is not in proper classfile format
+   */
+  static final native Class defineClass(ClassLoader cl, String name,
+					byte[] data, int offset, int len,
+					ProtectionDomain pd)
+    throws ClassFormatError;
 
-class VMClassLoader {
+  static final native void linkClass0 (Class klass);
+  static final native void markClassErrorState0 (Class klass);
 
-    /** 
-     * Helper to define a class using a string of bytes.
-     * 
-     * @param name the name to give the class.  null if unknown.
-     * @param data the data representing the classfile, in classfile format.
-     * @param offset the offset into the data where the classfile starts.
-     * @param len the length of the classfile data in the array.
-     * @return the class that was defined.
-     * @exception ClassFormatError if the byte array is not in proper classfile format.
-     */
-    final static native Class defineClass(ClassLoader cl, String name, 
-					  byte[] data, int offset, int len) 
-	throws ClassFormatError;
-
-    /** 
-     * Helper to resolve all references to other classes from this class.
-     * @param c the class to resolve.
-     */
-  // Not yet needed for libgcj.
-  //    final static native void resolveClass(Class c);
-
-    /** 
-     * Helper for java.lang.Integer, Byte, etc. to get the TYPE class
-     * at initialization time. 
-     *
-     * @param type code for the primitive type.
-     */
-  static native Class getPrimitiveClass(char type);
+  /**
+   * Helper to resolve all references to other classes from this class.
+   *
+   * @param c the class to resolve
+   */
+  static final void resolveClass(Class clazz)
+  {
+    synchronized (clazz)
+      {
+	try
+	  {
+	    linkClass0 (clazz);
+	  }
+	catch (Throwable x)
+	  {
+	    markClassErrorState0 (clazz);
+
+	    LinkageError e;
+	    if (x instanceof LinkageError)
+	      e = (LinkageError) x;
+	    else if (x instanceof ClassNotFoundException)
+	      {
+		e = new NoClassDefFoundError("while resolving class: "
+					     + clazz.getName());
+		e.initCause (x);
+	      }
+	    else
+	      {
+		e = new LinkageError ("unexpected exception during linking: "
+				      + clazz.getName());
+		e.initCause (x);
+	      }
+	    throw e;
+	  }
+      }
+  }
+
+  /**
+   * Helper to load a class from the bootstrap class loader.
+   *
+   * In libgcj, this does nothing, as the default system loader knows
+   * how to find classes that have been linked in.
+   *
+   * @param name the class name to load
+   * @param resolve whether to resolve it
+   * @return the class, loaded by the bootstrap classloader or null
+   * if the class wasn't found. Returning null is equivalent to throwing
+   * a ClassNotFoundException (but a possible performance optimization).
+   */
+  static final Class loadClass(String name, boolean resolve)
+    throws ClassNotFoundException
+  {
+    return null;
+  }
+
+  /**
+   * Helper to load a resource from the bootstrap class loader.
+   *
+   * In libgcj, this does nothing, as the default system loader knows
+   * how to find resources that have been linked in.
+   *
+   * @param name the resource to find
+   * @return the URL to the resource
+   */
+  static URL getResource(String name)
+  {
+    return null;
+  }
+
+  /**
+   * Helper to get a list of resources from the bootstrap class loader.
+   *
+   * In libgcj, this does nothing, as the default system loader knows
+   * how to find resources that have been linked in.
+   *
+   * @param name the resource to find
+   * @return an enumeration of resources
+   * @throws IOException if one occurs
+   */
+  static Enumeration getResources(String name) throws IOException
+  {
+    return EmptyEnumeration.getInstance();
+  }
+
+  /**
+   * Helper to get a package from the bootstrap class loader.  The default
+   * implementation of returning null may be adequate, or you may decide
+   * that this needs some native help.
+   *
+   * @param name the name to find
+   * @return the named package, if it exists
+   */
+  static Package getPackage(String name)
+  {
+    return null;
+  }
+
+  /**
+   * Helper to get all packages from the bootstrap class loader.  The default
+   * implementation of returning an empty array may be adequate, or you may
+   * decide that this needs some native help.
+   *
+   * @return all named packages, if any exist
+   */
+  static Package[] getPackages()
+  {
+    return new Package[0];
+  }
+
+  /**
+   * Helper for java.lang.Integer, Byte, etc to get the TYPE class
+   * at initialization time. The type code is one of the chars that
+   * represents the primitive type as in JNI.
+   *
+   * <ul>
+   * <li>'Z' - boolean</li>
+   * <li>'B' - byte</li>
+   * <li>'C' - char</li>
+   * <li>'D' - double</li>
+   * <li>'F' - float</li>
+   * <li>'I' - int</li>
+   * <li>'J' - long</li>
+   * <li>'S' - short</li>
+   * <li>'V' - void</li>
+   * </ul>
+   *
+   * @param type the primitive type
+   * @return a "bogus" class representing the primitive type
+   */
+  static final native Class getPrimitiveClass(char type);
 
   /**
    * The system default for assertion status. This is used for all system
@@ -103,5 +274,35 @@
   static final Map classAssertionStatus()
   {
     return new HashMap();
+  }
+
+  static native ClassLoader getSystemClassLoaderInternal();
+
+  static ClassLoader getSystemClassLoader()
+  {
+    // This method is called as the initialization of systemClassLoader,
+    // so if there is a null value, this is the first call and we must check
+    // for java.system.class.loader.
+    String loader = System.getProperty("java.system.class.loader");
+    ClassLoader default_sys = getSystemClassLoaderInternal();
+    if (loader != null)
+      {
+	try
+	  {
+	    Class load_class = Class.forName(loader, true, default_sys);
+	    Constructor c
+	      = load_class.getConstructor(new Class[] { ClassLoader.class });
+	    default_sys
+	      = (ClassLoader) c.newInstance(new Object[] { default_sys });
+	  }
+	catch (Exception e)
+	  {
+	    System.err.println("Requested system classloader "
+			       + loader + " failed, using "
+			       + "gnu.gcj.runtime.VMClassLoader");
+	    e.printStackTrace();
+	  }
+      }
+    return default_sys;
   }
 }
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.63
diff -u -r1.63 natClass.cc
--- java/lang/natClass.cc 21 Jul 2003 01:54:05 -0000 1.63
+++ java/lang/natClass.cc 25 Sep 2003 07:36:49 -0000
@@ -48,6 +48,7 @@
 #include <java/lang/System.h>
 #include <java/lang/SecurityManager.h>
 #include <java/lang/StringBuffer.h>
+#include <java/lang/VMClassLoader.h>
 #include <gnu/gcj/runtime/StackTrace.h>
 #include <gcj/method.h>
 #include <gnu/gcj/runtime/MethodRef.h>
@@ -758,7 +759,7 @@
 	{
 	  // this can throw exceptions, so exit the monitor as a precaution.
 	  _Jv_MonitorExit (this);
-	  java::lang::ClassLoader::resolveClass0 (this);
+	  java::lang::VMClassLoader::resolveClass (this);
 	  _Jv_MonitorEnter (this);
 	}
       else
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.58
diff -u -r1.58 natClassLoader.cc
--- java/lang/natClassLoader.cc 30 Jan 2003 23:20:45 -0000 1.58
+++ java/lang/natClassLoader.cc 25 Sep 2003 07:36:49 -0000
@@ -1,6 +1,6 @@
 // natClassLoader.cc - Implementation of java.lang.ClassLoader native methods.
 
-/* Copyright (C) 1999, 2000, 2001, 2002  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -44,11 +44,12 @@
 /////////// java.lang.ClassLoader native methods ////////////
 
 java::lang::Class *
-java::lang::ClassLoader::defineClass0 (jstring name,
-				       jbyteArray data, 
-				       jint offset,
-				       jint length,
-				       java::security::ProtectionDomain *pd)
+java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader,
+					jstring name,
+					jbyteArray data, 
+					jint offset,
+					jint length,
+					java::security::ProtectionDomain *pd)
 {
 #ifdef INTERPRETER
   jclass klass;
@@ -62,8 +63,8 @@
 
   // Record the defining loader.  For the system class loader, we
   // record NULL.
-  if (this != java::lang::ClassLoader::getSystemClassLoader())
-    klass->loader = this;
+  if (loader != java::lang::ClassLoader::getSystemClassLoader())
+    klass->loader = loader;
 
   if (name != 0)
     {
@@ -105,6 +106,36 @@
 #endif
 }
 
+// Finish linking a class.  Only called from ClassLoader::resolveClass.
+void
+java::lang::VMClassLoader::linkClass0 (java::lang::Class *klass)
+{
+  _Jv_WaitForState (klass, JV_STATE_LINKED);
+}
+
+void
+java::lang::VMClassLoader::markClassErrorState0 (java::lang::Class *klass)
+{
+  klass->state = JV_STATE_ERROR;
+  klass->notifyAll ();
+}
+
+java::lang::ClassLoader *
+java::lang::VMClassLoader::getSystemClassLoaderInternal()
+{
+  _Jv_InitClass (&gnu::gcj::runtime::VMClassLoader::class$);
+  return gnu::gcj::runtime::VMClassLoader::instance;
+}
+
+jclass
+java::lang::VMClassLoader::getPrimitiveClass (jchar type)
+{
+  char sig[2];
+  sig[0] = (char) type;
+  sig[1] = '\0';
+  return _Jv_FindClassFromSignature (sig, NULL);
+}
+
 void
 _Jv_WaitForState (jclass klass, int state)
 {
@@ -141,39 +172,6 @@
     throw new java::lang::LinkageError;
 }
 
-// Finish linking a class.  Only called from ClassLoader::resolveClass.
-void
-java::lang::ClassLoader::linkClass0 (java::lang::Class *klass)
-{
-  _Jv_WaitForState (klass, JV_STATE_LINKED);
-}
-
-void
-java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass)
-{
-  klass->state = JV_STATE_ERROR;
-  klass->notifyAll ();
-}
-
-jclass
-java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *cl, 
-					jstring name,
-					jbyteArray data, 
-					jint offset,
-					jint length)
-{
-  return cl->defineClass (name, data, offset, length);
-}
-
-jclass
-java::lang::VMClassLoader::getPrimitiveClass (jchar type)
-{
-  char sig[2];
-  sig[0] = (char) type;
-  sig[1] = '\0';
-  return _Jv_FindClassFromSignature (sig, NULL);
-}
-
 typedef unsigned int uaddr __attribute__ ((mode (pointer)));
 
 /** This function does class-preparation for compiled classes.  
@@ -281,7 +279,7 @@
 //  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
+//  initiating, so we only store classes in this table if they have more
 //  than one class loader associated.
 //
 
Index: java/lang/reflect/Proxy.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Proxy.java,v
retrieving revision 1.4
diff -u -r1.4 Proxy.java
--- java/lang/reflect/Proxy.java 26 Aug 2003 14:37:10 -0000 1.4
+++ java/lang/reflect/Proxy.java 25 Sep 2003 07:36:50 -0000
@@ -1335,17 +1335,10 @@
         {
           // XXX Do we require more native support here?
 
-          // XXX Security hole - it is possible for another thread to grab the
-          // VMClassLoader.defineClass Method object, and abuse it while we
-          // have temporarily made it accessible. Do we need to add some
-          // synchronization lock to prevent user reflection while we use it?
-
-          // XXX This is waiting on VM support for protection domains.
-
           Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
           Class[] types = {ClassLoader.class, String.class,
                            byte[].class, int.class, int.class,
-                           /* ProtectionDomain.class */ };
+                           ProtectionDomain.class };
           Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
 
           // Bypass the security check of setAccessible(true), since this
@@ -1354,7 +1347,7 @@
           m.flag = true;
           Object[] args = {loader, qualName, bytecode, new Integer(0),
                            new Integer(bytecode.length),
-                           /* Object.class.getProtectionDomain() */ };
+                           Object.class.getProtectionDomain() };
           Class clazz = (Class) m.invoke(null, args);
           m.flag = false;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]