diff options
author | (no author) <(no author)@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-09-22 21:39:00 +0000 |
---|---|---|
committer | (no author) <(no author)@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-09-22 21:39:00 +0000 |
commit | 2e9c0dc38e2692b04281844366dbb367ae1294e1 (patch) | |
tree | e56f44693864144d87710daeab9743d4e76b6037 /libjava/java/lang | |
parent | 780b7d9b87ddf306aa31c750d5eb9d96a9cb69ea (diff) |
This commit was manufactured by cvs2svn to create tagobjc-improvements-candidate-20030922
'objc-improvements-candidate-20030922'.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/tags/objc-improvements-candidate-20030922@71666 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/java/lang')
28 files changed, 765 insertions, 371 deletions
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index db05cb618a6..9bcff6fbb55 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -243,7 +243,7 @@ public: private: - void checkMemberAccess (jint flags); + void memberAccessCheck (jint flags); void initializeClass (void); @@ -328,6 +328,9 @@ private: friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); friend void _Jv_MakeVTable (jclass); + friend jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, + jint flags); + // Return array class corresponding to element type KLASS, creating it if // necessary. inline friend jclass @@ -366,6 +369,8 @@ private: friend class gnu::gcj::runtime::StackTrace; friend class java::io::VMObjectStreamClass; + friend void _Jv_sharedlib_register_hook (jclass klass); + // Chain for class pool. jclass next; // Name of class. diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 44f5b5ab529..bd776913fdd 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -72,14 +72,7 @@ public final class Class implements Serializable public Method getDeclaredMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException, SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - { - sm.checkMemberAccess(this, Member.DECLARED); - Package p = getPackage(); - if (p != null) - sm.checkPackageAccess(p.getName()); - } + memberAccessCheck(Member.DECLARED); if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) throw new NoSuchMethodException(methodName); @@ -101,9 +94,7 @@ public final class Class implements Serializable public Field getField (String fieldName) throws NoSuchFieldException, SecurityException { - SecurityManager s = System.getSecurityManager(); - if (s != null) - s.checkMemberAccess (this, java.lang.reflect.Member.DECLARED); + memberAccessCheck (Member.PUBLIC); Field fld = getField(fieldName, fieldName.hashCode()); if (fld == null) throw new NoSuchFieldException(fieldName); @@ -148,14 +139,7 @@ public final class Class implements Serializable public Method getMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException, SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - { - sm.checkMemberAccess(this, Member.PUBLIC); - Package p = getPackage(); - if (p != null) - sm.checkPackageAccess(p.getName()); - } + memberAccessCheck(Member.PUBLIC); if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) throw new NoSuchMethodException(methodName); @@ -334,14 +318,6 @@ public final class Class implements Serializable { } - // Do a security check. - private void checkMemberAccess (int flags) - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkMemberAccess(this, flags); - } - // Initialize the class. private native void initializeClass (); @@ -361,4 +337,20 @@ public final class Class implements Serializable return ""; return name.substring(0, lastInd); } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } } diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 5ae70cdba95..008a19e6603 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -162,12 +162,10 @@ public abstract class ClassLoader SecurityManager sm = System.getSecurityManager(); if (sm != null) { - /* FIXME: security, getClassContext() not implemented. Class c = VMSecurityManager.getClassContext()[1]; ClassLoader cl = c.getClassLoader(); - if (cl != null && cl != this) + if (cl != null && ! cl.isAncestorOf(this)) sm.checkPermission(new RuntimePermission("getClassLoader")); - */ } return parent; } @@ -996,4 +994,20 @@ public abstract class ClassLoader packageAssertionStatus = new HashMap(); classAssertionStatus = new HashMap(); } + + /** + * Return true if this loader is either the specified class loader + * or an ancestor thereof. + * @param loader the class loader to check + */ + final boolean isAncestorOf(ClassLoader loader) + { + while (loader != null) + { + if (this == loader) + return true; + loader = loader.parent; + } + return false; + } } diff --git a/libjava/java/lang/InheritableThreadLocal.java b/libjava/java/lang/InheritableThreadLocal.java index 31b64f54798..5dfbe9a6230 100644 --- a/libjava/java/lang/InheritableThreadLocal.java +++ b/libjava/java/lang/InheritableThreadLocal.java @@ -1,5 +1,5 @@ /* InheritableThreadLocal -- a ThreadLocal which inherits values across threads - Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,9 +37,11 @@ exception statement from your version. */ package java.lang; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.ArrayList; +import java.util.Map; import java.util.WeakHashMap; /** @@ -67,7 +69,8 @@ public class InheritableThreadLocal extends ThreadLocal * List can be collected, too. Maps to a list in case the user overrides * equals. */ - private static final WeakHashMap threadMap = new WeakHashMap(); + private static final Map threadMap + = Collections.synchronizedMap(new WeakHashMap()); /** * Creates a new InheritableThreadLocal that has no values associated @@ -77,7 +80,7 @@ public class InheritableThreadLocal extends ThreadLocal { Thread currentThread = Thread.currentThread(); // Note that we don't have to synchronize, as only this thread will - // ever modify the returned heritage. + // ever modify the returned heritage and threadMap is a synchronizedMap. List heritage = (List) threadMap.get(currentThread); if (heritage == null) { @@ -114,7 +117,7 @@ public class InheritableThreadLocal extends ThreadLocal // The currentThread is the parent of the new thread. Thread parentThread = Thread.currentThread(); // Note that we don't have to synchronize, as only this thread will - // ever modify the returned heritage. + // ever modify the returned heritage and threadMap is a synchronizedMap. ArrayList heritage = (ArrayList) threadMap.get(parentThread); if (heritage != null) { diff --git a/libjava/java/lang/Math.java b/libjava/java/lang/Math.java index 0d0930e8bf6..cb5f70b1cfb 100644 --- a/libjava/java/lang/Math.java +++ b/libjava/java/lang/Math.java @@ -1,5 +1,5 @@ /* java.lang.Math -- common mathematical functions, native allowed - Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -521,7 +521,7 @@ public final class Math * double to <code>x / y</code> (ties go to the even n); for a zero * remainder, the sign is that of <code>x</code>. If either argument is NaN, * the first argument is infinite, or the second argument is zero, the result - * is NaN; if x is finite but y is infinte, the result is x. This is + * is NaN; if x is finite but y is infinite, the result is x. This is * accurate within the limits of doubles. * * @param x the dividend (the top half) diff --git a/libjava/java/lang/Runtime.java b/libjava/java/lang/Runtime.java index 932600b5f8f..5c6037ed8a7 100644 --- a/libjava/java/lang/Runtime.java +++ b/libjava/java/lang/Runtime.java @@ -1,5 +1,5 @@ /* Runtime.java -- access to the VM process - Copyright (C) 1998, 2002 Free Software Foundation + Copyright (C) 1998, 2002, 2003 Free Software Foundation This file is part of GNU Classpath. @@ -65,7 +65,7 @@ public class Runtime /** * The current security manager. This is located here instead of in - * Runtime, to avoid security problems, as well as bootstrap issues. + * System, to avoid security problems, as well as bootstrap issues. * Make sure to access it in a thread-safe manner; it is package visible * to avoid overhead in java.lang. */ diff --git a/libjava/java/lang/StrictMath.java b/libjava/java/lang/StrictMath.java index b47d89ca040..bacc291faa5 100644 --- a/libjava/java/lang/StrictMath.java +++ b/libjava/java/lang/StrictMath.java @@ -1,5 +1,5 @@ /* java.lang.StrictMath -- common mathematical functions, strict Java - Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -1053,7 +1053,7 @@ public final strictfp class StrictMath * double to <code>x / y</code> (ties go to the even n); for a zero * remainder, the sign is that of <code>x</code>. If either argument is NaN, * the first argument is infinite, or the second argument is zero, the result - * is NaN; if x is finite but y is infinte, the result is x. + * is NaN; if x is finite but y is infinite, the result is x. * * @param x the dividend (the top half) * @param y the divisor (the bottom half) diff --git a/libjava/java/lang/String.java b/libjava/java/lang/String.java index fe00b9100cc..6844405e34c 100644 --- a/libjava/java/lang/String.java +++ b/libjava/java/lang/String.java @@ -419,7 +419,7 @@ public final class String implements Serializable, Comparable, CharSequence { // No need to synchronize or mark the buffer, since we know it is // only used once. - init (buffer.value, 0, buffer.count, true); + init (buffer); } /** @@ -1253,5 +1253,6 @@ public final class String implements Serializable, Comparable, CharSequence 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 native void init(gnu.gcj.runtime.StringBuffer buffer); private static native void rehash(); } diff --git a/libjava/java/lang/StringBuffer.java b/libjava/java/lang/StringBuffer.java index fac7892524e..a7c2590f39a 100644 --- a/libjava/java/lang/StringBuffer.java +++ b/libjava/java/lang/StringBuffer.java @@ -564,8 +564,9 @@ public final class StringBuffer implements Serializable, CharSequence throw new StringIndexOutOfBoundsException(); if (len == 0) return ""; - // Share the char[] unless 3/4 empty. - shared = (len << 2) >= value.length; + // Share unless substring is smaller than 1/4 of the buffer. + if ((len << 2) >= value.length) + shared = true; // Package constructor avoids an array copy. return new String(value, beginIndex, len, shared); } diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java index 32f7d174580..64498b23ba4 100644 --- a/libjava/java/lang/Thread.java +++ b/libjava/java/lang/Thread.java @@ -614,11 +614,6 @@ public class Thread implements Runnable public Thread (ThreadGroup g, Runnable r, String n) { this (currentThread (), g, r, n); - - // The Class Libraries book says ``threadName cannot be null''. I - // take this to mean NullPointerException. - if (n == null) - throw new NullPointerException (); } /** @@ -645,15 +640,15 @@ public class Thread implements Runnable { // Just ignore stackSize for now. this (currentThread (), g, r, n); + } + private Thread (Thread current, ThreadGroup g, Runnable r, String n) + { // The Class Libraries book says ``threadName cannot be null''. I // take this to mean NullPointerException. if (n == null) throw new NullPointerException (); - } - - private Thread (Thread current, ThreadGroup g, Runnable r, String n) - { + if (g == null) { // If CURRENT is null, then we are bootstrapping the first thread. diff --git a/libjava/java/lang/ThreadGroup.java b/libjava/java/lang/ThreadGroup.java index 80f62b6a7a7..b79c136dffe 100644 --- a/libjava/java/lang/ThreadGroup.java +++ b/libjava/java/lang/ThreadGroup.java @@ -718,6 +718,7 @@ public class ThreadGroup if (groups == null) return; threads.remove(t); + t.group = null; // Daemon groups are automatically destroyed when all their threads die. if (daemon_flag && groups.size() == 0 && threads.size() == 0) { diff --git a/libjava/java/lang/ThreadLocal.java b/libjava/java/lang/ThreadLocal.java index b5877f51b6a..972565949a8 100644 --- a/libjava/java/lang/ThreadLocal.java +++ b/libjava/java/lang/ThreadLocal.java @@ -1,5 +1,5 @@ /* ThreadLocal -- a variable with a unique value per thread - Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,7 @@ exception statement from your version. */ package java.lang; +import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; @@ -101,7 +102,7 @@ public class ThreadLocal * <code>set(Thread, Object)</code> and <code>get(Thread)</code> methods * access it. Package visible for use by InheritableThreadLocal. */ - final Map valueMap = new WeakHashMap(); + final Map valueMap = Collections.synchronizedMap(new WeakHashMap()); /** * Creates a ThreadLocal object without associating any value to it yet. @@ -135,7 +136,7 @@ public class ThreadLocal { Thread currentThread = Thread.currentThread(); // Note that we don't have to synchronize, as only this thread will - // ever modify the returned value. + // ever modify the returned value and valueMap is a synchronizedMap. Object value = valueMap.get(currentThread); if (value == null) { @@ -156,7 +157,7 @@ public class ThreadLocal public void set(Object value) { // Note that we don't have to synchronize, as only this thread will - // ever modify the returned value. + // ever modify the returned value and valueMap is a synchronizedMap. valueMap.put(Thread.currentThread(), value == null ? NULL : value); } } diff --git a/libjava/java/lang/Win32Process.java b/libjava/java/lang/Win32Process.java index b1c7e027379..7a5872705b8 100644 --- a/libjava/java/lang/Win32Process.java +++ b/libjava/java/lang/Win32Process.java @@ -67,6 +67,14 @@ final class ConcreteProcess extends Process File dir) throws IOException { + for (int i = 0; i < progarray.length; i++) + { + String s = progarray[i]; + + if ( (s.indexOf (' ') >= 0) || (s.indexOf ('\t') >= 0)) + progarray[i] = "\"" + s + "\""; + } + startProcess (progarray, envp, dir); } diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 0db8228d63b..4b0858225df 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -101,7 +101,7 @@ java::lang::Class::forName (jstring className) { klass = t->classAt (i); } - loader = klass->getClassLoader(); + loader = klass->getClassLoaderInternal(); } catch (::java::lang::ArrayIndexOutOfBoundsException *e) { @@ -113,13 +113,31 @@ java::lang::Class::forName (jstring className) java::lang::ClassLoader * java::lang::Class::getClassLoader (void) { -#if 0 - // FIXME: the checks we need to do are more complex. See the spec. - // Currently we can't implement them. java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); if (s != NULL) - s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); -#endif + { + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + ClassLoader *caller_loader = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + caller_loader = caller->getClassLoaderInternal(); + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + + // If the caller has a non-null class loader, and that loader + // is not this class' loader or an ancestor thereof, then do a + // security check. + if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader)) + s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); + } // The spec requires us to return `null' for primitive classes. In // other cases we have the option of returning `null' for classes @@ -136,13 +154,14 @@ java::lang::Class::getClassLoader (void) java::lang::reflect::Constructor * java::lang::Class::getConstructor (JArray<jclass> *param_types) { + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { @@ -163,7 +182,7 @@ java::lang::Class::getConstructor (JArray<jclass> *param_types) JArray<java::lang::reflect::Constructor *> * java::lang::Class::_getConstructors (jboolean declared) { - // FIXME: this method needs access checks. + memberAccessCheck(java::lang::reflect::Member::PUBLIC); int numConstructors = 0; int max = isPrimitive () ? 0 : method_count; @@ -206,13 +225,14 @@ java::lang::Class::_getConstructors (jboolean declared) java::lang::reflect::Constructor * java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types) { + memberAccessCheck(java::lang::reflect::Member::DECLARED); + jstring partial_sig = getSignature (param_types, true); jint hash = partial_sig->hashCode (); int i = isPrimitive () ? 0 : method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (methods[i].name, init_name) && _Jv_equal (methods[i].signature, partial_sig, hash)) { @@ -256,9 +276,7 @@ java::lang::Class::getField (jstring name, jint hash) java::lang::reflect::Field * java::lang::Class::getDeclaredField (jstring name) { - java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); - if (s != NULL) - s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED); + memberAccessCheck(java::lang::reflect::Member::DECLARED); int hash = name->hashCode(); for (int i = 0; i < field_count; i++) { @@ -277,9 +295,7 @@ java::lang::Class::getDeclaredField (jstring name) JArray<java::lang::reflect::Field *> * java::lang::Class::getDeclaredFields (void) { - java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); - if (s != NULL) - s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED); + memberAccessCheck(java::lang::reflect::Member::DECLARED); JArray<java::lang::reflect::Field *> *result = (JArray<java::lang::reflect::Field *> *) JvNewObjectArray (field_count, &java::lang::reflect::Field::class$, NULL); @@ -361,6 +377,8 @@ java::lang::Class::_getDeclaredMethod (jstring name, JArray<java::lang::reflect::Method *> * java::lang::Class::getDeclaredMethods (void) { + memberAccessCheck(java::lang::reflect::Member::DECLARED); + int numMethods = 0; int max = isPrimitive () ? 0 : method_count; int i; @@ -424,7 +442,7 @@ java::lang::Class::getClasses (void) JArray<jclass> * java::lang::Class::getDeclaredClasses (void) { - checkMemberAccess (java::lang::reflect::Member::DECLARED); + memberAccessCheck (java::lang::reflect::Member::DECLARED); // Until we have inner classes, it always makes sense to return an // empty array. JArray<jclass> *result @@ -482,9 +500,7 @@ java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result, JArray<java::lang::reflect::Field *> * java::lang::Class::getFields (void) { - // FIXME: security checking. - - using namespace java::lang::reflect; + memberAccessCheck(java::lang::reflect::Member::PUBLIC); int count = _getFields (NULL, 0); @@ -518,7 +534,6 @@ java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types) int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) { - // FIXME: access checks. if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len) && (klass->methods[i].accflags @@ -642,7 +657,7 @@ java::lang::Class::getMethods (void) { using namespace java::lang::reflect; - // FIXME: security checks. + memberAccessCheck(Member::PUBLIC); // This will overestimate the size we need. jint count = _getMethods (NULL, 0); @@ -696,12 +711,7 @@ java::lang::Class::isInstance (jobject obj) jobject java::lang::Class::newInstance (void) { - // FIXME: do accessibility checks here. There currently doesn't - // seem to be any way to do these. - // FIXME: we special-case one check here just to pass a Plum Hall - // test. Once access checking is implemented, remove this. - if (this == &java::lang::Class::class$) - throw new java::lang::IllegalAccessException; + memberAccessCheck(java::lang::reflect::Member::PUBLIC); if (isPrimitive () || isInterface () @@ -1744,7 +1754,26 @@ _Jv_MakeVTable (jclass klass) { for (int i = 0; i < klass->vtable_method_count; ++i) if (! flags[i]) - // FIXME: messsage. - throw new java::lang::AbstractMethodError (); + { + using namespace java::lang; + while (klass != NULL) + { + for (int j = 0; j < klass->method_count; ++j) + { + if (klass->methods[i].index == i) + { + StringBuffer *buf = new StringBuffer (); + buf->append (_Jv_NewStringUtf8Const (klass->methods[i].name)); + buf->append ((jchar) ' '); + buf->append (_Jv_NewStringUtf8Const (klass->methods[i].signature)); + throw new AbstractMethodError (buf->toString ()); + } + } + klass = klass->getSuperclass (); + } + // Couldn't find the name, which is weird. + // But we still must throw the error. + throw new AbstractMethodError (); + } } } diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 69f78f64491..b86da32f8f3 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -217,7 +217,8 @@ java::lang::Runtime::_load (jstring path, jboolean do_search) if (h == NULL) { const char *msg = lt_dlerror (); - jstring str = path->concat (JvNewStringLatin1 (": ")); + jstring str = JvNewStringLatin1 (lib_name); + str = str->concat (JvNewStringLatin1 (": ")); str = str->concat (JvNewStringLatin1 (msg)); throw new UnsatisfiedLinkError (str); } @@ -563,7 +564,7 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) if (_Jv_Jar_Class_Path) newprops->put(JvNewStringLatin1 ("java.class.path"), - JvNewStringLatin1 (_Jv_Jar_Class_Path)); + JvNewStringLatin1 (_Jv_Jar_Class_Path)); else { // FIXME: find libgcj.zip and append its path? @@ -585,6 +586,9 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) sb->toString ()); } + // The path to libgcj's boot classes + SET ("sun.boot.class.path", BOOT_CLASS_PATH); + // The name used to invoke this process (argv[0] in C). SET ("gnu.gcj.progname", _Jv_GetSafeArg (0)); diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc index 98309cfe62e..6fd928478b5 100644 --- a/libjava/java/lang/natString.cc +++ b/libjava/java/lang/natString.cc @@ -28,6 +28,7 @@ details. */ #include <java/util/Locale.h> #include <gnu/gcj/convert/UnicodeToBytes.h> #include <gnu/gcj/convert/BytesToUnicode.h> +#include <gnu/gcj/runtime/StringBuffer.h> #include <jvm.h> static void unintern (jobject); @@ -525,6 +526,12 @@ java::lang::String::init (jbyteArray bytes, jint offset, jint count, this->count = outpos; } +void +java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer) +{ + init (buffer->value, 0, buffer->count, true); +} + jboolean java::lang::String::equals(jobject anObject) { diff --git a/libjava/java/lang/natSystem.cc b/libjava/java/lang/natSystem.cc index e2d42324386..4a08bb138bf 100644 --- a/libjava/java/lang/natSystem.cc +++ b/libjava/java/lang/natSystem.cc @@ -66,8 +66,10 @@ java::lang::System::arraycopy (jobject src, jint src_offset, __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) + || (unsigned jint) src_offset > (unsigned jint) src_a->length + || (unsigned jint) (src_offset + count) > (unsigned jint) src_a->length + || (unsigned jint) dst_offset > (unsigned jint) dst_a->length + || (unsigned jint) (dst_offset + count) > (unsigned jint) dst_a->length) throw new ArrayIndexOutOfBoundsException; // Do-nothing cases. diff --git a/libjava/java/lang/natWin32Process.cc b/libjava/java/lang/natWin32Process.cc index ff7ddb5f50a..49fa853a398 100644 --- a/libjava/java/lang/natWin32Process.cc +++ b/libjava/java/lang/natWin32Process.cc @@ -9,18 +9,11 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ #include <config.h> - -#include <stdio.h> - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> +#include <platform.h> // Conflicts with the definition in "java/lang/reflect/Modifier.h" #undef STRICT -#include <gcj/cni.h> -#include <jvm.h> - #include <java/lang/ConcreteProcess.h> #include <java/lang/IllegalThreadStateException.h> #include <java/lang/InterruptedException.h> @@ -53,6 +46,11 @@ java::lang::ConcreteProcess::cleanup (void) errorStream->close (); errorStream = NULL; } + if (procHandle) + { + CloseHandle((HANDLE) procHandle); + procHandle = (jint) INVALID_HANDLE_VALUE; + } } void @@ -99,8 +97,28 @@ java::lang::ConcreteProcess::waitFor (void) { DWORD exitStatus = 0UL; - // FIXME: The wait should be interruptible. - WaitForSingleObject ((HANDLE) procHandle, INFINITE); + // Set up our waitable objects array + // - 0: the handle to the process we just launched + // - 1: our thread's interrupt event + HANDLE arh[2]; + arh[0] = (HANDLE) procHandle; + arh[1] = _Jv_Win32GetInterruptEvent (); + DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE); + + // Use the returned value from WaitForMultipleObjects + // instead of our thread's interrupt_flag to test for + // thread interruption. See the comment for + // _Jv_Win32GetInterruptEvent(). + bool bInterrupted = rval == (WAIT_OBJECT_0 + 1); + + if (bInterrupted) + { + // Querying this forces a reset our thread's interrupt flag. + Thread::interrupted(); + + cleanup (); + throw new InterruptedException (); + } GetExitCodeProcess ((HANDLE) procHandle, &exitStatus); exitCode = exitStatus; @@ -111,16 +129,6 @@ java::lang::ConcreteProcess::waitFor (void) return exitCode; } -static char * -new_string (jstring string) -{ - jsize s = _Jv_GetStringUTFLength (string); - char *buf = (char *) _Jv_Malloc (s + 1); - _Jv_GetStringUTFRegion (string, 0, s, buf); - buf[s] = '\0'; - return buf; -} - void java::lang::ConcreteProcess::startProcess (jstringArray progarray, jstringArray envp, @@ -136,7 +144,7 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, int cmdLineLen = 0; for (int i = 0; i < progarray->length; ++i) - cmdLineLen += (_Jv_GetStringUTFLength (elts[i]) + 3); + cmdLineLen += (_Jv_GetStringUTFLength (elts[i]) + 1); char *cmdLine = (char *) _Jv_Malloc (cmdLineLen + 1); char *cmdLineCurPos = cmdLine; @@ -145,11 +153,9 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, { if (i > 0) *cmdLineCurPos++ = ' '; - *cmdLineCurPos++ = '\"'; jsize s = _Jv_GetStringUTFLength (elts[i]); _Jv_GetStringUTFRegion (elts[i], 0, s, cmdLineCurPos); cmdLineCurPos += s; - *cmdLineCurPos++ = '\"'; } *cmdLineCurPos = '\0'; @@ -179,9 +185,7 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, } // Get the working directory path, if specified. - char *wdir = NULL; - if (dir != NULL) - wdir = new_string (dir->getPath ()); + JV_TEMP_UTF_STRING (wdir, dir ? dir->getPath () : 0); errorStream = NULL; inputStream = NULL; @@ -206,29 +210,25 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, sAttrs.lpSecurityDescriptor = NULL; - char tmpBuff[64]; if (CreatePipe (&cldStdInRd, &cldStdInWr, &sAttrs, 0) == 0) { - sprintf (tmpBuff, - "Error creating stdin pipe (Win32 Error Code: %lu)", - GetLastError ()); - throw new IOException (JvNewStringLatin1 (tmpBuff)); + DWORD dwErrorCode = GetLastError (); + throw new IOException (_Jv_WinStrError ("Error creating stdin pipe", + dwErrorCode)); } if (CreatePipe (&cldStdOutRd, &cldStdOutWr, &sAttrs, 0) == 0) { - sprintf (tmpBuff, - "Error creating stdout pipe (Win32 Error Code: %lu)", - GetLastError ()); - throw new IOException (JvNewStringLatin1 (tmpBuff)); + DWORD dwErrorCode = GetLastError (); + throw new IOException (_Jv_WinStrError ("Error creating stdout pipe", + dwErrorCode)); } if (CreatePipe (&cldStdErrRd, &cldStdErrWr, &sAttrs, 0) == 0) { - sprintf (tmpBuff, - "Error creating stderr pipe (Win32 Error Code: %lu)", - GetLastError ()); - throw new IOException (JvNewStringLatin1 (tmpBuff)); + DWORD dwErrorCode = GetLastError (); + throw new IOException (_Jv_WinStrError ("Error creating stderr pipe", + dwErrorCode)); } outputStream = new FileOutputStream @@ -265,10 +265,9 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, &si, &pi) == 0) { - sprintf (tmpBuff, - "Error creating child process (Win32 Error Code: %lu)", - GetLastError ()); - throw new IOException (JvNewStringLatin1 (tmpBuff)); + DWORD dwErrorCode = GetLastError (); + throw new IOException ( + _Jv_WinStrError ("Error creating child process", dwErrorCode)); } procHandle = (jint ) pi.hProcess; @@ -281,8 +280,6 @@ java::lang::ConcreteProcess::startProcess (jstringArray progarray, _Jv_Free (cmdLine); if (env != NULL) _Jv_Free (env); - if (wdir != NULL) - _Jv_Free (wdir); } catch (java::lang::Throwable *thrown) { diff --git a/libjava/java/lang/ref/Reference.java b/libjava/java/lang/ref/Reference.java index b02a4ed5775..a6385a81617 100644 --- a/libjava/java/lang/ref/Reference.java +++ b/libjava/java/lang/ref/Reference.java @@ -1,5 +1,5 @@ /* java.lang.ref.Reference - Copyright (C) 1999, 2002 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,7 +40,7 @@ package java.lang.ref; /** * This is the base class of all references. A reference allows - * refering to an object without preventing the garbage collection to + * refering to an object without preventing the garbage collector to * collect it. The only way to get the referred object is via the * <code>get()</code>-method. This method will return * <code>null</code> if the object was collected. <br> @@ -52,11 +52,11 @@ package java.lang.ref; * There are currently three types of references: soft reference, * weak reference and phantom reference. <br> * - * Soft references will be cleared if the garbage collection is told + * Soft references will be cleared if the garbage collector is told * to free some memory and there are no unreferenced or weakly referenced * objects. It is useful for caches. <br> * - * Weak references will be cleared as soon as the garbage collection + * Weak references will be cleared as soon as the garbage collector * determines that the refered object is only weakly reachable. They * are useful as keys in hashtables (see <code>WeakHashtable</code>) as * you get notified when nobody has the key anymore. @@ -74,7 +74,7 @@ public abstract class Reference { /** * The underlying object. This field is handled in a special way by - * the garbage collection. + * the garbage collector. * GCJ LOCAL: * This is a RawData because it must be disguised from the GC. * END GCJ LOCAL @@ -83,15 +83,25 @@ public abstract class Reference /** * This is like REFERENT but is not scanned by the GC. We keep a - * copy around so that we can see when clear() has been called. + * copy around so that we can clean up our internal data structure + * even after clear() is called. * GCJ LOCAL: - * This field doesn't exist in Classpath; we use it to detect - * clearing. + * This field doesn't exist in Classpath. * END GCJ LOCAL */ gnu.gcj.RawData copy; /** + * Set to true if {@link #clear()} is called. + * GCJ LOCAL: + * This field doesn't exist in Classpath. It is used internally in + * natReference.cc, which enqueues the reference unless it is true + * (has been cleared). + * END GCJ LOCAL + */ + boolean cleared = false; + + /** * The queue this reference is registered on. This is null, if this * wasn't registered to any queue or reference was already enqueued. */ @@ -107,7 +117,7 @@ public abstract class Reference Reference nextOnQueue; /** - * This lock should be taken by the garbage collection, before + * This lock should be taken by the garbage collector, before * determining reachability. It will prevent the get()-method to * return the reference so that reachability doesn't change. */ @@ -152,7 +162,7 @@ public abstract class Reference */ public Object get() { - synchronized(lock) + synchronized (lock) { return referent; } @@ -161,13 +171,17 @@ public abstract class Reference /** * Clears the reference, so that it doesn't refer to its object * anymore. For soft and weak references this is called by the - * garbage collection. For phantom references you should call + * garbage collector. For phantom references you should call * this when enqueuing the reference. */ public void clear() { - referent = null; - copy = null; + // Must synchronize so changes are visible in finalizer thread. + synchronized (lock) + { + referent = null; + cleared = true; + } } /** @@ -181,7 +195,7 @@ public abstract class Reference /** * Enqueue an object on a reference queue. This is normally executed - * by the garbage collection. + * by the garbage collector. */ public boolean enqueue() { diff --git a/libjava/java/lang/ref/natReference.cc b/libjava/java/lang/ref/natReference.cc index 64262f900cb..551bd0809d1 100644 --- a/libjava/java/lang/ref/natReference.cc +++ b/libjava/java/lang/ref/natReference.cc @@ -1,6 +1,6 @@ // natReference.cc - Native code for References -/* Copyright (C) 2001, 2002 Free Software Foundation +/* Copyright (C) 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -67,6 +67,8 @@ static int hash_count = 0; // Number of slots total in HASH. Must be power of 2. static int hash_size = 0; +#define DELETED_REFERENCE ((jobject) -1) + static object_list * find_slot (jobject key) { @@ -89,7 +91,10 @@ find_slot (jobject key) return &hash[deleted_index]; } else if (ptr->weight == DELETED) - deleted_index = index; + { + deleted_index = index; + JvAssert (ptr->reference == DELETED_REFERENCE); + } index = (index + step) & (hash_size - 1); JvAssert (index != start_index); } @@ -132,6 +137,11 @@ remove_from_hash (jobject obj) java::lang::ref::Reference *ref = reinterpret_cast<java::lang::ref::Reference *> (obj); object_list *head = find_slot (ref->copy); + + // We might have found a new slot. We can just ignore that here. + if (head->reference != ref->copy) + return; + object_list **link = &head->next; head = head->next; @@ -168,7 +178,7 @@ add_to_hash (java::lang::ref::Reference *the_reference) // Use `copy' here because the `referent' field has been cleared. jobject referent = the_reference->copy; object_list *item = find_slot (referent); - if (item->reference == NULL) + if (item->reference == NULL || item->reference == DELETED_REFERENCE) { // New item, so make an entry for the finalizer. item->reference = referent; @@ -217,6 +227,7 @@ finalize_referred_to_object (jobject obj) // run, all the object's references have been processed, and the // object is unreachable. There is, at long last, no way to // resurrect it. + list->reference = DELETED_REFERENCE; list->weight = DELETED; --hash_count; return; @@ -247,9 +258,7 @@ finalize_referred_to_object (jobject obj) { java::lang::ref::Reference *ref = reinterpret_cast<java::lang::ref::Reference *> (head->reference); - // If the copy is already NULL then the user must have - // called Reference.clear(). - if (ref->copy != NULL) + if (! ref->cleared) ref->enqueue (); object_list *next = head->next; diff --git a/libjava/java/lang/reflect/Constructor.java b/libjava/java/lang/reflect/Constructor.java index 4a30e2ae394..53db35a6975 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, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -11,88 +11,196 @@ details. */ package java.lang.reflect; /** - * @author Tom Tromey <tromey@cygnus.com> - * @date December 12, 1998 + * The Constructor class represents a constructor of a class. It also allows + * dynamic creation of an object, via reflection. Invocation on Constructor + * objects knows how to do widening conversions, but throws + * {@link IllegalArgumentException} if a narrowing conversion would be + * necessary. You can query for information on this Constructor regardless + * of location, but construction access may be limited by Java language + * access controls. If you can't do it in the compiler, you can't normally + * do it here either.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> + * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getConstructor(Object[]) + * @see java.lang.Class#getDeclaredConstructor(Object[]) + * @see java.lang.Class#getConstructors() + * @see java.lang.Class#getDeclaredConstructors() + * @since 1.1 + * @status updated to 1.4 */ -/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 - * "The Java Language Specification", ISBN 0-201-63451-1 - * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. - * Status: Incomplete: needs a private constructor, and - * newInstance() needs to be written. - */ - public final class Constructor extends AccessibleObject implements Member { - public boolean equals (Object obj) - { - if (! (obj instanceof Constructor)) - return false; - Constructor c = (Constructor) obj; - return declaringClass == c.declaringClass && offset == c.offset; - } + /** + * This class is uninstantiable except from native code. + */ + private Constructor () + { + } + /** + * Gets the class that declared this constructor. + * @return the class that declared this member + */ public Class getDeclaringClass () - { - return declaringClass; - } - - public Class[] getExceptionTypes () - { - if (exception_types == null) - getType(); - return (Class[]) exception_types.clone(); - } - - public native int getModifiers (); + { + return declaringClass; + } + /** + * Gets the name of this constructor (the non-qualified name of the class + * it was declared in). + * @return the name of this constructor + */ public String getName () { return declaringClass.getName(); } + /** + * Gets the modifiers this constructor uses. Use the <code>Modifier</code> + * class to interpret the values. A constructor can only have a subset of the + * following modifiers: public, private, protected. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public native int getModifiers (); + + /** + * Get the parameter list for this constructor, in declaration order. If the + * constructor takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the constructor's parameters + */ public Class[] getParameterTypes () - { - if (parameter_types == null) - getType (); - return (Class[]) parameter_types.clone(); - } + { + if (parameter_types == null) + getType (); + return (Class[]) parameter_types.clone(); + } + /** + * Get the exception types this constructor says it throws, in no particular + * order. If the constructor has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the constructor's throws clause + */ + public Class[] getExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class[]) exception_types.clone(); + } + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Constructors are semantically equivalent if they have the same + * declaring class and the same parameter list. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Constructor)) + return false; + Constructor c = (Constructor) obj; + return declaringClass == c.declaringClass && offset == c.offset; + } + + /** + * Get the hash code for the Constructor. + * + * @return the hash code for the object + */ public int hashCode () - { - // FIXME. - return getName().hashCode() + declaringClass.getName().hashCode(); - } + { + // FIXME. + return getName().hashCode() + declaringClass.getName().hashCode(); + } - // Update cached values from method descriptor in class. - private native void getType (); + /** + * Get a String representation of the Constructor. A Constructor's String + * representation is "<modifier> <classname>(<paramtypes>) + * throws <exceptions>", where everything after ')' is omitted if + * there are no exceptions.<br> Example: + * <code>public java.io.FileInputStream(java.lang.Runnable) + * throws java.io.FileNotFoundException</code> + * + * @return the String representation of the Constructor + */ + public String toString () + { + if (parameter_types == null) + getType (); + StringBuffer b = new StringBuffer (); + Modifier.toString(getModifiers(), b); + b.append(" "); + Method.appendClassName (b, declaringClass); + b.append("("); + for (int i = 0; i < parameter_types.length; ++i) + { + Method.appendClassName (b, parameter_types[i]); + if (i < parameter_types.length - 1) + b.append(","); + } + b.append(")"); + return b.toString(); + } + /** + * Create a new instance by invoking the constructor. Arguments are + * automatically unwrapped and widened, if needed.<p> + * + * If this class is abstract, you will get an + * <code>InstantiationException</code>. If the constructor takes 0 + * arguments, you may use null or a 0-length array for <code>args</code>.<p> + * + * If this Constructor enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not create this object in similar compiled code. If the class + * is uninitialized, you trigger class initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Then, the constructor is invoked. If it completes normally, the return + * value will be the new object. If it completes abruptly, the exception is + * wrapped in an <code>InvocationTargetException</code>. + * + * @param args the arguments to the constructor + * @return the newly created object + * @throws IllegalAccessException if the constructor could not normally be + * called by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * or if the arguments types are wrong even with a widening + * conversion + * @throws InstantiationException if the class is abstract + * @throws InvocationTargetException if the constructor throws an exception + * @throws ExceptionInInitializerError if construction triggered class + * initialization, which then failed + */ public native Object newInstance (Object[] args) throws InstantiationException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException; + IllegalArgumentException, InvocationTargetException; - public String toString () - { - if (parameter_types == null) - getType (); - StringBuffer b = new StringBuffer (); - Modifier.toString(getModifiers(), b); - b.append(" "); - Method.appendClassName (b, declaringClass); - b.append("("); - for (int i = 0; i < parameter_types.length; ++i) - { - Method.appendClassName (b, parameter_types[i]); - if (i < parameter_types.length - 1) - b.append(","); - } - b.append(")"); - return b.toString(); - } - - // Can't create these. - private Constructor () - { - } + // Update cached values from method descriptor in class. + private native void getType (); // Declaring class. private Class declaringClass; diff --git a/libjava/java/lang/reflect/Field.java b/libjava/java/lang/reflect/Field.java index 6410a7f770d..b54a103d9bc 100644 --- a/libjava/java/lang/reflect/Field.java +++ b/libjava/java/lang/reflect/Field.java @@ -1,4 +1,4 @@ -/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -12,15 +12,6 @@ package java.lang.reflect; * @author Per Bothner <bothner@cygnus.com> * @date September 1998; February 1999. */ -/* Status: Mostly implemented. - * However, access checks are not implemented. See natField.cc for - * _Jv_CheckFieldAccessibility as well as the missing getCaller. - * Note that the idea is to have to compiler convert calls to - * setXXX(...) and getXXX(...) to setXXX(CALLER, ...) and getXXX(CALLER, ...), - * where CALLER is reference to the class that contains the calls to - * setXXX or getXXX. This is easy for the compiler, and replaces - * expensive stack and table searching with a constant. - */ public final class Field extends AccessibleObject implements Member { @@ -39,12 +30,12 @@ public final class Field extends AccessibleObject implements Member } public boolean equals (Object fld) - { - if (! (fld instanceof Field)) - return false; - Field f = (Field) fld; - return declaringClass == f.declaringClass && offset == f.offset; - } + { + if (! (fld instanceof Field)) + return false; + Field f = (Field) fld; + return declaringClass == f.declaringClass && offset == f.offset; + } public Class getDeclaringClass () { @@ -62,11 +53,6 @@ public final class Field extends AccessibleObject implements Member return (declaringClass.hashCode() ^ offset); } - // The idea is that the compiler will magically translate - // fld.getShort(obj) to fld.getShort(THISCLASS, obj). - // This makes checking assessiblity more efficient, - // since we don't have to do any stack-walking. - public boolean getBoolean (Object obj) throws IllegalArgumentException, IllegalAccessException { diff --git a/libjava/java/lang/reflect/Method.java b/libjava/java/lang/reflect/Method.java index 7bd0a312511..3e0507fcaa1 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, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -13,43 +13,92 @@ package java.lang.reflect; import gnu.gcj.RawData; /** - * @author Tom Tromey <tromey@cygnus.com> - * @date December 12, 1998 + * The Method class represents a member method of a class. It also allows + * dynamic invocation, via reflection. This works for both static and + * instance methods. Invocation on Method objects knows how to do + * widening conversions, but throws {@link IllegalArgumentException} if + * a narrowing conversion would be necessary. You can query for information + * on this Method regardless of location, but invocation access may be limited + * by Java language access controls. If you can't do it in the compiler, you + * can't normally do it here either.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> + * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getMethod(String,Object[]) + * @see java.lang.Class#getDeclaredMethod(String,Object[]) + * @see java.lang.Class#getMethods() + * @see java.lang.Class#getDeclaredMethods() + * @since 1.1 + * @status updated to 1.4 */ -/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 - * "The Java Language Specification", ISBN 0-201-63451-1 - * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. - * Status: Complete, but not correct: access checks aren't done. - */ - public final class Method extends AccessibleObject implements Member { - public boolean equals (Object obj) + /** + * This class is uninstantiable. + */ + private Method () { - if (! (obj instanceof Method)) - return false; - Method m = (Method) obj; - return declaringClass == m.declaringClass && offset == m.offset; } + /** + * Gets the class that declared this method, or the class where this method + * is a non-inherited member. + * @return the class that declared this member + */ public Class getDeclaringClass () { return declaringClass; } - public Class[] getExceptionTypes () - { - if (exception_types == null) - getType(); - return (Class[]) exception_types.clone(); - } + /** + * Gets the name of this method. + * @return the name of this method + */ + public native String getName (); + /** + * Gets the modifiers this method uses. Use the <code>Modifier</code> + * class to interpret the values. A method can only have a subset of the + * following modifiers: public, private, protected, abstract, static, + * final, synchronized, native, and strictfp. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ public native int getModifiers (); - public native String getName (); - - private native void getType (); + /** + * Gets the return type of this method. + * @return the type of this method + */ + public Class getReturnType () + { + if (return_type == null) + getType(); + return return_type; + } + /** + * Get the parameter list for this method, in declaration order. If the + * method takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the method's parameters + */ public Class[] getParameterTypes () { if (parameter_types == null) @@ -57,43 +106,57 @@ public final class Method extends AccessibleObject implements Member return (Class[]) parameter_types.clone(); } - public Class getReturnType () + /** + * Get the exception types this method says it throws, in no particular + * order. If the method has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the method's throws clause + */ + public Class[] getExceptionTypes () { - if (return_type == null) + if (exception_types == null) getType(); - return return_type; + return (Class[]) exception_types.clone(); } - public int hashCode () + /** + * Compare two objects to see if they are semantically equivalent. + * Two Methods are semantically equivalent if they have the same declaring + * class, name, and parameter list. This ignores different exception + * clauses or return types. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not + */ + public boolean equals (Object obj) { - // FIXME. - return getName().hashCode() + declaringClass.getName().hashCode(); + if (! (obj instanceof Method)) + return false; + Method m = (Method) obj; + return declaringClass == m.declaringClass && offset == m.offset; } - public native Object invoke (Object obj, Object[] args) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException; - - // Append a class name to a string buffer. We try to print the - // fully-qualified name, the way that a Java programmer would expect - // it to be written. Weirdly, Class has no appropriate method for - // this. - static void appendClassName (StringBuffer buf, Class k) + /** + * Get the hash code for the Method. + * + * @return the hash code for the object + */ + public int hashCode () { - if (k.isArray ()) - { - appendClassName (buf, k.getComponentType ()); - buf.append ("[]"); - } - else - { - // This is correct for primitive and reference types. Really - // we'd like `Main$Inner' to be printed as `Main.Inner', I - // think, but that is a pain. - buf.append (k.getName ()); - } + // FIXME. + return getName().hashCode() + declaringClass.getName().hashCode(); } + /** + * Get a String representation of the Method. A Method's String + * representation is "<modifiers> <returntype> + * <methodname>(<paramtypes>) throws <exceptions>", where + * everything after ')' is omitted if there are no exceptions.<br> Example: + * <code>public static int run(java.lang.Runnable,int)</code> + * + * @return the String representation of the Method + */ public String toString () { if (parameter_types == null) @@ -128,8 +191,71 @@ public final class Method extends AccessibleObject implements Member return b.toString(); } - private Method () + /** + * Invoke the method. Arguments are automatically unwrapped and widened, + * and the result is automatically wrapped, if needed.<p> + * + * If the method is static, <code>o</code> will be ignored. Otherwise, + * the method uses dynamic lookup as described in JLS 15.12.4.4. You cannot + * mimic the behavior of nonvirtual lookup (as in super.foo()). This means + * you will get a <code>NullPointerException</code> if <code>o</code> is + * null, and an <code>IllegalArgumentException</code> if it is incompatible + * with the declaring class of the method. If the method takes 0 arguments, + * you may use null or a 0-length array for <code>args</code>.<p> + * + * Next, if this Method enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not acces this method in similar compiled code. If the method + * is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Finally, the method is invoked. If it completes normally, the return value + * will be null for a void method, a wrapped object for a primitive return + * method, or the actual return of an Object method. If it completes + * abruptly, the exception is wrapped in an + * <code>InvocationTargetException</code>. + * + * @param o the object to invoke the method on + * @param args the arguments to the method + * @return the return value of the method, wrapped in the appropriate + * wrapper if it is primitive + * @throws IllegalAccessException if the method could not normally be called + * by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * if the arguments types are wrong even with a widening conversion; + * or if <code>o</code> is not an instance of the class or interface + * declaring this method + * @throws InvocationTargetException if the method throws an exception + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static method triggered + * class initialization, which then failed + */ + public native Object invoke (Object obj, Object[] args) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException; + + private native void getType (); + + // Append a class name to a string buffer. We try to print the + // fully-qualified name, the way that a Java programmer would expect + // it to be written. Weirdly, Class has no appropriate method for + // this. + static void appendClassName (StringBuffer buf, Class k) { + if (k.isArray ()) + { + appendClassName (buf, k.getComponentType ()); + buf.append ("[]"); + } + else + { + // This is correct for primitive and reference types. Really + // we'd like `Main$Inner' to be printed as `Main.Inner', I + // think, but that is a pain. + buf.append (k.getName ()); + } } // Declaring class. diff --git a/libjava/java/lang/reflect/Proxy.java b/libjava/java/lang/reflect/Proxy.java index e327f44664b..1b38a483842 100644 --- a/libjava/java/lang/reflect/Proxy.java +++ b/libjava/java/lang/reflect/Proxy.java @@ -1,5 +1,5 @@ /* Proxy.java -- build a proxy class that implements reflected interfaces - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -733,7 +733,7 @@ public class Proxy implements Serializable * The package this class is in. Possibly null, meaning the unnamed * package. */ - Package pack; + String pack; /** * The interfaces this class implements. Non-null, but possibly empty. @@ -777,6 +777,21 @@ public class Proxy implements Serializable } /** + * Return the name of a package given the name of a class. + * Returns null if no package. We use this in preference to + * using Class.getPackage() to avoid problems with ClassLoaders + * that don't set the package. + */ + static String getPackage(Class k) + { + String name = k.getName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0) + return name.substring(0, idx); + return null; + } + + /** * Verifies that the arguments are legal, and sets up remaining data * This should only be called when a class must be generated, as * it is expensive. @@ -818,8 +833,8 @@ public class Proxy implements Serializable if (! Modifier.isPublic(inter.getModifiers())) if (in_package) { - Package p = inter.getPackage(); - if (data.pack != inter.getPackage()) + String p = getPackage(inter); + if (! data.pack.equals(p)) throw new IllegalArgumentException("non-public interfaces " + "from different " + "packages"); @@ -827,7 +842,7 @@ public class Proxy implements Serializable else { in_package = true; - data.pack = inter.getPackage(); + data.pack = getPackage(inter); } for (int j = i-1; j >= 0; j--) if (data.interfaces[j] == inter) @@ -954,7 +969,7 @@ public class Proxy implements Serializable // access_flags putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC); // this_class - qualName = ((data.pack == null ? "" : data.pack.getName() + '.') + qualName = ((data.pack == null ? "" : data.pack + '.') + "$Proxy" + data.id); putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false))); // super_class diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc index 78751229eab..ce76b9c92d4 100644 --- a/libjava/java/lang/reflect/natArray.cc +++ b/libjava/java/lang/reflect/natArray.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1999, 2000, 2001 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -15,6 +15,7 @@ details. */ #include <jvm.h> #include <gcj/cni.h> #include <java/lang/reflect/Array.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> #include <java/lang/IllegalArgumentException.h> #include <java/lang/Byte.h> #include <java/lang/Short.h> @@ -38,8 +39,8 @@ java::lang::reflect::Array::newInstance (jclass componentType, jint length) return _Jv_NewPrimArray (componentType, length); } else + // FIXME: class loader? return JvNewObjectArray (length, componentType, NULL); - } jobject @@ -52,10 +53,26 @@ java::lang::reflect::Array::newInstance (jclass componentType, jint* dims = elements (dimensions); if (ndims == 1) return newInstance (componentType, dims[0]); + + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + ClassLoader *caller_loader = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + caller_loader = caller->getClassLoaderInternal(); + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jclass arrayType = componentType; - for (int i = 0; i < ndims; i++) // FIXME 2nd arg should - // be "current" loader - arrayType = _Jv_GetArrayClass (arrayType, 0); + for (int i = 0; i < ndims; i++) + arrayType = _Jv_GetArrayClass (arrayType, caller_loader); return _Jv_NewMultiArray (arrayType, ndims, dims); } @@ -343,9 +360,11 @@ java::lang::reflect::Array::setBoolean (jobject array, void java::lang::reflect::Array::set (jobject array, jint index, - jobject value, jclass elType) + jobject value, jclass elType) { - if (! _Jv_IsInstanceOf (value, elType)) + // We don't have to call getElementType here, or check INDEX, + // because it was already done in the Java wrapper. + if (value != NULL && ! _Jv_IsInstanceOf (value, elType)) throw new java::lang::IllegalArgumentException; elements ((jobjectArray) array) [index] = value; } diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc index 7f90b1243e4..466c7544112 100644 --- a/libjava/java/lang/reflect/natConstructor.cc +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -1,6 +1,6 @@ // natConstructor.cc - Native code for Constructor class. -/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -13,6 +13,8 @@ details. */ #include <gcj/cni.h> #include <jvm.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalAccessException.h> #include <java/lang/reflect/Constructor.h> #include <java/lang/reflect/Method.h> #include <java/lang/reflect/InvocationTargetException.h> @@ -46,6 +48,24 @@ java::lang::reflect::Constructor::newInstance (jobjectArray args) if (parameter_types == NULL) getType (); + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + + if (! isAccessible() && ! _Jv_CheckAccess(caller, declaringClass, + declaringClass->getModifiers())) + throw new java::lang::IllegalAccessException; + using namespace java::lang::reflect; if (Modifier::isAbstract (declaringClass->getModifiers())) throw new InstantiationException; diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index 93e27a280ce..b7f12f06e92 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, 2001 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation This file is part of libgcj. @@ -15,6 +15,7 @@ details. */ #include <jvm.h> #include <java/lang/reflect/Field.h> #include <java/lang/reflect/Modifier.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> #include <java/lang/IllegalArgumentException.h> #include <java/lang/IllegalAccessException.h> #include <java/lang/NullPointerException.h> @@ -46,31 +47,37 @@ java::lang::reflect::Field::getType () { jfieldID fld = _Jv_FromReflectedField (this); JvSynchronize sync (declaringClass); - _Jv_ResolveField (fld, declaringClass->getClassLoader ()); + _Jv_ResolveField (fld, declaringClass->getClassLoaderInternal ()); return fld->type; } -static void -_Jv_CheckFieldAccessibility (jfieldID /*fld*/, jclass /*caller*/) -{ -#if 0 - if (caller == NULL) - caller = getCaller(); -#endif -#if 0 - _Jv_ushort flags = fld->getModifiers(); - check accesss; -#endif -} - static void* getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj) { + // FIXME: we know CALLER is NULL here. At one point we planned to + // have the compiler insert the caller as a hidden argument in some + // calls. However, we never implemented that, so we have to find + // the caller by hand instead. + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(7); + try + { + // We want to skip all the frames on the stack from this class. + for (int i = 1; + !caller || caller == &java::lang::reflect::Field::class$; + i++) + caller = t->classAt (i); + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jfieldID fld = _Jv_FromReflectedField (field); _Jv_ushort flags = fld->getModifiers(); - if (! (flags & java::lang::reflect::Modifier::PUBLIC) - && ! field->isAccessible ()) - _Jv_CheckFieldAccessibility (fld, caller); + if (! field->isAccessible () + && ! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags)) + throw new java::lang::IllegalAccessException; + if (flags & java::lang::reflect::Modifier::STATIC) { jclass fldClass = field->getDeclaringClass (); diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index c0f7077cc40..6330c4b4675 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999, 2000, 2001 , 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -30,6 +30,8 @@ details. */ #include <java/lang/Double.h> #include <java/lang/IllegalArgumentException.h> #include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/VirtualMachineError.h> #include <java/lang/Class.h> #include <gcj/method.h> #include <gnu/gcj/RawData.h> @@ -142,19 +144,33 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) if (parameter_types == NULL) getType (); + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + jmethodID meth = _Jv_FromReflectedMethod (this); + jclass klass; if (! java::lang::reflect::Modifier::isStatic(meth->accflags)) { - jclass k = obj ? obj->getClass() : NULL; if (! obj) throw new java::lang::NullPointerException; - if (! declaringClass->isAssignableFrom(k)) + klass = obj->getClass(); + if (! declaringClass->isAssignableFrom(klass)) throw new java::lang::IllegalArgumentException; - // FIXME: access checks. // Find the possibly overloaded method based on the runtime type // of the object. - meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature); + meth = _Jv_LookupDeclaredMethod (klass, meth->name, meth->signature); } else { @@ -162,8 +178,12 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) // here and not in _Jv_CallAnyMethodA because JNI initializes a // class whenever a method lookup is done. _Jv_InitClass (declaringClass); + klass = declaringClass; } + if (! isAccessible() && ! _Jv_CheckAccess(caller, klass, meth->accflags)) + throw new IllegalArgumentException; + return _Jv_CallAnyMethodA (obj, return_type, meth, false, parameter_types, args); } @@ -207,7 +227,7 @@ java::lang::reflect::Method::getType () jclass *elts = elements (exception_types); for (int i = 0; i < count; ++i) elts[i] = _Jv_FindClass (method->throws[i], - declaringClass->getClassLoader ()); + declaringClass->getClassLoaderInternal ()); } void @@ -218,7 +238,7 @@ _Jv_GetTypesFromSignature (jmethodID method, { _Jv_Utf8Const* sig = method->signature; - java::lang::ClassLoader *loader = declaringClass->getClassLoader(); + java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal(); char *ptr = sig->data; int numArgs = 0; /* First just count the number of parameters. */ @@ -290,9 +310,8 @@ _Jv_GetTypesFromSignature (jmethodID method, break; } - // FIXME: 2'nd argument should be "current loader" while (--num_arrays >= 0) - type = _Jv_GetArrayClass (type, 0); + type = _Jv_GetArrayClass (type, loader); // ARGPTR can be NULL if we are processing the return value of a // call from Constructor. if (argPtr) @@ -309,14 +328,15 @@ _Jv_GetTypesFromSignature (jmethodID method, // to a `jvalue' (see jni.h); for a void method this should be NULL. // This function returns an exception (if one was thrown), or NULL if // the call went ok. -jthrowable +void _Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, JArray<jclass> *parameter_types, jvalue *args, - jvalue *result) + jvalue *result, + jboolean is_jni_call) { #ifdef USE_LIBFFI JvAssert (! is_constructor || ! obj); @@ -344,19 +364,11 @@ _Jv_CallAnyMethodA (jobject obj, jclass *paramelts = elements (parameter_types); - // FIXME: at some point the compiler is going to add extra arguments - // to some functions. In particular we are going to do this for - // handling access checks in reflection. We must add these hidden - // arguments here. - // Special case for the `this' argument of a constructor. Note that // the JDK 1.2 docs specify that the new object must be allocated // before argument conversions are done. if (is_constructor) - { - // FIXME: must special-case String, arrays, maybe others here. - obj = JvAllocObject (return_type); - } + obj = JvAllocObject (return_type); const int size_per_arg = sizeof(jvalue); ffi_cif cif; @@ -398,15 +410,11 @@ _Jv_CallAnyMethodA (jobject obj, if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, rtype, argtypes) != FFI_OK) - { - // FIXME: throw some kind of VirtualMachineError here. - } + throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed")); using namespace java::lang; using namespace java::lang::reflect; - Throwable *ex = NULL; - union { ffi_arg i; @@ -416,17 +424,51 @@ _Jv_CallAnyMethodA (jobject obj, jdouble d; } ffi_result; + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = 0; + break; + case FFI_TYPE_SINT16: + result->s = 0; + break; + case FFI_TYPE_UINT16: + result->c = 0; + break; + case FFI_TYPE_SINT32: + result->i = 0; + break; + case FFI_TYPE_SINT64: + result->j = 0; + break; + case FFI_TYPE_FLOAT: + result->f = 0; + break; + case FFI_TYPE_DOUBLE: + result->d = 0; + break; + case FFI_TYPE_POINTER: + result->l = 0; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + try { ffi_call (&cif, (void (*)()) meth->ncode, &ffi_result, values); } - catch (Throwable *ex2) + catch (Throwable *ex) { - // FIXME: this is wrong for JNI. But if we just return the - // exception, then the non-JNI cases won't be able to - // distinguish it from exceptions we might generate ourselves. - // Sigh. - ex = new InvocationTargetException (ex2); + // For JNI we just throw the real error. For reflection, we + // wrap the underlying method's exception in an + // InvocationTargetException. + if (! is_jni_call) + ex = new InvocationTargetException (ex); + throw ex; } // Since ffi_call returns integer values promoted to a word, use @@ -470,11 +512,8 @@ _Jv_CallAnyMethodA (jobject obj, break; } } - - return ex; #else - throw new java::lang::UnsupportedOperationException; - return 0; + throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build")); #endif // USE_LIBFFI } @@ -488,8 +527,6 @@ _Jv_CallAnyMethodA (jobject obj, JArray<jclass> *parameter_types, jobjectArray args) { - // FIXME: access checks. - if (parameter_types->length == 0 && args == NULL) { // The JDK accepts this, so we do too. @@ -553,16 +590,9 @@ _Jv_CallAnyMethodA (jobject obj, } jvalue ret_value; - java::lang::Throwable *ex = _Jv_CallAnyMethodA (obj, - return_type, - meth, - is_constructor, - parameter_types, - argvals, - &ret_value); - - if (ex) - throw ex; + _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor, + parameter_types, argvals, &ret_value, + false); jobject r; #define VAL(Wrapper, Field) (new Wrapper (ret_value.Field)) |