This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: add `throws' reflection information


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,
 			     &parameter_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++)
     {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]