diff options
Diffstat (limited to 'libjava/java/lang')
22 files changed, 300 insertions, 176 deletions
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 9736b78829b..3f09a5a445b 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -98,6 +98,13 @@ struct _Jv_ifaces jshort count; }; +// Used for vtable pointer manipulation. +union _Jv_Self +{ + char *vtable_ptr; + jclass self; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -105,7 +112,8 @@ struct _Jv_ifaces class java::lang::Class : public java::lang::Object { public: - static jclass forName (jstring className, java::lang::ClassLoader *loader); + static jclass forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader); static jclass forName (jstring className); JArray<jclass> *getClasses (void); @@ -208,9 +216,8 @@ public: // C++ ctors set the vtbl pointer to point at an offset inside the vtable // object. That doesn't work for Java, so this hack adjusts it back. - void *p = ((void **)this)[0]; - ((void **)this)[0] = (void *)((char *)p-2*sizeof (void *)); - + ((_Jv_Self *)this)->vtable_ptr -= 2 * sizeof (void *); + // We must initialize every field of the class. We do this in the // same order they are declared in Class.h, except for fields that // are initialized to NULL. diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 0f081ebbac6..e42c4be6146 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -30,7 +30,9 @@ public final class Class implements Serializable { public static native Class forName (String className) throws ClassNotFoundException; - public static native Class forName (String className, ClassLoader loader) + /** @since 1.2 */ + public static native Class forName (String className, boolean initialize, + ClassLoader loader) throws ClassNotFoundException; public native Class[] getClasses (); public native ClassLoader getClassLoader (); diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 402e8124864..f081cc55de1 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -1,6 +1,6 @@ // ClassLoader.java - Define policies for loading Java classes. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -25,18 +25,23 @@ import java.util.Stack; * @author Kresten Krab Thorup */ -public abstract class ClassLoader { - +public abstract class ClassLoader +{ static private ClassLoader system; private ClassLoader parent; - public ClassLoader getParent () + public final ClassLoader getParent () { /* FIXME: security */ return parent; } - - public static native ClassLoader getSystemClassLoader (); + + public static ClassLoader getSystemClassLoader () + { + if (system == null) + system = gnu.gcj.runtime.VMClassLoader.instance; + return system; + } /** * Creates a <code>ClassLoader</code> with no parent. @@ -55,6 +60,7 @@ public abstract class ClassLoader { * <code>checkCreateClassLoader</code> on the current * security manager. * @exception java.lang.SecurityException if not allowed + * @since 1.2 */ protected ClassLoader(ClassLoader parent) { @@ -71,12 +77,12 @@ public abstract class ClassLoader { * @see ClassLoader#loadClass(String,boolean) * @exception java.lang.ClassNotFoundException */ - public Class loadClass(String name) - throws java.lang.ClassNotFoundException, java.lang.LinkageError + 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) @@ -96,7 +102,7 @@ public abstract class ClassLoader { * @deprecated */ protected Class loadClass(String name, boolean link) - throws java.lang.ClassNotFoundException, java.lang.LinkageError + throws java.lang.ClassNotFoundException { Class c = findLoadedClass (name); @@ -106,7 +112,7 @@ public abstract class ClassLoader { if (parent != null) return parent.loadClass (name, link); else - c = findSystemClass (name); + c = system.findClass (name); } catch (ClassNotFoundException ex) { /* ignore, we'll try findClass */; } @@ -130,6 +136,7 @@ public abstract class ClassLoader { * @param name Name of the class to find. * @return The class found. * @exception java.lang.ClassNotFoundException + * @since 1.2 */ protected Class findClass (String name) throws ClassNotFoundException @@ -201,7 +208,7 @@ public abstract class ClassLoader { throw new java.lang.LinkageError ("class " + name + " already loaded"); - + try { // Since we're calling into native code here, // we better make sure that any generated @@ -232,7 +239,6 @@ public abstract class ClassLoader { int len) 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 @@ -262,13 +268,11 @@ public abstract class ClassLoader { * @exception java.lang.LinkageError */ protected final void resolveClass(Class clazz) - throws java.lang.LinkageError { resolveClass0(clazz); } static void resolveClass0(Class clazz) - throws java.lang.LinkageError { synchronized (clazz) { @@ -288,15 +292,13 @@ public abstract class ClassLoader { /** Internal method. Calls _Jv_PrepareClass and * _Jv_PrepareCompiledClass. This is only called from resolveClass. */ - private static native void linkClass0(Class clazz) - throws java.lang.LinkageError; + 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); - /** * Returns a class found in a system-specific way, typically * via the <code>java.class.path</code> system property. Loads the @@ -307,14 +309,14 @@ public abstract class ClassLoader { * @exception java.lang.LinkageError * @exception java.lang.ClassNotFoundException */ - protected Class findSystemClass(String name) - throws java.lang.ClassNotFoundException, java.lang.LinkageError + protected final Class findSystemClass(String name) + throws java.lang.ClassNotFoundException { return getSystemClassLoader ().loadClass (name); } /* - * Does currently nothing. + * Does currently nothing. FIXME. */ protected final void setSigners(Class claz, Object[] signers) { /* claz.setSigners (signers); */ @@ -328,13 +330,13 @@ public abstract class ClassLoader { * @param name class to find. * @return the class loaded, or null. */ - protected native Class findLoadedClass(String name); + protected final native Class findLoadedClass(String name); - public static final InputStream getSystemResourceAsStream(String name) { + public static InputStream getSystemResourceAsStream(String name) { return getSystemClassLoader().getResourceAsStream (name); } - public static final URL getSystemResource(String name) { + public static URL getSystemResource(String name) { return getSystemClassLoader().getResource (name); } @@ -397,7 +399,7 @@ public abstract class ClassLoader { return null; } - public Enumeration getResources (String name) throws IOException + public final Enumeration getResources (String name) throws IOException { // The rules say search the parent class if non-null, // otherwise search the built-in class loader (assumed to be diff --git a/libjava/java/lang/ExceptionInInitializerError.java b/libjava/java/lang/ExceptionInInitializerError.java index 0aad2fc89ea..d43a8599127 100644 --- a/libjava/java/lang/ExceptionInInitializerError.java +++ b/libjava/java/lang/ExceptionInInitializerError.java @@ -1,6 +1,6 @@ // ExceptionInInitializerError.java -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -38,7 +38,7 @@ public class ExceptionInInitializerError extends LinkageError public ExceptionInInitializerError (Throwable e) { - super (); + super (e.toString()); exception = e; } @@ -49,17 +49,35 @@ public class ExceptionInInitializerError extends LinkageError public void printStackTrace () { - exception.printStackTrace (); + if (exception != null) + { + System.err.print (this.getClass().getName() + ": "); + exception.printStackTrace (); + } + else + super.printStackTrace (); } public void printStackTrace (PrintStream ps) { - exception.printStackTrace (ps); + if (exception != null) + { + ps.print (this.getClass().getName() + ": "); + exception.printStackTrace (ps); + } + else + super.printStackTrace (ps); } public void printStackTrace (PrintWriter pw) { - exception.printStackTrace (pw); + if (exception != null) + { + pw.print (this.getClass().getName() + ": "); + exception.printStackTrace (pw); + } + else + super.printStackTrace (pw); } // The exception that caused this error. diff --git a/libjava/java/lang/Integer.java b/libjava/java/lang/Integer.java index 2cf7bb45349..88d0769a275 100644 --- a/libjava/java/lang/Integer.java +++ b/libjava/java/lang/Integer.java @@ -155,13 +155,15 @@ public final class Integer extends Number implements Comparable public static Integer getInteger(String prop, Integer defobj) { try - { - return decode(System.getProperty(prop)); - } + { + String val = System.getProperty(prop); + if (val != null) + return decode(val); + } catch (NumberFormatException ex) - { - return defobj; - } + { + } + return defobj; } public int hashCode() diff --git a/libjava/java/lang/Long.java b/libjava/java/lang/Long.java index cb2cec2d904..2e812f9696d 100644 --- a/libjava/java/lang/Long.java +++ b/libjava/java/lang/Long.java @@ -156,13 +156,15 @@ public final class Long extends Number implements Comparable public static Long getLong(String prop, Long defobj) { try - { - return decode(System.getProperty(prop)); - } + { + String val = System.getProperty(prop); + if (val != null) + return decode(val); + } catch (NumberFormatException ex) - { - return defobj; - } + { + } + return defobj; } public int hashCode() diff --git a/libjava/java/lang/Runtime.java b/libjava/java/lang/Runtime.java index e746c60b384..28befc26d19 100644 --- a/libjava/java/lang/Runtime.java +++ b/libjava/java/lang/Runtime.java @@ -1,6 +1,6 @@ // Runtime.java - Runtime class. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -63,6 +63,10 @@ public class Runtime } public native void exit (int status); + + // Shutdown the runtime without a SecurityManager check. libgcj uses this + // exit function internally. + final native void _exit (int status); public native long freeMemory (); public native void gc (); diff --git a/libjava/java/lang/String.java b/libjava/java/lang/String.java index 22e11530f77..b985cf4186c 100644 --- a/libjava/java/lang/String.java +++ b/libjava/java/lang/String.java @@ -347,6 +347,5 @@ public final class String implements Serializable, Comparable private native void init (byte[] chars, int hibyte, int offset, int count); private native void init (byte[] chars, int offset, int count, String enc) throws UnsupportedEncodingException; - private static native void unintern (Object obj); private static native void rehash (); } diff --git a/libjava/java/lang/System.java b/libjava/java/lang/System.java index 162bc1f21eb..0f7bd7ba8b7 100644 --- a/libjava/java/lang/System.java +++ b/libjava/java/lang/System.java @@ -230,7 +230,7 @@ public final class System public static void setSecurityManager (SecurityManager s) { if (secman != null) - throw new SecurityException (); + secman.checkPermission(new RuntimePermission("setSecurityManager")); secman = s; } diff --git a/libjava/java/lang/ThreadGroup.java b/libjava/java/lang/ThreadGroup.java index cf1e7171ccb..bdf37f9ec9c 100644 --- a/libjava/java/lang/ThreadGroup.java +++ b/libjava/java/lang/ThreadGroup.java @@ -1,5 +1,5 @@ /* java.lang.ThreadGroup - Copyright (C) 1998, 2000 Free Software Foundation, Inc. + Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -204,16 +204,21 @@ public class ThreadGroup * @return the number of active threads in this ThreadGroup and * its descendants. * @specnote it isn't clear what the definition of an "Active" thread is. - * Current JDKs regard all threads as active until they are - * finished, regardless of whether the thread has been started - * or not. We implement this behaviour. - * There is open JDC bug, <A HREF="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html"> + * Current JDKs regard a thread as active if has been + * started and not finished. We implement this behaviour. + * There is a JDC bug, <A HREF="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html"> * 4089701</A>, regarding this issue. * */ public synchronized int activeCount() { - int total = threads.size(); + int total = 0; + for (int i = 0; i < threads.size(); ++i) + { + if (((Thread) threads.elementAt(i)).isAlive ()) + ++total; + } + for (int i=0; i < groups.size(); i++) { ThreadGroup g = (ThreadGroup) groups.elementAt(i); @@ -274,7 +279,11 @@ public class ThreadGroup { Enumeration e = threads.elements(); while (e.hasMoreElements() && next_index < list.length) - list[next_index++] = (Thread) e.nextElement(); + { + Thread t = (Thread) e.nextElement(); + if (t.isAlive ()) + list[next_index++] = t; + } if (recurse && next_index != list.length) { e = groups.elements(); @@ -502,7 +511,19 @@ public class ThreadGroup { if (thread != null) System.out.print("Exception in thread \"" + thread.getName() + "\" "); - t.printStackTrace(); + try + { + t.printStackTrace(); + } + catch (Throwable x) + { + // This means that something is badly screwed up with the runtime, + // or perhaps someone is messing with the SecurityManager. In any + // case, try to deal with it gracefully. + System.out.println(t); + System.err.println("*** Got " + x.toString() + + " while trying to print stack trace"); + } had_uncaught_exception = true; } } diff --git a/libjava/java/lang/Throwable.java b/libjava/java/lang/Throwable.java index 4aa21399c5a..5c330fe315e 100644 --- a/libjava/java/lang/Throwable.java +++ b/libjava/java/lang/Throwable.java @@ -57,7 +57,7 @@ class CPlusPlusDemangler extends OutputStream CPlusPlusDemangler (PrintWriter writer) throws IOException { p = writer; - proc = Runtime.getRuntime ().exec ("c++filt"); + proc = Runtime.getRuntime ().exec ("c++filt -s java"); procOut = proc.getOutputStream (); procIn = proc.getInputStream (); } diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 6678b7794cf..0786cacf517 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -72,7 +72,8 @@ static _Jv_Utf8Const *finit_leg_name = _Jv_makeUtf8Const ("$finit$", 7); jclass -java::lang::Class::forName (jstring className, java::lang::ClassLoader *loader) +java::lang::Class::forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader) { if (! className) JvThrow (new java::lang::NullPointerException); @@ -90,10 +91,11 @@ java::lang::Class::forName (jstring className, java::lang::ClassLoader *loader) ? _Jv_FindClassFromSignature (name->data, loader) : _Jv_FindClass (name, loader)); - if (klass) + if (klass == NULL) + throw new java::lang::ClassNotFoundException (className); + + if (initialize) _Jv_InitClass (klass); - else - JvThrow (new java::lang::ClassNotFoundException (className)); return klass; } @@ -102,7 +104,7 @@ jclass java::lang::Class::forName (jstring className) { // FIXME: should use class loader from calling method. - return forName (className, NULL); + return forName (className, true, NULL); } java::lang::reflect::Constructor * @@ -290,8 +292,12 @@ java::lang::Class::getSignature (JArray<jclass> *param_types, java::lang::StringBuffer *buf = new java::lang::StringBuffer (); buf->append((jchar) '('); jclass *v = elements (param_types); - for (int i = 0; i < param_types->length; ++i) - v[i]->getSignature(buf); + // A NULL param_types means "no parameters". + if (param_types != NULL) + { + for (int i = 0; i < param_types->length; ++i) + v[i]->getSignature(buf); + } buf->append((jchar) ')'); if (is_constructor) buf->append((jchar) 'V'); @@ -627,7 +633,7 @@ java::lang::Class::isAssignableFrom (jclass klass) jboolean java::lang::Class::isInstance (jobject obj) { - if (__builtin_expect (! obj || isPrimitive (), false)) + if (! obj) return false; _Jv_InitClass (this); return _Jv_IsAssignableFrom (this, JV_CLASS (obj)); @@ -903,11 +909,8 @@ _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx) jboolean _Jv_IsAssignableFrom (jclass target, jclass source) { - if (source == target - || (target == &ObjectClass && !source->isPrimitive()) - || (source->ancestors != NULL - && source->ancestors[source->depth - target->depth] == target)) - return true; + if (source == target) + return true; // If target is array, so must source be. if (target->isArray ()) @@ -932,15 +935,31 @@ _Jv_IsAssignableFrom (jclass target, jclass source) if (__builtin_expect ((if_idt == NULL), false)) return false; // No class implementing TARGET has been loaded. jshort cl_iindex = cl_idt->cls.iindex; - if (cl_iindex <= if_idt->iface.ioffsets[0]) + if (cl_iindex < if_idt->iface.ioffsets[0]) { jshort offset = if_idt->iface.ioffsets[cl_iindex]; - if (offset < cl_idt->cls.itable_length + if (offset != -1 && offset < cl_idt->cls.itable_length && cl_idt->cls.itable[offset] == target) return true; } + return false; } + + // Primitive TYPE classes are only assignable to themselves. + if (__builtin_expect (target->isPrimitive(), false)) + return false; + if (target == &ObjectClass) + { + if (source->isPrimitive()) + return false; + return true; + } + else if (source->ancestors != NULL + && source->depth >= target->depth + && source->ancestors[source->depth - target->depth] == target) + return true; + return false; } @@ -1310,7 +1329,7 @@ _Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num) { if (j >= num) goto found; - if (i > ifaces[j]->idt->iface.ioffsets[0]) + if (i >= ifaces[j]->idt->iface.ioffsets[0]) continue; int ioffset = ifaces[j]->idt->iface.ioffsets[i]; /* We can potentially share this position with another class. */ diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 979de3fc2d6..b3dfdff38f9 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -48,15 +48,6 @@ details. */ /////////// java.lang.ClassLoader native methods //////////// -java::lang::ClassLoader * -java::lang::ClassLoader::getSystemClassLoader (void) -{ - JvSynchronize sync (&ClassLoaderClass); - if (! system) - system = gnu::gcj::runtime::VMClassLoader::getVMClassLoader (); - return system; -} - java::lang::Class * java::lang::ClassLoader::defineClass0 (jstring name, jbyteArray data, @@ -79,7 +70,9 @@ java::lang::ClassLoader::defineClass0 (jstring name, { _Jv_Utf8Const * name2 = _Jv_makeUtf8Const (name); - _Jv_VerifyClassName (name2); + if (! _Jv_VerifyClassName (name2)) + JvThrow (new java::lang::ClassFormatError + (JvNewStringLatin1 ("erroneous class name"))); klass->name = name2; } @@ -176,11 +169,10 @@ java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass) klass->notifyAll (); } - -/** this is the only native method in VMClassLoader, so - we define it here. */ +// This is the findClass() implementation for the System classloader. It is +// the only native method in VMClassLoader, so we define it here. jclass -gnu::gcj::runtime::VMClassLoader::findSystemClass (jstring name) +gnu::gcj::runtime::VMClassLoader::findClass (jstring name) { _Jv_Utf8Const *name_u = _Jv_makeUtf8Const (name); jclass klass = _Jv_FindClassInCache (name_u, 0); @@ -209,6 +201,12 @@ gnu::gcj::runtime::VMClassLoader::findSystemClass (jstring name) klass = _Jv_FindClassInCache (name_u, 0); } } + + // Now try loading using the interpreter. + if (! klass) + { + klass = java::net::URLClassLoader::findClass (name); + } return klass; } @@ -400,7 +398,8 @@ _Jv_UnregisterClass (jclass the_class) void _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) { - _Jv_LoaderInfo *info = new _Jv_LoaderInfo; // non-gc alloc! + // non-gc alloc! + _Jv_LoaderInfo *info = (_Jv_LoaderInfo *) _Jv_Malloc (sizeof(_Jv_LoaderInfo)); jint hash = HASH_UTF(klass->name); _Jv_MonitorEnter (&ClassClass); @@ -409,7 +408,6 @@ _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) info->next = initiated_classes[hash]; initiated_classes[hash] = info; _Jv_MonitorExit (&ClassClass); - } // This function is called many times during startup, before main() is diff --git a/libjava/java/lang/natDouble.cc b/libjava/java/lang/natDouble.cc index bc60ddaec28..af2d70ad6f3 100644 --- a/libjava/java/lang/natDouble.cc +++ b/libjava/java/lang/natDouble.cc @@ -10,15 +10,12 @@ details. */ #include <config.h> -#if HAVE_ALLOCA_H -#include <alloca.h> -#endif - #include <stdlib.h> #include <gcj/cni.h> #include <java/lang/String.h> #include <java/lang/Double.h> +#include <java/lang/Character.h> #include <java/lang/NumberFormatException.h> #include <jvm.h> @@ -164,23 +161,28 @@ jdouble java::lang::Double::parseDouble(jstring str) { int length = str->length(); - // Note that UTF can expand 3x. - -#ifdef HAVE_ALLOCA - char *data = (char *) alloca (3 * length + 1); -#else -#error --- need an alternate implementation here --- -#endif - - data[_Jv_GetStringUTFRegion (str, 0, length, data)] = 0; - - struct _Jv_reent reent; - memset (&reent, 0, sizeof reent); - - double val = _strtod_r (&reent, data, NULL); - - if (reent._errno) - _Jv_Throw (new NumberFormatException); - - return val; + while (length > 0 + && Character::isWhitespace(str->charAt(length - 1))) + length--; + jsize start = 0; + while (length > 0 + && Character::isWhitespace(str->charAt(start))) + start++, length--; + + if (length > 0) + { + // Note that UTF can expand 3x. + char *data = (char *) __builtin_alloca (3 * length + 1); + jsize blength = _Jv_GetStringUTFRegion (str, start, length, data); + data[blength] = 0; + + struct _Jv_reent reent; + memset (&reent, 0, sizeof reent); + + char *endptr; + double val = _strtod_r (&reent, data, &endptr); + if (endptr == data + blength) + return val; + } + _Jv_Throw (new NumberFormatException); } diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 5ff7d2edacf..3f1a0b335fc 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -1,6 +1,6 @@ // natRuntime.cc - Implementation of native side of Runtime class. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -78,7 +78,12 @@ void java::lang::Runtime::exit (jint status) { checkExit (status); + _exit (status); +} +void +java::lang::Runtime::_exit (jint status) +{ // Make status right for Unix. This is perhaps strange. if (status < 0 || status > 255) status = 255; diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc index bb903fbde6f..255d4cf11c7 100644 --- a/libjava/java/lang/natString.cc +++ b/libjava/java/lang/natString.cc @@ -1,6 +1,6 @@ // natString.cc - Implementation of java.lang.String native methods. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -29,6 +29,7 @@ details. */ #include <gnu/gcj/convert/BytesToUnicode.h> #include <jvm.h> +static void unintern (jobject); static jstring* strhash = NULL; static int strhash_count = 0; /* Number of slots used in strhash. */ static int strhash_size = 0; /* Number of slots available in strhash. @@ -45,6 +46,10 @@ static int strhash_size = 0; /* Number of slots available in strhash. #define DELETED_STRING ((jstring)(~0)) #define SET_STRING_IS_INTERNED(STR) /* nothing */ +#define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01) +#define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01) +#define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01) + /* Find a slot where the string with elements DATA, length LEN, and hash HASH should go in the strhash table of interned strings. */ jstring* @@ -57,11 +62,12 @@ _Jv_StringFindSlot (jchar* data, jint len, jint hash) int index = start_index; /* step must be non-zero, and relatively prime with strhash_size. */ - int step = 8 * hash + 7; + jint step = (hash ^ (hash >> 16)) | 1; for (;;) { jstring* ptr = &strhash[index]; - if (*ptr == NULL) + jstring value = (jstring) UNMASK_PTR (*ptr); + if (value == NULL) { if (deleted_index >= 0) return (&strhash[deleted_index]); @@ -70,8 +76,8 @@ _Jv_StringFindSlot (jchar* data, jint len, jint hash) } else if (*ptr == DELETED_STRING) deleted_index = index; - else if ((*ptr)->length() == len - && memcmp(JvGetStringChars(*ptr), data, 2*len) == 0) + else if (value->length() == len + && memcmp(JvGetStringChars(value), data, 2*len) == 0) return (ptr); index = (index + step) & (strhash_size - 1); JvAssert (index != start_index); @@ -115,16 +121,18 @@ java::lang::String::rehash() if (strhash == NULL) { strhash_size = 1024; - strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring)); + strhash = (jstring *) _Jv_AllocBytesChecked (strhash_size + * sizeof (jstring)); memset (strhash, 0, strhash_size * sizeof (jstring)); } else { int i = strhash_size; jstring* ptr = strhash + i; - strhash_size *= 2; - strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring)); - memset (strhash, 0, strhash_size * sizeof (jstring)); + int nsize = strhash_size * 2; + jstring *next = (jstring *) _Jv_AllocBytesChecked (nsize + * sizeof (jstring)); + memset (next, 0, nsize * sizeof (jstring)); while (--i >= 0) { @@ -134,19 +142,23 @@ java::lang::String::rehash() /* This is faster equivalent of * *__JvGetInternSlot(*ptr) = *ptr; */ - jint hash = (*ptr)->hashCode(); - jint index = hash & (strhash_size - 1); - jint step = 8 * hash + 7; + jstring val = (jstring) UNMASK_PTR (*ptr); + jint hash = val->hashCode(); + jint index = hash & (nsize - 1); + jint step = (hash ^ (hash >> 16)) | 1; for (;;) { - if (strhash[index] == NULL) + if (next[index] == NULL) { - strhash[index] = *ptr; + next[index] = *ptr; break; } - index = (index + step) & (strhash_size - 1); + index = (index + step) & (nsize - 1); } } + + strhash_size = nsize; + strhash = next; } } @@ -154,30 +166,61 @@ jstring java::lang::String::intern() { JvSynchronize sync (&StringClass); - if (4 * strhash_count >= 3 * strhash_size) + if (3 * strhash_count >= 2 * strhash_size) rehash(); jstring* ptr = _Jv_StringGetSlot(this); if (*ptr != NULL && *ptr != DELETED_STRING) - return *ptr; - SET_STRING_IS_INTERNED(this); + { + // See description in unintern() to understand this. + *ptr = (jstring) MASK_PTR (*ptr); + return (jstring) UNMASK_PTR (*ptr); + } + jstring str = this->data == this ? this + : _Jv_NewString(JvGetStringChars(this), this->length()); + SET_STRING_IS_INTERNED(str); strhash_count++; - *ptr = this; + *ptr = str; // When string is GC'd, clear the slot in the hash table. - // _Jv_RegisterFinalizer ((void *) this, unintern); - return this; + _Jv_RegisterFinalizer ((void *) str, unintern); + return str; } /* Called by String fake finalizer. */ -void -java::lang::String::unintern (jobject obj) +static void +unintern (jobject obj) { JvSynchronize sync (&StringClass); jstring str = reinterpret_cast<jstring> (obj); jstring* ptr = _Jv_StringGetSlot(str); if (*ptr == NULL || *ptr == DELETED_STRING) return; - *ptr = DELETED_STRING; - strhash_count--; + + // We assume the lowest bit of the pointer is free for our nefarious + // manipulations. What we do is set it to `0' (implicitly) when + // interning the String. If we subsequently re-intern the same + // String, then we set the bit. When finalizing, if the bit is set + // then we clear it and re-register the finalizer. We know this is + // a safe approach because both the intern() and unintern() acquire + // the class lock; this bit can't be manipulated when the lock is + // not held. So if we are finalizing and the bit is clear then we + // know all references are gone and we can clear the entry in the + // hash table. The naive approach of simply clearing the pointer + // here fails in the case where a request to intern a new string + // with the same contents is made between the time the intern()d + // string is found to be unreachable and when the finalizer is + // actually run. In this case we could clear a pointer to a valid + // string, and future intern() calls for that particular value would + // spuriously fail. + if (PTR_MASKED (*ptr)) + { + *ptr = (jstring) UNMASK_PTR (*ptr); + _Jv_RegisterFinalizer ((void *) obj, unintern); + } + else + { + *ptr = DELETED_STRING; + strhash_count--; + } } jstring @@ -222,17 +265,21 @@ _Jv_NewStringUtf8Const (Utf8Const* str) chrs = JvGetStringChars(jstr); } + jint hash = 0; while (data < limit) - *chrs++ = UTF8_GET(data, limit); + { + jchar ch = UTF8_GET(data, limit); + hash = (31 * hash) + ch; + *chrs++ = ch; + } chrs -= length; JvSynchronize sync (&StringClass); - if (4 * strhash_count >= 3 * strhash_size) + if (3 * strhash_count >= 2 * strhash_size) java::lang::String::rehash(); - int hash = str->hash; jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); if (*ptr != NULL && *ptr != DELETED_STRING) - return *ptr; + return (jstring) UNMASK_PTR (*ptr); strhash_count++; if (jstr == NULL) { @@ -242,6 +289,8 @@ _Jv_NewStringUtf8Const (Utf8Const* str) } *ptr = jstr; SET_STRING_IS_INTERNED(jstr); + // When string is GC'd, clear the slot in the hash table. + _Jv_RegisterFinalizer ((void *) jstr, unintern); return jstr; } diff --git a/libjava/java/lang/natSystem.cc b/libjava/java/lang/natSystem.cc index 330be72220f..57e135c7db5 100644 --- a/libjava/java/lang/natSystem.cc +++ b/libjava/java/lang/natSystem.cc @@ -90,7 +90,7 @@ java::lang::System::arraycopy (jobject src, jint src_offset, jint count) { if (! src || ! dst) - _Jv_Throw (new NullPointerException); + throw new NullPointerException; jclass src_c = src->getClass(); jclass dst_c = dst->getClass(); @@ -100,14 +100,14 @@ java::lang::System::arraycopy (jobject src, jint src_offset, if (! src_c->isArray() || ! dst_c->isArray() || src_comp->isPrimitive() != dst_comp->isPrimitive() || (src_comp->isPrimitive() && src_comp != dst_comp)) - _Jv_Throw (new ArrayStoreException); + throw new ArrayStoreException; __JArray *src_a = (__JArray *) src; __JArray *dst_a = (__JArray *) dst; if (src_offset < 0 || dst_offset < 0 || count < 0 || src_offset + count > src_a->length || dst_offset + count > dst_a->length) - _Jv_Throw (new ArrayIndexOutOfBoundsException); + throw new ArrayIndexOutOfBoundsException; // Do-nothing cases. if ((src == dst && src_offset == dst_offset) @@ -149,7 +149,7 @@ java::lang::System::arraycopy (jobject src, jint src_offset, { if (*src_elts && ! dst_comp->isAssignableFrom((*src_elts)->getClass())) - _Jv_Throw (new ArrayStoreException); + throw new ArrayStoreException; *dst_elts++ = *src_elts++; } } @@ -249,9 +249,11 @@ java::lang::System::getSystemTimeZone (void) mktime(tim = localtime(¤t_time)); #ifdef STRUCT_TM_HAS_GMTOFF - tzoffset = -(tim->tm_gmtoff); // tm_gmtoff is secs EAST of UTC. + // tm_gmtoff is secs EAST of UTC. + tzoffset = -(tim->tm_gmtoff) + tim->tm_isdst * 3600L; #elif HAVE_TIMEZONE - tzoffset = timezone; // timezone is secs WEST of UTC. + // timezone is secs WEST of UTC. + tzoffset = timezone; #else // FIXME: there must be another global if neither tm_gmtoff nor timezone // is available, esp. if tzname is valid. diff --git a/libjava/java/lang/natThrowable.cc b/libjava/java/lang/natThrowable.cc index dab3ba6387a..e2821c5ddfb 100644 --- a/libjava/java/lang/natThrowable.cc +++ b/libjava/java/lang/natThrowable.cc @@ -39,10 +39,6 @@ details. */ #include <name-finder.h> -#ifdef __ia64__ -extern "C" int __ia64_backtrace (void **array, int size); -#endif - /* FIXME: size of the stack trace is limited to 128 elements. It's undoubtedly sensible to limit the stack trace, but 128 is rather arbitrary. It may be better to configure this. */ @@ -52,20 +48,16 @@ java::lang::Throwable::fillInStackTrace (void) { if (! trace_enabled) return this; -#if defined (HAVE_BACKTRACE) || defined (__ia64__) +#if defined (HAVE_BACKTRACE) void *p[128]; // We subtract 1 from the number of elements because we don't want // to include the call to fillInStackTrace in the trace. -#if defined (__ia64__) - int n = __ia64_backtrace (p, 128) - 1; -#else int n = backtrace (p, 128) - 1; -#endif if (n > 0) { - // ??? Might this cause a problem if the byte array isn't aligned? + // We copy the array below to deal with alignment issues. stackTrace = JvNewByteArray (n * sizeof p[0]); memcpy (elements (stackTrace), p+1, (n * sizeof p[0])); } @@ -83,8 +75,9 @@ java::lang::Throwable::printRawStackTrace (java::io::PrintWriter *wr) if (!stackTrace) return; - void **p = (void **)elements (stackTrace); - int depth = stackTrace->length / sizeof p[0]; + int depth = stackTrace->length / sizeof (void *); + void *p[depth]; + memcpy (p, elements (stackTrace), sizeof p); _Jv_name_finder finder (_Jv_ThisExecutable ()); diff --git a/libjava/java/lang/reflect/Constructor.java b/libjava/java/lang/reflect/Constructor.java index 77c437e24fa..2d527c3ba75 100644 --- a/libjava/java/lang/reflect/Constructor.java +++ b/libjava/java/lang/reflect/Constructor.java @@ -1,6 +1,6 @@ // Constructor.java - Represents a constructor for a class. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -38,6 +38,8 @@ public final class Constructor extends AccessibleObject implements Member public Class[] getExceptionTypes () { + if (exception_types == null) + getType(); return (Class[]) exception_types.clone(); } diff --git a/libjava/java/lang/reflect/Method.java b/libjava/java/lang/reflect/Method.java index 119a56f2141..e616670e587 100644 --- a/libjava/java/lang/reflect/Method.java +++ b/libjava/java/lang/reflect/Method.java @@ -1,6 +1,6 @@ // Method.java - Represent method of class or interface. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -39,6 +39,8 @@ public final class Method extends AccessibleObject implements Member public Class[] getExceptionTypes () { + if (exception_types == null) + getType(); return (Class[]) exception_types.clone(); } diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc index a8da794bdb8..2209ad9fa64 100644 --- a/libjava/java/lang/reflect/natConstructor.cc +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -34,6 +34,10 @@ java::lang::reflect::Constructor::getType () declaringClass, ¶meter_types, NULL); + + // FIXME: for now we have no way to get exception information. + exception_types = + (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$, NULL); } jobject diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index 57421d690b4..0aedc4ea363 100644 --- a/libjava/java/lang/reflect/natField.cc +++ b/libjava/java/lang/reflect/natField.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation This file is part of libgcj. @@ -44,17 +44,8 @@ jclass java::lang::reflect::Field::getType () { jfieldID fld = _Jv_FromReflectedField (this); - if (! fld->isResolved()) - { - JvSynchronize sync (declaringClass); - if (! fld->isResolved()) - { - fld->type - = _Jv_FindClassFromSignature(((Utf8Const*) (fld->type))->data, - declaringClass->getClassLoader()); - fld->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; - } - } + JvSynchronize sync (declaringClass); + _Jv_ResolveField (fld, declaringClass->getClassLoader ()); return fld->type; } |