aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/lang
diff options
context:
space:
mode:
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
commit2e9c0dc38e2692b04281844366dbb367ae1294e1 (patch)
treee56f44693864144d87710daeab9743d4e76b6037 /libjava/java/lang
parent780b7d9b87ddf306aa31c750d5eb9d96a9cb69ea (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')
-rw-r--r--libjava/java/lang/Class.h7
-rw-r--r--libjava/java/lang/Class.java46
-rw-r--r--libjava/java/lang/ClassLoader.java20
-rw-r--r--libjava/java/lang/InheritableThreadLocal.java13
-rw-r--r--libjava/java/lang/Math.java4
-rw-r--r--libjava/java/lang/Runtime.java4
-rw-r--r--libjava/java/lang/StrictMath.java4
-rw-r--r--libjava/java/lang/String.java3
-rw-r--r--libjava/java/lang/StringBuffer.java5
-rw-r--r--libjava/java/lang/Thread.java13
-rw-r--r--libjava/java/lang/ThreadGroup.java1
-rw-r--r--libjava/java/lang/ThreadLocal.java9
-rw-r--r--libjava/java/lang/Win32Process.java8
-rw-r--r--libjava/java/lang/natClass.cc87
-rw-r--r--libjava/java/lang/natRuntime.cc8
-rw-r--r--libjava/java/lang/natString.cc7
-rw-r--r--libjava/java/lang/natSystem.cc6
-rw-r--r--libjava/java/lang/natWin32Process.cc87
-rw-r--r--libjava/java/lang/ref/Reference.java42
-rw-r--r--libjava/java/lang/ref/natReference.cc21
-rw-r--r--libjava/java/lang/reflect/Constructor.java236
-rw-r--r--libjava/java/lang/reflect/Field.java28
-rw-r--r--libjava/java/lang/reflect/Method.java228
-rw-r--r--libjava/java/lang/reflect/Proxy.java27
-rw-r--r--libjava/java/lang/reflect/natArray.cc33
-rw-r--r--libjava/java/lang/reflect/natConstructor.cc22
-rw-r--r--libjava/java/lang/reflect/natField.cc43
-rw-r--r--libjava/java/lang/reflect/natMethod.cc124
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 "&lt;modifier&gt; &lt;classname&gt;(&lt;paramtypes&gt;)
+ * throws &lt;exceptions&gt;", 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 "&lt;modifiers&gt; &lt;returntype&gt;
+ * &lt;methodname&gt;(&lt;paramtypes&gt;) throws &lt;exceptions&gt;", 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))