This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: add `throws' reflection information
- To: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Subject: Patch: add `throws' reflection information
- From: Tom Tromey <tromey at redhat dot com>
- Date: 24 Aug 2001 10:42:55 -0600
- Cc: Java Patch List <java-patches at gcc dot gnu dot org>
- Reply-To: tromey at redhat dot com
This patch adds reflection data so that
java.lang.reflect.Method.getExceptionTypes() will work.
It required a change to the compiler and the runtime.
This patch also fixes some bugs I found in the reflection code that
occur when printing an array type.
I tested this on x86 Red Hat Linux 6.2. I wrote a new Mauve test for
the bug fix I introduced.
Alex, are the compiler parts ok for the trunk?
Tom
Index: gcc/java/ChangeLog
from Tom Tromey <tromey@redhat.com>
* decl.c (init_decl_processing): Add `throws' field to method
descriptor.
* class.c (make_method_value): Compute `throws' field for method.
Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.108
diff -u -r1.108 class.c
--- gcc/java/class.c 2001/08/18 00:53:20 1.108
+++ gcc/java/class.c 2001/08/24 00:36:20
@@ -1151,6 +1151,7 @@
make_method_value (mdecl)
tree mdecl;
{
+ static int method_name_count = 0;
tree minit;
tree code;
#define ACC_TRANSLATED 0x4000
@@ -1173,6 +1174,44 @@
}
PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
PUSH_FIELD_VALUE (minit, "ncode", code);
+
+ {
+ /* Compute the `throws' information for the method. */
+ tree table = integer_zero_node;
+ if (DECL_FUNCTION_THROWS (mdecl) != NULL_TREE)
+ {
+ int length = 1 + list_length (DECL_FUNCTION_THROWS (mdecl));
+ tree iter, type, array;
+ char buf[60];
+
+ table = tree_cons (NULL_TREE, table, NULL_TREE);
+ for (iter = DECL_FUNCTION_THROWS (mdecl);
+ iter != NULL_TREE;
+ iter = TREE_CHAIN (iter))
+ {
+ tree sig = build_java_signature (TREE_VALUE (iter));
+ tree utf8
+ = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig),
+ IDENTIFIER_LENGTH (sig)));
+ table = tree_cons (NULL_TREE, utf8, table);
+ }
+ type = build_prim_array_type (ptr_type_node, length);
+ table = build (CONSTRUCTOR, type, NULL_TREE, table);
+ /* Compute something unique enough. */
+ sprintf (buf, "_methods%d", method_name_count++);
+ array = build_decl (VAR_DECL, get_identifier (buf), type);
+ DECL_INITIAL (array) = table;
+ TREE_STATIC (array) = 1;
+ DECL_ARTIFICIAL (array) = 1;
+ DECL_IGNORED_P (array) = 1;
+ rest_of_decl_compilation (array, (char*) 0, 1, 0);
+
+ table = build1 (ADDR_EXPR, ptr_type_node, array);
+ }
+
+ PUSH_FIELD_VALUE (minit, "throws", table);
+ }
+
FINISH_RECORD_CONSTRUCTOR (minit);
return minit;
}
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.107
diff -u -r1.107 decl.c
--- gcc/java/decl.c 2001/08/17 21:07:07 1.107
+++ gcc/java/decl.c 2001/08/24 00:36:22
@@ -715,6 +715,7 @@
PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type);
PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node);
PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node);
+ PUSH_FIELD (method_type_node, field, "throws", ptr_type_node);
FINISH_RECORD (method_type_node);
build_decl (TYPE_DECL, get_identifier ("Method"), method_type_node);
Index: libjava/ChangeLog
from Tom Tromey <tromey@redhat.com>
* java/lang/reflect/Field.java (toString): Use
Method.appendClassName.
* java/lang/reflect/Constructor.java (toString): Use
Method.appendClassName.
* java/lang/reflect/Method.java: Reindented.
(appendClassName): New method.
(toString): Use it.
* defineclass.cc (handleMethod ): Initialize `throws' field of
method.
(read_one_method_attribute): Handle Exceptions attribute.
* java/lang/reflect/natMethod.cc (ClassClass): Removed.
(ObjectClass): Removed.
(getType): Compute `exception_types'.
* java/lang/Class.h (struct _Jv_Method): Added `throws' field.
Index: libjava/defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.17
diff -u -r1.17 defineclass.cc
--- libjava/defineclass.cc 2001/05/24 05:40:36 1.17
+++ libjava/defineclass.cc 2001/08/24 00:36:34
@@ -526,10 +526,42 @@
if (is_attribute_name (name, "Exceptions"))
{
- /* we ignore this for now */
- skip (length);
+ _Jv_Method *method = reinterpret_cast<_Jv_Method *>
+ (&def->methods[method_index]);
+ if (method->throws != NULL)
+ throw_class_format_error ("only one Exceptions attribute allowed per method");
+
+ int num_exceptions = read2u ();
+ // We use malloc here because the GC won't scan the method
+ // objects. FIXME this means a memory leak if we GC a class.
+ // (Currently we never do.)
+ _Jv_Utf8Const **exceptions =
+ (_Jv_Utf8Const **) _Jv_Malloc ((num_exceptions + 1) * sizeof (_Jv_Utf8Const *));
+
+ int out = 0;
+ _Jv_word *pool_data = def->constants.data;
+ for (int i = 0; i < num_exceptions; ++i)
+ {
+ try
+ {
+ int ndx = read2u ();
+ // JLS 2nd Ed. 4.7.5 requires that the tag not be 0.
+ if (ndx != 0)
+ {
+ check_tag (ndx, JV_CONSTANT_Class);
+ exceptions[out++] = pool_data[ndx].utf8;
+ }
+ }
+ catch (java::lang::Throwable *exc)
+ {
+ _Jv_Free (exceptions);
+ throw exc;
+ }
+ }
+ exceptions[out] = NULL;
+ method->throws = exceptions;
}
-
+
else if (is_attribute_name (name, "Code"))
{
int start_off = pos;
@@ -1206,6 +1238,7 @@
// intialize...
method->ncode = 0;
+ method->throws = NULL;
if (verify)
{
Index: libjava/java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.35
diff -u -r1.35 Class.h
--- libjava/java/lang/Class.h 2001/07/05 15:57:09 1.35
+++ libjava/java/lang/Class.h 2001/08/24 00:36:35
@@ -64,10 +64,18 @@
struct _Jv_Method
{
+ // Method name.
_Jv_Utf8Const *name;
+ // Method signature.
_Jv_Utf8Const *signature;
+ // Access flags.
_Jv_ushort accflags;
+ // Pointer to underlying function.
void *ncode;
+ // NULL-terminated list of exception class names; can be NULL if
+ // there are none such.
+ _Jv_Utf8Const **throws;
+
_Jv_Method *getNextMethod ()
{ return this + 1; }
};
Index: libjava/java/lang/reflect/Constructor.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Constructor.java,v
retrieving revision 1.6
diff -u -r1.6 Constructor.java
--- libjava/java/lang/reflect/Constructor.java 2001/03/22 06:37:16 1.6
+++ libjava/java/lang/reflect/Constructor.java 2001/08/24 00:36:35
@@ -77,11 +77,11 @@
StringBuffer b = new StringBuffer ();
b.append(Modifier.toString(getModifiers()));
b.append(" ");
- b.append(getName());
+ Method.appendClassName (b, declaringClass);
b.append("(");
for (int i = 0; i < parameter_types.length; ++i)
{
- b.append(parameter_types[i].getName());
+ Method.appendClassName (b, parameter_types[i]);
if (i < parameter_types.length - 1)
b.append(",");
}
Index: libjava/java/lang/reflect/Field.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Field.java,v
retrieving revision 1.5
diff -u -r1.5 Field.java
--- libjava/java/lang/reflect/Field.java 2000/09/11 22:49:29 1.5
+++ libjava/java/lang/reflect/Field.java 2001/08/24 00:36:35
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
This file is part of libgcj.
@@ -257,9 +257,9 @@
Modifier.toString(mods, sbuf);
sbuf.append(' ');
}
- sbuf.append(getType().getName());
+ Method.appendClassName (sbuf, getType ());
sbuf.append(' ');
- sbuf.append(getDeclaringClass().getName());
+ Method.appendClassName (sbuf, getDeclaringClass());
sbuf.append('.');
sbuf.append(getName());
return sbuf.toString();
Index: libjava/java/lang/reflect/Method.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Method.java,v
retrieving revision 1.11
diff -u -r1.11 Method.java
--- libjava/java/lang/reflect/Method.java 2001/03/22 06:37:16 1.11
+++ libjava/java/lang/reflect/Method.java 2001/08/24 00:36:35
@@ -25,24 +25,24 @@
public final class Method extends AccessibleObject implements Member
{
public boolean equals (Object obj)
- {
- if (! (obj instanceof Method))
- return false;
- Method m = (Method) obj;
- return declaringClass == m.declaringClass && offset == m.offset;
- }
+ {
+ if (! (obj instanceof Method))
+ return false;
+ Method m = (Method) obj;
+ return declaringClass == m.declaringClass && offset == m.offset;
+ }
public Class getDeclaringClass ()
- {
- return declaringClass;
- }
+ {
+ return declaringClass;
+ }
public Class[] getExceptionTypes ()
- {
- if (exception_types == null)
- getType();
- return (Class[]) exception_types.clone();
- }
+ {
+ if (exception_types == null)
+ getType();
+ return (Class[]) exception_types.clone();
+ }
public native int getModifiers ();
@@ -51,62 +51,82 @@
private native void getType ();
public Class[] getParameterTypes ()
- {
- if (parameter_types == null)
- getType();
- return (Class[]) parameter_types.clone();
- }
+ {
+ if (parameter_types == null)
+ getType();
+ return (Class[]) parameter_types.clone();
+ }
public Class getReturnType ()
- {
- if (return_type == null)
- getType();
- return return_type;
- }
+ {
+ if (return_type == null)
+ getType();
+ return return_type;
+ }
public int hashCode ()
- {
- // FIXME.
- return getName().hashCode() + declaringClass.getName().hashCode();
- }
+ {
+ // FIXME.
+ return getName().hashCode() + declaringClass.getName().hashCode();
+ }
public native Object invoke (Object obj, Object[] args)
throws IllegalAccessException, IllegalArgumentException,
- InvocationTargetException;
+ 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)
+ {
+ 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 ());
+ }
+ }
+
public String toString ()
- {
- if (parameter_types == null)
- getType ();
-
- StringBuffer b = new StringBuffer ();
- Modifier.toString(getModifiers(), b);
- b.append(" ");
- b.append(return_type.getName());
- b.append(" ");
- b.append(declaringClass.getName());
- b.append(".");
- b.append(getName());
- b.append("(");
- for (int i = 0; i < parameter_types.length; ++i)
- {
- b.append(parameter_types[i].getName());
- if (i < parameter_types.length - 1)
- b.append(",");
- }
- b.append(")");
- if (exception_types.length > 0)
- {
- b.append(" throws ");
- for (int i = 0; i < exception_types.length; ++i)
- {
- b.append(exception_types[i].getName());
- if (i < exception_types.length - 1)
- b.append(",");
- }
- }
- return b.toString();
- }
+ {
+ if (parameter_types == null)
+ getType ();
+
+ StringBuffer b = new StringBuffer ();
+ Modifier.toString(getModifiers(), b);
+ b.append(" ");
+ appendClassName (b, return_type);
+ b.append(" ");
+ appendClassName (b, declaringClass);
+ b.append(".");
+ b.append(getName());
+ b.append("(");
+ for (int i = 0; i < parameter_types.length; ++i)
+ {
+ appendClassName (b, parameter_types[i]);
+ if (i < parameter_types.length - 1)
+ b.append(",");
+ }
+ b.append(")");
+ if (exception_types.length > 0)
+ {
+ b.append(" throws ");
+ for (int i = 0; i < exception_types.length; ++i)
+ {
+ appendClassName (b, exception_types[i]);
+ if (i < exception_types.length - 1)
+ b.append(",");
+ }
+ }
+ return b.toString();
+ }
private Method ()
{
Index: libjava/java/lang/reflect/natMethod.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natMethod.cc,v
retrieving revision 1.22
diff -u -r1.22 natMethod.cc
--- libjava/java/lang/reflect/natMethod.cc 2001/06/02 08:49:31 1.22
+++ libjava/java/lang/reflect/natMethod.cc 2001/08/24 00:36:35
@@ -1,6 +1,6 @@
// natMethod.cc - Native code for Method class.
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
This file is part of libgcj.
@@ -38,10 +38,6 @@
#include <gcj/method.h>
#include <gnu/gcj/RawData.h>
-// FIXME: remove these
-#define ObjectClass java::lang::Object::class$
-#define ClassClass java::lang::Class::class$
-
#include <stdlib.h>
#if USE_LIBFFI
@@ -200,14 +196,27 @@
void
java::lang::reflect::Method::getType ()
{
- _Jv_GetTypesFromSignature (_Jv_FromReflectedMethod (this),
+ _Jv_Method *method = _Jv_FromReflectedMethod (this);
+ _Jv_GetTypesFromSignature (method,
declaringClass,
¶meter_types,
&return_type);
+
+ int count = 0;
+ if (method->throws != NULL)
+ {
+ while (method->throws[count] != NULL)
+ ++count;
+ }
- // FIXME: for now we have no way to get exception information.
- exception_types = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass,
- NULL);
+ exception_types
+ = (JArray<jclass> *) JvNewObjectArray (count,
+ &java::lang::Class::class$,
+ NULL);
+ jclass *elts = elements (exception_types);
+ for (int i = 0; i < count; ++i)
+ elts[i] = _Jv_FindClassFromSignature (method->throws[i]->data,
+ declaringClass->getClassLoader ());
}
void
@@ -254,7 +263,7 @@
}
JArray<jclass> *args = (JArray<jclass> *)
- JvNewObjectArray (numArgs, &ClassClass, NULL);
+ JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL);
jclass* argPtr = elements (args);
for (ptr = sig->data; *ptr != '\0'; ptr++)
{