From 58eb6e7cef1cea515f8da18d24341a4aa53ccb70 Mon Sep 17 00:00:00 2001 From: Anthony Green Date: Sun, 8 Aug 1999 14:06:23 +0000 Subject: [multiple changes] 1999-08-09 Anthony Green * gij.cc: New file. * include/config.h.in: Rebuilt. * acconfig.h: Add INTERPRETER. * configure: Rebuilt. * Makefile.in: Rebuilt. * Makefile.am (libffi_files): Identify the libffi object files for inclusion in libgcj. (LIBFFIINCS): Define. * interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1): Dummy definition for configurations without an interpreter. * java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to java::lang::Boolean constructor. * include/java-interp.h: Always include java-cpool.h. * java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0 when INTERPRETER not defined. * java/lang/Class.h (finalize): Define. * gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch IOException from File.getCanonicalPath. (getStream): Likewise. * NEWS: More news. * THANKS: More thanks. 1999-08-09 Kresten Krab Thorup * resolve.cc (get_ffi_type_from_signature): Generate uint16 for jchar type. (_Jv_PrepareClass): Allow non-abstract classes to have abstract subclasses. (_Jv_ResolvePoolEntry): Revert subclass check for protected fields and methods. * interpret.cc (continue1/perform_invoke): Don't sign extend uint16 return val. (continue1/lshl,lshr): Push long, not int. (continue1/ulshr): Use UINT64, not long long. * defineclass.cc (handleFieldsEnd): Handle case when all fields are static. * java/lang/natClass.cc (forName): Add call to _Jv_InitClass. * java/lang/FirstThread.java (run): Add top-level exception handler. (run0): Renamed from run. 1999-08-08 Kresten Krab Thorup * configure.in (--with-interpreter): Added. * include/config.h.in (INTERPRETER): Added. * java/lang/ClassLoader.java: File replaced. * java/lang/VMClassLoader.java: New file. * java/lang/natClassLoader.cc: New file. * gnu/gcj/runtime/MethodInvocation.java: New file. * gnu/gcj/util/path/SearchPath.java: New file. * gnu/gcj/util/path/PathEntry.java: New file. * gnu/gcj/util/path/DirectoryPathEntry.java: New file. * gnu/gcj/util/path/ZipPathEntry.java: New file. * gnu/gcj/util/path/URLPathEntry.java: New file. * gnu/gcj/util/path/CacheEntry.java: New file. * include/java-interp.h: New file. * include/java-cpool.h: New file. * include/java-insns.h: New file. * defineclass.cc: New file. * interpret.cc: New file. * resolve.cc: New file. * java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass, _Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass, _Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc. (finalize): New. (STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE, STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_ prefix. (initializeClass): Use new JV_ prefixed names. Also, call ClassLoader::resolveClass instead of _Jv_ResolveClass. * java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING, JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED, JV_STATE_LINKED): New. (_Jv_WaitForState, _Jv_RegisterInitiatingLoader, _Jv_UnregisterClass, _Jv_InternClassStrings): New friends. (_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod, _Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass, _Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod, _Jv_InterpMethodInvocation): New friends for interpreter. (finalize): New. (CONSTANT_Class, CONSTANT_String, etc.): Moved to include/java-cpool.h and renamed with JV_ prefix. * include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New decls. (_Jv_UnregisterClass): New decl. * java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added class loader argument. (_Jv_FindClass): Use class loader. * prims.cc (_Jv_makeUtf8Const): New function. (_Jv_NewObjectArray): Change use of _Jv_FindArrayClass. (_Jv_NewPrimArray): Ditto. (_Jv_FindClassFromSignature): Ditto. * java/lang/reflect/natArray.cc (newInstance): Ditto. * java/lang/reflect/natMethod.cc (getType): Ditto. * include/java-field.h (_Jv_Field::isRef): Make robust for non-resolved contexts. * boehm.cc (_Jv_MarkObj): Mark interpreter-related fields. Also, don't mark class->next field. * java/lang/VirtualMachineError.java: Added FIXME note. * configure.in (INTERPSPEC): New spec. * libgcj.spec.in: Added INTERPSPEC. * Makefile.am: Added gcjh friends for java/lang/VMClassLoader and gnu/gcj/runtime/MethodInvocation. (libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc. (ordinary_java_source_files): Added above mentioned java classes. * configure: Rebuilt. * Makefile.in: Rebuilt. From-SVN: r28597 --- libjava/java/lang/ClassLoader.java | 426 ++++++++++++++++++++++++++++++++----- 1 file changed, 367 insertions(+), 59 deletions(-) (limited to 'libjava/java/lang/ClassLoader.java') diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 048cea7..f0b533f 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -9,86 +9,394 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.lang; + import java.io.InputStream; -import java.util.Hashtable; +import java.net.URL; +import java.net.URLConnection; +import java.util.Stack; /** - * @author Tom Tromey - * @date October 28, 1998 + * The class ClassLoader is intended to be subclassed by + * applications in order to describe new ways of loading classes, + * such as over the network. + * + * @author Kresten Krab Thorup */ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * Status: Just a stub; not useful at all. */ -public abstract class ClassLoader -{ - protected ClassLoader () - { - cache = new Hashtable (); - } +public abstract class ClassLoader { - protected final Class defineClass (String className, byte[] bytecode, - int offset, int length) - { - throw new ClassFormatError ("defineClass unimplemented"); - } + static private ClassLoader system; + + private static native ClassLoader getVMClassLoader0 (); - protected final Class defineClass (byte[] bytecodes, - int offset, int length) - { - return defineClass (null, bytecodes, offset, length); - } + static public ClassLoader getSystemClassLoader () { + if (system == null) + system = getVMClassLoader0 (); + return system; + } - protected final Class findLoadedClass (String className) - { - return (Class) cache.get(className); - } + /** + * Creates a ClassLoader. The only thing this + * constructor does, is to call + * checkCreateClassLoader on the current + * security manager. + * @exception java.lang.SecurityException if not allowed + */ + protected ClassLoader() + { + SecurityManager security = System.getSecurityManager (); + if (security != null) + security.checkCreateClassLoader (); + } - protected final Class findSystemClass (String className) - throws ClassNotFoundException - { - Class c = system.findLoadedClass(className); - system.resolveClass(c); - return c; - } + /** + * 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, java.lang.LinkageError + { + return loadClass (name, true); + } - // FIXME: Needs URL. - // public URL getResource (String resName); + /** + * Loads the class by the given name. + * As per java 1.1, this has been deprecated. Use + * loadClass(String) + * instead. + * @param name the name of the class. + * @param link if the class should be linked. + * @return the class loaded. + * @exception java.lang.ClassNotFoundException + * @deprecated + */ + protected abstract Class loadClass(String name, boolean link) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; - public InputStream getResourceAsStream (String resName) - { - return null; - } + /** + * 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. + *

+ * 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 + * java.lang.ClassNotFoundException 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) */ + protected final Class defineClass(byte[] data, int off, int len) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + return defineClass (null, data, off, len); + } - // FIXME: Needs URL. - // public static final URL getSystemResource (String resName); + /** + * Defines a class, given the class-data. This is preferable + * over defineClass(byte[],off,len) since it is more + * secure. If the expected name does not match that of the class + * file, ClassNotFoundException is thrown. If + * name denotes the name of an already loaded class, a + * LinkageError is thrown. + *

+ * + * 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. + * @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) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + if (data==null || data.length < off+len || off<0 || len<0) + throw new ClassFormatError ("arguments to defineClass " + + "are meaningless"); - public static final InputStream getSystemResourceAsStream (String resName) - { - return null; - } + // as per 5.3.5.1 + if (name != null && findLoadedClass (name) != null) + throw new java.lang.LinkageError ("class " + + name + + " already loaded"); - protected abstract Class loadClass (String className, boolean resolve) - throws ClassNotFoundException; - public Class loadClass (String name) throws ClassNotFoundException - { - return loadClass (name, true); - } + try { + // Since we're calling into native code here, + // we better make sure that any generated + // exception is to spec! + + return defineClass0 (name, data, off, len); + + } catch (java.lang.LinkageError x) { + throw x; // rethrow + + } catch (java.lang.ClassNotFoundException x) { + throw x; // rethrow + + } catch (java.lang.VirtualMachineError x) { + throw x; // rethrow + + } catch (java.lang.Throwable x) { + // This should never happen, or we are beyond spec. + + throw new InternalError ("Unexpected exception " + + "while defining class " + + name + ": " + + x.toString ()); + } + } + + /** This is the entry point of defineClass into the native code */ + private native Class defineClass0 (String name, + byte[] data, + int off, + int len) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; - protected final void resolveClass (Class c) - { - // Nothing for now. - } - protected final void setSigners (Class cl, Object[] signers) - { - // Nothing for now. + /** This is called by defineClass0, once the "raw" and uninitialized + * class object has been created, and handles exceptions generated + * while actually defining the class (_Jv_DefineClass). defineClass0 + * holds the lock on the new class object, so it needs to capture + * these exceptions. */ + + private static Throwable defineClass1 (Class klass, byte[] data, + int offset, int length) + { + try { + defineClass2 (klass, data, offset, length); + } catch (Throwable x) { + return x; } + return null; + } + + /** This is just a wrapper for _Jv_DefineClass */ + private static native void defineClass2 (Class klass, byte[] data, + int offset, int length) + throws Throwable; + + /** + * Link the given class. This will bring the class to a state where + * the class initializer can be run. Linking involves the following + * steps: + *

    + *
  • Prepare (allocate and internalize) the constant strings that + * are used in this class. + *
  • Allocate storage for static fields, and define the layout + * of instance fields. + *
  • Perform static initialization of ``static final'' int, + * long, float, double and String fields for which there is a + * compile-time constant initializer. + *
  • Create the internal representation of the ``vtable''. + *
+ * For gcj-compiled classes, only the first step is + * performed. The compiler will have done the rest already. + *

+ * This is called by the system automatically, + * as part of class initialization; there is no reason to ever call + * this method directly. + *

+ * 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. + *

+ * FIXME: The JDK documentation declares this method + * final, we declare it static -- any + * objections? This allows us to call it directly from native code + * with less hassle. + * + * @param clazz the class to link. + * @exception java.lang.LinkageError + */ + protected static void resolveClass(Class clazz) + throws java.lang.LinkageError + { + synchronized (clazz) + { + try { + linkClass0 (clazz); + } catch (Throwable x) { + markClassErrorState0 (clazz); + + if (x instanceof Error) + throw (Error)x; + else + throw new java.lang.InternalError + ("unexpected exception during linking: " + x); + } + } + } + + /** Internal method. Calls _Jv_PrepareClass and + * _Jv_InternClassStrings. This is only called from resolveClass. */ + private static native void linkClass0(Class clazz) + throws java.lang.LinkageError; + + /** 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); + + + /** + * Returns a class found in a system-specific way, typically + * via the java.class.path system property. + * + * @param name the class to resolve. + * @return the class loaded. + * @exception java.lang.LinkageError + * @exception java.lang.ClassNotFoundException + */ + protected native static Class findSystemClass(String name) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; + + /* + * Does currently nothing. + */ + protected final void setSigners(Class claz, Object[] signers) { + /* claz.setSigners (signers); */ + } + + /* + * If a class named name was previously loaded using + * this ClassLoader, then it is returned. Otherwise + * it returns null. + * @param name class to find. + * @return the class loaded, or null. + */ + protected native Class findLoadedClass(String name); - // Class cache. - private Hashtable cache; + public static final InputStream getSystemResourceAsStream(String name) { + return system.getResourceAsStream (name); + } - // The system class loader. FIXME: should have an actual value - private static final ClassLoader system = null; + public static final URL getSystemResource(String name) { + return system.getResource (name); + } + + public static final byte[] getSystemResourceAsBytes(String name) { + return system.getResourceAsBytes (name); + } + + /** + * Return an InputStream representing the resource name. + * This is essentially like + * getResource(name).openStream(), 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.lang.ClassLoader#getResourceAsBytes(String) + * @see java.io.InputStream + */ + public InputStream getResourceAsStream(String name) + { + try { + URL res = getResource (name); + if (res == null) return null; + return res.openStream (); + } catch (java.io.IOException x) { + return null; + } + } + + /** + * Return a byte array byte[] representing the + * resouce name. This only works for resources + * that have a known content-length, and + * it will block while loading the resource. Returns null + * for error conditions.

+ * Since it is synchroneous, this is only convenient for + * resources that are "readily" available. System resources + * can conveniently be loaded this way, and the runtime + * system uses this to load class files.

+ * To find the class data for a given class, use + * something like the following: + *

    + * String res = clazz.getName().replace ('.', '/')) + ".class";
    + * byte[] data = getResourceAsBytes (res); + *
+ * @param name resource to load + * @return a byte array, or null + * @see java.lang.ClassLoader#getResource(String) + * @see java.lang.ClassLoader#getResourceAsStream(String) + */ + public byte[] getResourceAsBytes(String name) { + try { + URL res = getResource (name); + if (res == null) return null; + URLConnection conn = res.openConnection (); + int len = conn.getContentLength (); + if (len == -1) return null; + return readbytes (conn.getInputStream (), len); + } catch (java.io.IOException x) { + return null; + } + } + + /** + * Return an java.io.URL representing the resouce name. + * @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 + */ + public URL getResource(String name) { + return null; + } + + /** + * Utility routine to read a resource fully, even if the given + * InputStream only provides partial results. + */ + private static byte[] readbytes (InputStream is, int length) + { + try { + + byte[] data = new byte[length]; + int read; + int off = 0; + + while (off != length) + { + read = is.read (data, off, (int) (length-off)); + + if (read == -1) + return null; + + off += read; + } + + return data; + } catch (java.io.IOException x) { + return null; + } + } } -- cgit v1.1