diff options
Diffstat (limited to 'libjava/java')
-rw-r--r-- | libjava/java/lang/Class.h | 82 | ||||
-rw-r--r-- | libjava/java/lang/Class.java | 3 | ||||
-rw-r--r-- | libjava/java/lang/ClassLoader.java | 426 | ||||
-rw-r--r-- | libjava/java/lang/FirstThread.java | 21 | ||||
-rw-r--r-- | libjava/java/lang/VMClassLoader.java | 117 | ||||
-rw-r--r-- | libjava/java/lang/VirtualMachineError.java | 5 | ||||
-rw-r--r-- | libjava/java/lang/natClass.cc | 386 | ||||
-rw-r--r-- | libjava/java/lang/natClassLoader.cc | 624 | ||||
-rw-r--r-- | libjava/java/lang/natFirstThread.cc | 8 | ||||
-rw-r--r-- | libjava/java/lang/reflect/natArray.cc | 7 | ||||
-rw-r--r-- | libjava/java/lang/reflect/natMethod.cc | 4 | ||||
-rw-r--r-- | libjava/java/net/natPlainSocketImpl.cc | 2 |
12 files changed, 1319 insertions, 366 deletions
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index eb0a2f95533..df55425daee 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -21,25 +21,30 @@ details. */ extern "C" void _Jv_InitClass (jclass klass); extern "C" void _Jv_RegisterClasses (jclass *classes); +// These are the possible values for the `state' field of the class +// structure. Note that ordering is important here; in particular +// `resolved' must come between `nothing' and the other states. +// Whenever the state changes, one should notify all waiters of this +// class. +#define JV_STATE_NOTING 0 // set by compiler + +#define JV_STATE_PRELOADING 1 // can do _Jv_FindClass +#define JV_STATE_LOADING 3 // has super installed +#define JV_STATE_LOADED 5 // is complete + +#define JV_STATE_COMPILED 6 // this was a compiled class + +#define JV_STATE_PREPARED 7 // layout & static init done +#define JV_STATE_LINKED 9 // strings interned + +#define JV_STATE_IN_PROGRESS 10 // <clinit> running +#define JV_STATE_DONE 12 // + +#define JV_STATE_ERROR 14 // must be last + struct _Jv_Field; struct _Jv_VTable; -#define CONSTANT_Class 7 -#define CONSTANT_Fieldref 9 -#define CONSTANT_Methodref 10 -#define CONSTANT_InterfaceMethodref 11 -#define CONSTANT_String 8 -#define CONSTANT_Integer 3 -#define CONSTANT_Float 4 -#define CONSTANT_Long 5 -#define CONSTANT_Double 6 -#define CONSTANT_NameAndType 12 -#define CONSTANT_Utf8 1 -#define CONSTANT_Unicode 2 -#define CONSTANT_ResolvedFlag 16 -#define CONSTANT_ResolvedString (CONSTANT_String+CONSTANT_ResolvedFlag) -#define CONSTANT_ResolvedClass (CONSTANT_Class+CONSTANT_ResolvedFlag) - struct _Jv_Constants { jint size; @@ -134,9 +139,11 @@ public: return size_in_bytes; } + // finalization + void finalize (); + private: void checkMemberAccess (jint flags); - void resolveConstants (void); // Various functions to handle class initialization. java::lang::Throwable *hackTrampoline (jint, java::lang::Throwable *); @@ -147,12 +154,6 @@ private: friend _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); friend void _Jv_InitClass (jclass klass); - friend void _Jv_RegisterClasses (jclass *classes); - friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name, - java::lang::ClassLoader *loader); - friend jclass _Jv_FindArrayClass (jclass element); - friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, - java::lang::ClassLoader *loader); friend jfieldID JvGetFirstInstanceField (jclass); friend jint JvNumInstanceFields (jclass); @@ -165,6 +166,41 @@ private: friend class _Jv_PrimClass; + // Friends classes and functions to implement the ClassLoader + friend class java::lang::ClassLoader; + + friend void _Jv_WaitForState (jclass, int); + friend void _Jv_RegisterClasses (jclass *classes); + friend void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void _Jv_UnregisterClass (jclass); + friend jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass _Jv_FindArrayClass (jclass element, + java::lang::ClassLoader *loader); + friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); + + friend void _Jv_InternClassStrings (jclass); + +#ifdef INTERPRETER + friend jboolean _Jv_IsInterpretedClass (jclass); + friend void _Jv_InitField (jobject, jclass, _Jv_Field*); + friend _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*); + friend int _Jv_DetermineVTableIndex (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*); + friend void _Jv_InitField (jobject, jclass, int); + friend void* _Jv_ResolvePoolEntry (jclass, int); + friend void _Jv_PrepareClass (jclass); + + friend class _Jv_ClassReader; + friend class _Jv_InterpClass; + friend class _Jv_InterpMethod; + friend class _Jv_InterpMethodInvocation; +#endif + #ifdef JV_MARKOBJ_DECL friend JV_MARKOBJ_DECL; #endif diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 4ffcceaf675..bc826e9029b 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -152,4 +152,7 @@ public final class Class implements Serializable // Initialize the class. private native void initializeClass (); + + // finalization + protected native void finalize (); } diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 048cea7d883..f0b533f6041 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 <tromey@cygnus.com> - * @date October 28, 1998 + * The class <code>ClassLoader</code> 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 <code>ClassLoader</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 + */ + 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 + * <code>loadClass(String)</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 + * @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. + * <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) */ + 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 <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. + * @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: + * <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. + * <P> + * FIXME: The JDK documentation declares this method + * <code>final</code>, we declare it <code>static</code> -- 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 <code>java.class.path</code> 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 <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 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 + * <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.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 <code>byte[]</code> representing the + * resouce <code>name</code>. This only works for resources + * that have a known <code>content-length</code>, and + * it will block while loading the resource. Returns null + * for error conditions.<p> + * 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. <p> + * To find the class data for a given class, use + * something like the following: + * <ul><code> + * String res = clazz.getName().replace ('.', '/')) + ".class";<br> + * byte[] data = getResourceAsBytes (res); + * </code></ul> + * @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 <code>name</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 + */ + 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; + } + } } diff --git a/libjava/java/lang/FirstThread.java b/libjava/java/lang/FirstThread.java index ec0f1db33d5..0dd5c9c67ad 100644 --- a/libjava/java/lang/FirstThread.java +++ b/libjava/java/lang/FirstThread.java @@ -19,12 +19,30 @@ package java.lang; final class FirstThread extends Thread { - public native void run (); + public native void run0 (); + public void run () + { + try { + run0 (); + } catch (Throwable ex) { + System.err.println ("uncaught exception at top level"); + ex.printStackTrace (); + } + } public FirstThread (ThreadGroup g, Class k, Object o) { super (g, null, "main"); klass = k; + klass_name = null; + args = o; + } + + public FirstThread (ThreadGroup g, String class_name, Object o) + { + super (g, null, "main"); + klass = null; + klass_name = class_name; args = o; } @@ -36,5 +54,6 @@ final class FirstThread extends Thread // Private data. private Class klass; + private String klass_name; private Object args; } diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java new file mode 100644 index 00000000000..026f6d8d1fb --- /dev/null +++ b/libjava/java/lang/VMClassLoader.java @@ -0,0 +1,117 @@ +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package java.lang; + +import java.io.*; +import java.net.URL; +import gnu.gcj.util.path.SearchPath; + +final class VMClassLoader extends java.lang.ClassLoader +{ + private SearchPath path; + private final String path_seperator; + private final String file_seperator; + private final char file_seperator_char; + + private VMClassLoader () { + path_seperator = System.getProperty ("path.separator", ":"); + file_seperator = System.getProperty ("file.separator", "/"); + + file_seperator_char = file_seperator.charAt (0); + + String class_path = System.getProperty ("java.class.path", "."); + path = new SearchPath (class_path); + } + + protected Class loadClass(String name, + boolean resolve) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + return loadClassInternal (name, resolve, false); + } + + /** I'm a little in doubt here, if this method is + actually supposed to throw a LinkageError, or not. + The spec, 20.14.3, is a little unclear. It says: + + `` The general contract of loadClass is that, given the name + of a class, it either returns the Class object for the class + or throws a ClassNotFoundException.'' + + However, by making LinkageError a checked exception, + i.e., mention it directly in the throws clause, + we'll force caller to consider that case as well. + **/ + + protected Class loadClassInternal(String name, + boolean resolve, + boolean fromBootLoader) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + Class clazz; + + /** TODO: call _Jv_VerifyClassName **/ + if ( (name.indexOf ('/') != -1) + || (name.charAt (0) == '.') + || (name.indexOf (file_seperator) != -1) + || (name.indexOf ("..") != -1)) + { + throw new IllegalArgumentException (name); + } + + // already loaded? + clazz = findLoadedClass (name); + + // we need access to the boot class loader here + if (clazz == null && !fromBootLoader) + clazz = findBootClass (name); + + if (clazz == null) + { + StringBuffer res = new StringBuffer (); + + // here we do actually replace .'s with /'s because + // we're going to find something in the file system. + res.append (name.replace ('.', file_seperator_char)); + res.append (".class"); + + byte[] data = getResourceAsBytes (res.toString ()); + + if (data == null) + throw new ClassNotFoundException (name); + + clazz = defineClass (name, data, 0, data.length); + + } + + if (resolve && clazz != null) + resolveClass (clazz); + + return clazz; + } + + private native Class findBootClass (String name); + + public InputStream getResourceAsStream(String name) + { + return path.getStream (name); + } + + public URL getResource(String name) + { + return path.getURL (name); + } + + public byte[] getResourceAsBytes(String name) + { + return path.getBytes (name); + } +} diff --git a/libjava/java/lang/VirtualMachineError.java b/libjava/java/lang/VirtualMachineError.java index dcc907c5d03..ee6d8e829bd 100644 --- a/libjava/java/lang/VirtualMachineError.java +++ b/libjava/java/lang/VirtualMachineError.java @@ -20,6 +20,11 @@ package java.lang; * Status: Believed complete and correct. */ +/* FIXME: We should consider adding some special error message when this + * exception is thrown, or maybe if it being caught at top-level. Such + * a message would direct the user to send a bug report to + * gcj-bugs@cygnus.com, or something like that. --KKT */ + public abstract class VirtualMachineError extends Error { public VirtualMachineError () diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 1768df5ecb2..367f14abb0f 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -39,6 +39,8 @@ details. */ #include <java/lang/System.h> #include <java/lang/SecurityManager.h> +#include <java-cpool.h> + #define CloneableClass _CL_Q34java4lang9Cloneable @@ -59,28 +61,6 @@ static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3); static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8); static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); -// These are the possible values for the `state' field. They more or -// less follow the section numbers in the Java Language Spec. Right -// now we don't bother to represent other interesting states, e.g. the -// states a class might inhabit before it is prepared. Note that -// ordering is important here; in particular `resolved' must come -// between `nothing' and the other states. -#define STATE_NOTHING 0 -#define STATE_RESOLVED 1 -#define STATE_IN_PROGRESS 6 -#define STATE_DONE 9 -#define STATE_ERROR 10 - -// Size of local hash table. -#define HASH_LEN 256 - -// Hash function for Utf8Consts. -#define HASH_UTF(Utf) (((Utf)->hash) % HASH_LEN) - -// This is the table we use to keep track of loaded classes. See Spec -// section 12.2. -static jclass loaded_classes[HASH_LEN]; - jclass @@ -111,6 +91,9 @@ java::lang::Class::forName (jstring className) #endif if (! klass) JvThrow (new java::lang::ClassNotFoundException (className)); + + _Jv_InitClass (klass); + return klass; } @@ -380,33 +363,13 @@ java::lang::Class::newInstance (void) return r; } -// Initialize the constants. void -java::lang::Class::resolveConstants (void) +java::lang::Class::finalize (void) { - for (int i = 0; i < constants.size; ++i) - { - if (constants.tags[i] == CONSTANT_String) - { - jstring str; - str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) constants.data[i]); - constants.data[i] = (void *) str; - constants.tags[i] = CONSTANT_ResolvedString; - } - else if (constants.tags[i] == CONSTANT_Class) - { - _Jv_Utf8Const *name = (_Jv_Utf8Const *) constants.data[i]; - jclass klass = _Jv_FindClassFromSignature (name->data, loader); - if (! klass) - { - jstring str = _Jv_NewStringUtf8Const (name); - JvThrow (new java::lang::ClassNotFoundException (str)); - } - - constants.data[i] = (void *) klass; - constants.tags[i] = CONSTANT_ResolvedClass; - } - } +#ifdef INTERPRETER + JvAssert (_Jv_IsInterpretedClass (this)); + _Jv_UnregisterClass (this); +#endif } // FIXME. @@ -424,38 +387,52 @@ void java::lang::Class::initializeClass (void) { // Short-circuit to avoid needless locking. - if (state == STATE_DONE) + if (state == JV_STATE_DONE) return; - // Step 1. - _Jv_MonitorEnter (this); + // do this before we enter the monitor below, since this can cause + // exceptions. Here we assume, that reading "state" is an atomic + // operation, I pressume that is true? --Kresten + if (state < JV_STATE_LINKED) + { +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (this)) + { + java::lang::ClassLoader::resolveClass (this); - // FIXME: This should actually be handled by calling into the class - // loader. For now we put it here. - if (state < STATE_RESOLVED) + // Step 1. + _Jv_MonitorEnter (this); + } + else +#endif + { + // Step 1. + _Jv_MonitorEnter (this); + _Jv_InternClassStrings (this); + } + } + else { - // We set the state before calling resolveConstants to avoid - // infinite recursion when processing String or Class. - state = STATE_RESOLVED; - resolveConstants (); + // Step 1. + _Jv_MonitorEnter (this); } // Step 2. java::lang::Thread *self = java::lang::Thread::currentThread(); // FIXME: `self' can be null at startup. Hence this nasty trick. self = (java::lang::Thread *) ((long) self | 1); - while (state == STATE_IN_PROGRESS && thread && thread != self) + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) wait (); // Steps 3 & 4. - if (state == STATE_DONE || state == STATE_IN_PROGRESS || thread == self) + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self) { _Jv_MonitorExit (this); return; } // Step 5. - if (state == STATE_ERROR) + if (state == JV_STATE_ERROR) { _Jv_MonitorExit (this); JvThrow (new java::lang::NoClassDefFoundError); @@ -463,7 +440,7 @@ java::lang::Class::initializeClass (void) // Step 6. thread = self; - state = STATE_IN_PROGRESS; + state = JV_STATE_IN_PROGRESS; _Jv_MonitorExit (this); // Step 7. @@ -477,7 +454,7 @@ java::lang::Class::initializeClass (void) { // Caught an exception. _Jv_MonitorEnter (this); - state = STATE_ERROR; + state = JV_STATE_ERROR; notify (); _Jv_MonitorExit (this); JvThrow (except); @@ -492,7 +469,7 @@ java::lang::Class::initializeClass (void) if (! except) { _Jv_MonitorEnter (this); - state = STATE_DONE; + state = JV_STATE_DONE; } else { @@ -503,7 +480,7 @@ java::lang::Class::initializeClass (void) except = hackTrampoline(2, except); } _Jv_MonitorEnter (this); - state = STATE_ERROR; + state = JV_STATE_ERROR; } notify (); _Jv_MonitorExit (this); @@ -530,6 +507,64 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, return NULL; } +#define MCACHE_SIZE 1013 + +struct _Jv_mcache { + jclass klass; + _Jv_Method *method; +}; + +static _Jv_mcache method_cache[MCACHE_SIZE]; +static int method_cache_count; + +static void* +_Jv_FindMethodInCache (jclass klass, + _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (int index = name->hash % MCACHE_SIZE; + method_cache[index].klass != NULL; + index = (index+1) % MCACHE_SIZE) + { + _Jv_mcache *mc = (method_cache+index); + _Jv_Method *m = mc->method; + + if (mc->klass == klass + && m != NULL // thread safe check + && _Jv_equalUtf8Consts (m->name, name) + && _Jv_equalUtf8Consts (m->signature, signature)) + { + return mc->method->ncode; + } + } + return NULL; +} + +static void +_Jv_AddMethodToCache (jclass klass, + _Jv_Method *method) +{ + _Jv_MonitorEnter (&ClassClass); + + if (method_cache_count > MCACHE_SIZE*2/3) + { + for (int i = 0; i < MCACHE_SIZE; i++) + method_cache[i].klass = 0; + } + + for (int index = method->name->hash % MCACHE_SIZE; + method_cache[index].klass != NULL; + index = (index+1) % MCACHE_SIZE) + { + method_cache[index].method = method; + method_cache[index].klass = klass; + } + + method_cache_count += 1; + + _Jv_MonitorExit (&ClassClass); +} + void * _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) @@ -539,6 +574,14 @@ _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, // call a method of a class until the class is linked. But this // captures the general idea. // klass->getClassLoader()->resolveClass(klass); + // + // KKT: This is unnessecary, exactly for the reason you present: + // _Jv_LookupInterfaceMethod is only called on object instances, and + // such have already been initialized (which includes resolving). + + void *ncode = _Jv_FindMethodInCache (klass, name, signature); + if (ncode != 0) + return ncode; for (; klass; klass = klass->getSuperclass()) { @@ -553,6 +596,8 @@ _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, if (! java::lang::reflect::Modifier::isPublic(meth->accflags)) JvThrow (new java::lang::IllegalAccessError); + _Jv_AddMethodToCache (klass, meth); + return meth->ncode; } JvThrow (new java::lang::IncompatibleClassChangeError); @@ -565,219 +610,6 @@ _Jv_InitClass (jclass klass) klass->initializeClass(); } -// This function is called many times during startup, before main() is -// run. We do our runtime initialization here the very first time we -// are called. At that point in time we know for certain we are -// running single-threaded, so we don't need to lock when modifying -// `init'. CLASSES is NULL-terminated. -void -_Jv_RegisterClasses (jclass *classes) -{ - static bool init = false; - - if (! init) - { - init = true; - _Jv_InitThreads (); - _Jv_InitGC (); - _Jv_InitializeSyncMutex (); - } - - JvSynchronize sync (&ClassClass); - for (; *classes; ++classes) - { - jclass klass = *classes; - jint hash = HASH_UTF (klass->name); - klass->next = loaded_classes[hash]; - loaded_classes[hash] = klass; - } -} - -void -_Jv_RegisterClass (jclass klass) -{ - jclass classes[2]; - classes[0] = klass; - classes[1] = NULL; - _Jv_RegisterClasses (classes); -} - -jclass -_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) -{ - JvSynchronize sync (&ClassClass); - jint hash = HASH_UTF (name); - jclass klass; - for (klass = loaded_classes[hash]; klass; klass = klass->next) - { - if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) - break; - } - return klass; -} - -#if 0 -jclass -_Jv_FindClassInCache (jstring name, java::lang::ClassLoader *loader) -{ - JvSynchronize sync (&ClassClass); - jint hash = name->hashCode(); - jclass klass = loaded_classes[(_Jv_ushort) hash % HASH_LEN]; - for ( ; klass; klass = klass->next) - { - if (loader == klass->loader - && _Jv_equalUtf8Consts (klass->name, name, hash)) - break; - } - return klass; -} -#endif - -jclass -_Jv_FindClass (_Jv_Utf8Const* name, java::lang::ClassLoader *loader) -{ - jclass klass = _Jv_FindClassInCache (name, loader); - if (loader && ! klass) - { - klass = loader->loadClass(_Jv_NewStringUtf8Const (name)); - if (klass) - _Jv_RegisterClass (klass); - } - return klass; -} - -#if 0 -jclass -_Jv_FindClass (jstring name, java::lang::ClassLoader *loader) -{ - jclass klass = _Jv_FindClassInCache (name, loader); - if (loader && ! klass) - { - klass = loader->loadClass(name); - if (klass) - _Jv_RegisterClass (klass); - } - return klass; -} -#endif - -jclass -_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, - java::lang::ClassLoader *loader) -{ - jclass ret = (jclass) JvAllocObject (&ClassClass); - - ret->next = NULL; - ret->name = name; - ret->accflags = 0; - ret->superclass = superclass; - ret->constants.size = 0; - ret->constants.tags = NULL; - ret->constants.data = NULL; - ret->methods = NULL; - ret->method_count = 0; - ret->vtable_method_count = 0; - ret->fields = NULL; - ret->size_in_bytes = 0; - ret->field_count = 0; - ret->static_field_count = 0; - ret->vtable = NULL; - ret->interfaces = NULL; - ret->loader = loader; - ret->interface_count = 0; - ret->state = 0; - ret->thread = NULL; - - _Jv_RegisterClass (ret); - - return ret; -} - -jclass -_Jv_FindArrayClass (jclass element) -{ - _Jv_Utf8Const *array_name; - int len; - if (element->isPrimitive()) - { - // For primitive types the array is cached in the class. - jclass ret = (jclass) element->methods; - if (ret) - return ret; - len = 3; - } - else - len = element->name->length + 5; - - { - char signature[len]; - int index = 0; - signature[index++] = '['; - // Compute name of array class to see if we've already cached it. - if (element->isPrimitive()) - { - signature[index++] = (char) element->method_count; - } - else - { - size_t length = element->name->length; - const char *const name = element->name->data; - if (name[0] != '[') - signature[index++] = 'L'; - memcpy (&signature[index], name, length); - index += length; - if (name[0] != '[') - signature[index++] = ';'; - } - array_name = _Jv_makeUtf8Const (signature, index); - } - - jclass array_class = _Jv_FindClassInCache (array_name, element->loader); - - if (! array_class) - { - // Create new array class. - array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader); - - // Note that `vtable_method_count' doesn't include the initial - // NULL slot. - int dm_count = ObjectClass.vtable_method_count + 1; - - // Create a new vtable by copying Object's vtable (except the - // class pointer, of course). Note that we allocate this as - // unscanned memory -- the vtables are handled specially by the - // GC. - int size = (sizeof (_Jv_VTable) + - ((dm_count - 1) * sizeof (void *))); - _Jv_VTable *vtable = (_Jv_VTable *) _Jv_AllocBytes (size); - vtable->clas = array_class; - memcpy (vtable->method, ObjectClass.vtable->method, - dm_count * sizeof (void *)); - array_class->vtable = vtable; - array_class->vtable_method_count = ObjectClass.vtable_method_count; - - // Stash the pointer to the element type. - array_class->methods = (_Jv_Method *) element; - - // Register our interfaces. - // FIXME: for JDK 1.2 we need Serializable. - static jclass interfaces[] = { &CloneableClass }; - array_class->interfaces = interfaces; - array_class->interface_count = 1; - - // FIXME: initialize other Class instance variables, - // e.g. `fields'. - - array_class->state = STATE_DONE; - } - - // For primitive types, point back at this array. - if (element->isPrimitive()) - element->methods = (_Jv_Method *) array_class; - - return array_class; -} - jboolean _Jv_IsInstanceOf(jobject obj, jclass cl) { diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc new file mode 100644 index 00000000000..13452eccd99 --- /dev/null +++ b/libjava/java/lang/natClassLoader.cc @@ -0,0 +1,624 @@ +// natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <cni.h> +#include <jvm.h> +#include <java/lang/Character.h> +#include <java/lang/Thread.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/InternalError.h> +#include <java/lang/LinkageError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ClassCircularityError.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/reflect/Modifier.h> + +#include <java-interp.h> + +#define CloneableClass _CL_Q34java4lang9Cloneable +extern java::lang::Class CloneableClass; +#define ObjectClass _CL_Q34java4lang6Object +extern java::lang::Class ObjectClass; +#define ClassClass _CL_Q34java4lang5Class +extern java::lang::Class ClassClass; +#define VMClassLoaderClass _CL_Q34java4lang17VMClassLoader +extern java::lang::Class VMClassLoader; +#define ClassLoaderClass _CL_Q34java4lang11ClassLoader +extern java::lang::Class ClassLoaderClass; + +/////////// java.lang.ClassLoader native methods //////////// + +#ifdef INTERPRETER +java::lang::VMClassLoader *redirect = 0; +#endif + +java::lang::ClassLoader* +java::lang::ClassLoader::getVMClassLoader0 () +{ +#ifdef INTERPRETER + if (redirect == 0) + redirect = new java::lang::VMClassLoader; + return redirect; +#else + return 0; +#endif +} + +void +java::lang::ClassLoader::defineClass2 (jclass klass, jbyteArray data, + jint offset, jint length) +{ +#ifdef INTERPRETER + _Jv_DefineClass (klass, data, offset, length); +#endif +} + +java::lang::Class * +java::lang::ClassLoader::defineClass0 (jstring name, + jbyteArray data, + jint offset, + jint length) +{ +#ifdef INTERPRETER + jclass klass; + klass = (jclass) JvAllocObject (&ClassClass, sizeof (_Jv_InterpClass)); + + // synchronize on the class, so that it is not + // attempted initialized until we're done loading. + _Jv_MonitorEnter (klass); + + // record which is the defining loader + klass->loader = this; + + // register that we are the initiating loader... + if (name != 0) + { + _Jv_Utf8Const * name2 = _Jv_makeUtf8Const (name); + + _Jv_VerifyClassName (name2); + + klass->name = name2; + } + + // this will do the magic. loadInto also operates + // as an exception trampoline for now... + Throwable *ex = defineClass1 (klass, data, offset, length); + + if (ex) // we failed to load it + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + _Jv_UnregisterClass (klass); + + _Jv_MonitorExit (klass); + + // FIXME: Here we may want to test that EX does + // indeed represent a valid exception. That is, + // anything but ClassNotFoundException, + // or some kind of Error. + + JvThrow (ex); + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_LOADED); + + // if an exception is generated, this is initially missed. + // however, we come back here in handleException0 below... + _Jv_MonitorExit (klass); + + return klass; + +#else // INTERPRETER + + return 0; +#endif +} + +void +_Jv_WaitForState (jclass klass, int state) +{ + if (klass->state >= state) + return; + + _Jv_MonitorEnter (klass) ; + + if (state == JV_STATE_LINKED) + { + _Jv_MonitorExit (klass); + _Jv_InternClassStrings (klass); + return; + } + + java::lang::Thread *self = java::lang::Thread::currentThread(); + + // this is similar to the strategy for class initialization. + // if we already hold the lock, just leave. + while (klass->state <= state + && klass->thread + && klass->thread != self) + klass->wait (); + + _Jv_MonitorExit (klass); + + if (klass->state == JV_STATE_ERROR) + { + _Jv_Throw (new java::lang::LinkageError ()); + } +} + +// Finish linking a class. Only called from ClassLoader::resolveClass. +void +java::lang::ClassLoader::linkClass0 (java::lang::Class *klass) +{ + if (klass->state >= JV_STATE_LINKED) + return; + +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (klass)) + { + _Jv_PrepareClass (klass); + } +#endif + + _Jv_InternClassStrings (klass); +} + +void +java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass) +{ + klass->state = JV_STATE_ERROR; + klass->notifyAll (); +} + + +/** this is the only native method in VMClassLoader, so + we define it here. */ +jclass +java::lang::VMClassLoader::findBootClass (jstring name) +{ + return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), 0); +} + +jclass +java::lang::ClassLoader::findLoadedClass (jstring name) +{ + return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this); +} + +jclass +java::lang::ClassLoader::findSystemClass (jstring name) +{ + return _Jv_FindClass (_Jv_makeUtf8Const (name), 0); +} + + +/* This is the final step of linking, internalizing the constant strings + * of a class. This is called for both compiled and interpreted + * classes, and it is *only* called from ClassLoader::linkClass0, + * which is always in a context where the current thread has a lock on + * the class in question. We define it here, and not in resolve.cc, so that + * the entire resolve.cc can be #ifdef'ed away when not using the + * interpreter. */ +void +_Jv_InternClassStrings(jclass klass) +{ + if (klass->state >= JV_STATE_LINKED) + return; + + // short-circuit, so that mutually dependent classes are ok + klass->state = JV_STATE_LINKED; + + _Jv_Constants *pool = &klass->constants; + for (int i = 1; i < pool->size; ++i) + { + if (pool->tags[i] == JV_CONSTANT_String) + { + jstring str; + str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) pool->data[i]); + pool->data[i] = (void *) str; + pool->tags[i] |= JV_CONSTANT_ResolvedFlag; + } + } + + klass->notifyAll (); +} + + +// +// A single class can have many "initiating" class loaders, +// and a single "defining" class loader. The Defining +// class loader is what is returned from Class.getClassLoader() +// and is used when loading dependent classes during resolution. +// The set of initiating class loaders are used to ensure +// safety of linking, and is maintained in the hash table +// "initiated_classes". A defining classloader is by definition also +// initiating, so we only store classes in this table, if they have more +// than one class loader associated. +// + + +// Size of local hash table. +#define HASH_LEN 1013 + +// Hash function for Utf8Consts. +#define HASH_UTF(Utf) (((Utf)->hash) % HASH_LEN) + +struct _Jv_LoaderInfo { + _Jv_LoaderInfo *next; + java::lang::Class *klass; + java::lang::ClassLoader *loader; +}; + +_Jv_LoaderInfo *initiated_classes[HASH_LEN]; +jclass loaded_classes[HASH_LEN]; + +jclass +_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + _Jv_MonitorEnter (&ClassClass); + jint hash = HASH_UTF (name); + + // first, if LOADER is a defining loader, then it is also initiating + jclass klass; + for (klass = loaded_classes[hash]; klass; klass = klass->next) + { + if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) + break; + } + + // otherwise, it may be that the class in question was defined + // by some other loader, but that the loading was initiated by + // the loader in question. + if (!klass) + { + _Jv_LoaderInfo *info; + for (info = initiated_classes[hash]; info; info = info->next) + { + if (loader == info->loader + && _Jv_equalUtf8Consts (name, info->klass->name)) + { + klass = info->klass; + break; + } + } + } + + _Jv_MonitorExit (&ClassClass); + + return klass; +} + +void +_Jv_UnregisterClass (jclass the_class) +{ + _Jv_MonitorEnter (&ClassClass); + jint hash = HASH_UTF(the_class->name); + + jclass *klass = &(loaded_classes[hash]); + for ( ; *klass; klass = &((*klass)->next)) + { + if (*klass == the_class) + { + *klass = (*klass)->next; + break; + } + } + + _Jv_LoaderInfo **info = &(initiated_classes[hash]); + for ( ; *info; info = &((*info)->next)) + { + while ((*info)->klass == the_class) + { + *info = (*info)->next; + } + } + + _Jv_MonitorExit (&ClassClass); +} + +void +_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + _Jv_LoaderInfo *info = new _Jv_LoaderInfo; // non-gc alloc! + jint hash = HASH_UTF(klass->name); + + _Jv_MonitorEnter (&ClassClass); + info->loader = loader; + info->klass = klass; + info->next = initiated_classes[hash]; + initiated_classes[hash] = info; + _Jv_MonitorExit (&ClassClass); + +} + +// This function is called many times during startup, before main() is +// run. We do our runtime initialization here the very first time we +// are called. At that point in time we know for certain we are +// running single-threaded, so we don't need to lock when modifying +// `init'. CLASSES is NULL-terminated. +void +_Jv_RegisterClasses (jclass *classes) +{ + static bool init = false; + + if (! init) + { + init = true; + _Jv_InitThreads (); + _Jv_InitGC (); + _Jv_InitializeSyncMutex (); + } + + JvSynchronize sync (&ClassClass); + for (; *classes; ++classes) + { + jclass klass = *classes; + jint hash = HASH_UTF (klass->name); + klass->next = loaded_classes[hash]; + loaded_classes[hash] = klass; + + // registering a compiled class causes + // it to be immediately "prepared". + if (klass->state == JV_STATE_NOTING) + klass->state = JV_STATE_COMPILED; + } +} + +void +_Jv_RegisterClass (jclass klass) +{ + jclass classes[2]; + classes[0] = klass; + classes[1] = NULL; + _Jv_RegisterClasses (classes); +} + +#if 0 +// NOTE: this one is out of date with the new loader stuff... +jclass +_Jv_FindClassInCache (jstring name, java::lang::ClassLoader *loader) +{ + JvSynchronize sync (&ClassClass); + jint hash = name->hashCode(); + jclass klass = loaded_classes[(_Jv_ushort) hash % HASH_LEN]; + for ( ; klass; klass = klass->next) + { + if (loader == klass->loader + && _Jv_equal (klass->name, name, hash)) + break; + } + _Jv_MonitorExit (&ClassClass); + return klass; +} +#endif + +jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader) +{ + jclass klass = _Jv_FindClassInCache (name, loader); + +#ifdef INTERPRETER + if (! klass) + { + jstring sname = _Jv_NewStringUTF (name->data); + + if (loader) + { + // Load using a user-defined loader, jvmspec 5.3.2 + klass = loader->loadClass(sname, false); + + // if "loader" delegateted the loadClass operation + // to another loader, register explicitly + // that he is also an initiating loader of the + // given class. + + if (klass && (klass->getClassLoader () != loader)) + _Jv_RegisterInitiatingLoader (klass, 0); + } + else + { + if (redirect == NULL) + { + _Jv_InitClass (&ClassLoaderClass); + java::lang::ClassLoader::getSystemClassLoader (); + } + + // Load using the bootstrap loader jmspec 5.3.1 + klass = redirect -> loadClassInternal (sname, false, true); + + // register that we're an initiating loader + if (klass) + { + _Jv_RegisterInitiatingLoader (klass, 0); + } + } + } + else + { + // we need classes to be in the hash while + // we're loading, so that they can refer to themselves. + _Jv_WaitForState (klass, JV_STATE_LOADED); + } +#endif + + return klass; +} + +#if 0 +// NOTE: this one is out of date with the new class loader stuff... +jclass +_Jv_FindClass (jstring name, java::lang::ClassLoader *loader) +{ + jclass klass = _Jv_FindClassInCache (name, loader); + if (! klass) + { + if (loader) + { + klass = loader->loadClass(name); + } + else + { + // jmspec 5.3.1.2 + + // delegate to the system loader + klass = java::lang::ClassLoader::system.loadClass (sname); + + // register that we're an initiating loader + if (klass) + _Jv_RegisterInitiatingLoader (klass, 0); + } + } + else + { + _Jv_WaitForState (klass, JV_STATE_LOADED); + } + + return klass; +} +#endif + +jclass +_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader) +{ + jclass ret = (jclass) JvAllocObject (&ClassClass); + + ret->next = NULL; + ret->name = name; + ret->accflags = 0; + ret->superclass = superclass; + ret->constants.size = 0; + ret->constants.tags = NULL; + ret->constants.data = NULL; + ret->methods = NULL; + ret->method_count = 0; + ret->vtable_method_count = 0; + ret->fields = NULL; + ret->size_in_bytes = 0; + ret->field_count = 0; + ret->static_field_count = 0; + ret->vtable = NULL; + ret->interfaces = NULL; + ret->loader = loader; + ret->interface_count = 0; + ret->state = 0; + ret->thread = NULL; + + _Jv_RegisterClass (ret); + + return ret; +} + +jclass +_Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader) +{ + _Jv_Utf8Const *array_name; + int len; + if (element->isPrimitive()) + { + // For primitive types the array is cached in the class. + jclass ret = (jclass) element->methods; + if (ret) + return ret; + len = 3; + } + else + len = element->name->length + 5; + + { + char signature[len]; + int index = 0; + signature[index++] = '['; + // Compute name of array class to see if we've already cached it. + if (element->isPrimitive()) + { + signature[index++] = (char) element->method_count; + } + else + { + size_t length = element->name->length; + const char *const name = element->name->data; + if (name[0] != '[') + signature[index++] = 'L'; + memcpy (&signature[index], name, length); + index += length; + if (name[0] != '[') + signature[index++] = ';'; + } + array_name = _Jv_makeUtf8Const (signature, index); + } + + jclass array_class = _Jv_FindClassInCache (array_name, element->loader); + + if (! array_class) + { + // Create new array class. + array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader); + + // Note that `vtable_method_count' doesn't include the initial + // NULL slot. + int dm_count = ObjectClass.vtable_method_count + 1; + + // Create a new vtable by copying Object's vtable (except the + // class pointer, of course). Note that we allocate this as + // unscanned memory -- the vtables are handled specially by the + // GC. + int size = (sizeof (_Jv_VTable) + + ((dm_count - 1) * sizeof (void *))); + _Jv_VTable *vtable = (_Jv_VTable *) _Jv_AllocBytes (size); + vtable->clas = array_class; + memcpy (vtable->method, ObjectClass.vtable->method, + dm_count * sizeof (void *)); + array_class->vtable = vtable; + array_class->vtable_method_count = ObjectClass.vtable_method_count; + + // Stash the pointer to the element type. + array_class->methods = (_Jv_Method *) element; + + // Register our interfaces. + // FIXME: for JDK 1.2 we need Serializable. + static jclass interfaces[] = { &CloneableClass }; + array_class->interfaces = interfaces; + array_class->interface_count = 1; + + // as per vmspec 5.3.3.2 + array_class->accflags = element->accflags; + + // FIXME: initialize other Class instance variables, + // e.g. `fields'. + + // say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; + + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); + } + + // For primitive types, point back at this array. + if (element->isPrimitive()) + element->methods = (_Jv_Method *) array_class; + + return array_class; +} + + diff --git a/libjava/java/lang/natFirstThread.cc b/libjava/java/lang/natFirstThread.cc index d47446be4a8..319e487b8ab 100644 --- a/libjava/java/lang/natFirstThread.cc +++ b/libjava/java/lang/natFirstThread.cc @@ -27,7 +27,7 @@ details. */ typedef void main_func (jobject); void -java::lang::FirstThread::run (void) +java::lang::FirstThread::run0 (void) { Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22); Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4); @@ -41,6 +41,12 @@ java::lang::FirstThread::run (void) DIE ("class must be public"); #endif + if (klass == NULL) + { + klass = java::lang::Class::forName (klass_name); + if (klass != NULL) _Jv_InitClass (klass); + } + _Jv_Method *meth = _Jv_GetMethodLocal (klass, main_name, main_signature); // Some checks from Java Spec section 12.1.4. diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc index 3da8b5c01ce..2c951db0046 100644 --- a/libjava/java/lang/reflect/natArray.cc +++ b/libjava/java/lang/reflect/natArray.cc @@ -45,10 +45,11 @@ java::lang::reflect::Array::newInstance (jclass componentType, jintArray dimensi if (ndims == 1) return newInstance (componentType, dims[0]); jclass arrayType = componentType; - for (int i = 0; i < ndims; i++) - arrayType = _Jv_FindArrayClass (arrayType); - return _Jv_NewMultiArray (arrayType, ndims, dims); + for (int i = 0; i < ndims; i++) // FIXME 2nd arg should + // be "current" loader + arrayType = _Jv_FindArrayClass (arrayType, 0); + return _Jv_NewMultiArray (arrayType, ndims, dims); } jint diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 720bbc3d74e..a62d1ffeac2 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -378,8 +378,10 @@ java::lang::reflect::Method::getType () while (*ptr != ';' && ptr[1] != '\0'); break; } + + // FIXME: 2'nd argument should be "current loader" while (--num_arrays >= 0) - type = _Jv_FindArrayClass (type); + type = _Jv_FindArrayClass (type, 0); *argPtr++ = type; } parameter_types = args; diff --git a/libjava/java/net/natPlainSocketImpl.cc b/libjava/java/net/natPlainSocketImpl.cc index d42b821614f..e652ba7d8e0 100644 --- a/libjava/java/net/natPlainSocketImpl.cc +++ b/libjava/java/net/natPlainSocketImpl.cc @@ -354,7 +354,7 @@ java::net::PlainSocketImpl::getOption (jint optID) if (l_val.l_onoff) return new java::lang::Integer (l_val.l_linger); else - return new java::lang::Boolean (false); + return new java::lang::Boolean ((__java_boolean)false); #else JvThrow (new java::lang::InternalError ( JvNewStringUTF ("SO_LINGER not supported"))); |