Patch: reflection bug fixes

Tom Tromey tromey@cygnus.com
Wed Jan 5 14:22:00 GMT 2000


I'm committing this patch.  It fixes a number of bugs in the new
reflection code (most of which were pointed out by the Mauve hacking I
did today).  It also implements a few more reflection methods; I think
only Class.getClasses() is missing now.

2000-01-05  Tom Tromey  <tromey@cygnus.com>

	* java/lang/Class.h (_getMethods): Declare.
	* java/lang/Class.java (_getMethods): Declare.
	* java/lang/natClass.cc (getDeclaringClass): Always return NULL.
	(getDeclaredClasses): Always return empty array.
	(_getMethods): New method.
	(getMethods): Wrote.
	(getDeclaredMethod): Return `rmethod'.
	(finit_name): New global.
	(getDeclaredMethods): Check for finit_name.
	(_getMethods): Likewise.
	(getMethod): Only return public methods.

Tom

Index: java/lang/Class.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/Class.h,v
retrieving revision 1.9
diff -u -r1.9 Class.h
--- Class.h	2000/01/05 16:35:20	1.9
+++ Class.h	2000/01/05 22:13:42
@@ -105,6 +105,8 @@
   void getSignature (java::lang::StringBuffer *buffer);
   static jstring getSignature (JArray<jclass> *, jboolean is_constructor);
   java::lang::reflect::Method *getMethod (jstring, JArray<jclass> *);
+  jint _getMethods (JArray<java::lang::reflect::Method *> *result,
+		    jint offset);
   JArray<java::lang::reflect::Method *> *getMethods (void);
 
   jint getModifiers (void)
Index: java/lang/Class.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/Class.java,v
retrieving revision 1.5
diff -u -r1.5 Class.java
--- Class.java	2000/01/05 16:35:20	1.5
+++ Class.java	2000/01/05 22:13:42
@@ -94,6 +94,7 @@
 
   public native Method getMethod (String methodName, Class[] parameterTypes)
     throws NoSuchMethodException, SecurityException;
+  private native int _getMethods (Method[] result, int offset);
   public native Method[] getMethods () throws SecurityException;
 
   public native int getModifiers ();
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natClass.cc,v
retrieving revision 1.10
diff -u -r1.10 natClass.cc
--- natClass.cc	2000/01/05 16:35:20	1.10
+++ natClass.cc	2000/01/05 22:13:51
@@ -63,6 +63,7 @@
 static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
 static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
 static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+static _Jv_Utf8Const *finit_name = _Jv_makeUtf8Const ("$finit$", 7);
 
 
 
@@ -310,6 +311,7 @@
 	  Method *rmethod = new Method ();
 	  rmethod->offset = (char*) (&methods[i]) - (char*) methods;
 	  rmethod->declaringClass = this;
+	  return rmethod;
 	}
     }
   JvThrow (new java::lang::NoSuchMethodException);
@@ -326,7 +328,8 @@
       _Jv_Method *method = &methods[i];
       if (method->name == NULL
 	  || _Jv_equalUtf8Consts (method->name, clinit_name)
-	  || _Jv_equalUtf8Consts (method->name, init_name))
+	  || _Jv_equalUtf8Consts (method->name, init_name)
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
 	continue;
       numMethods++;
     }
@@ -339,7 +342,8 @@
       _Jv_Method *method = &methods[i];
       if (method->name == NULL
 	  || _Jv_equalUtf8Consts (method->name, clinit_name)
-	  || _Jv_equalUtf8Consts (method->name, init_name))
+	  || _Jv_equalUtf8Consts (method->name, init_name)
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
 	continue;
       java::lang::reflect::Method* rmethod
 	= new java::lang::reflect::Method ();
@@ -370,16 +374,19 @@
 java::lang::Class::getDeclaredClasses (void)
 {
   checkMemberAccess (java::lang::reflect::Member::DECLARED);
-  JvFail ("java::lang::Class::getDeclaredClasses not implemented");
-  return NULL;			// Placate compiler.
+  // Until we have inner classes, it always makes sense to return an
+  // empty array.
+  JArray<jclass> *result
+    = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
+  return result;
 }
 
-// This is marked as unimplemented in the JCL book.
 jclass
 java::lang::Class::getDeclaringClass (void)
 {
-  JvFail ("java::lang::Class::getDeclaringClass unimplemented");
-  return NULL;			// Placate compiler.
+  // Until we have inner classes, it makes sense to always return
+  // NULL.
+  return NULL;
 }
 
 jint
@@ -463,6 +470,11 @@
 	    {
 	      // Found it.
 	      using namespace java::lang::reflect;
+
+	      // Method must be public.
+	      if (! Modifier::isPublic (methods[i].accflags))
+		break;
+
 	      Method *rmethod = new Method ();
 	      rmethod->offset = (char*) (&klass->methods[i]) - (char*) methods;
 	      rmethod->declaringClass = klass;
@@ -473,10 +485,118 @@
   JvThrow (new java::lang::NoSuchMethodException);
 }
 
+// This is a very slow implementation, since it re-scans all the
+// methods we've already listed to make sure we haven't duplicated a
+// method.  It also over-estimates the required size, so we have to
+// shrink the result array later.
+jint
+java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
+				jint offset)
+{
+  jint count = 0;
+
+  // First examine all local methods
+  for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
+    {
+      _Jv_Method *method = &methods[i];
+      if (method->name == NULL
+	  || _Jv_equalUtf8Consts (method->name, clinit_name)
+	  || _Jv_equalUtf8Consts (method->name, init_name)
+	  || _Jv_equalUtf8Consts (method->name, finit_name))
+	continue;
+      // Only want public methods.
+      if (! java::lang::reflect::Modifier::isPublic (method->accflags))
+	continue;
+
+      // This is where we over-count the slots required if we aren't
+      // filling the result for real.
+      if (result != NULL)
+	{
+	  jboolean add = true;
+	  java::lang::reflect::Method **mp = elements (result);
+	  // If we already have a method with this name and signature,
+	  // then ignore this one.  This can happen with virtual
+	  // methods.
+	  for (int j = 0; j < offset; ++j)
+	    {
+	      _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
+	      if (_Jv_equalUtf8Consts (method->name, meth_2->name)
+		  && _Jv_equalUtf8Consts (method->signature,
+					  meth_2->signature))
+		{
+		  add = false;
+		  break;
+		}
+	    }
+	  if (! add)
+	    continue;
+	}
+
+      if (result != NULL)
+	{
+	  using namespace java::lang::reflect;
+	  Method *rmethod = new Method ();
+	  rmethod->offset = (char *) method - (char *) methods;
+	  rmethod->declaringClass = this;
+	  Method **mp = elements (result);
+	  mp[offset + count] = rmethod;
+	}
+      ++count;
+    }
+  offset += count;
+
+  // Now examine superclasses.
+  if (getSuperclass () != NULL)
+    {
+      jint s_count = getSuperclass()->_getMethods (result, offset);
+      offset += s_count;
+      count += s_count;
+    }
+
+  // Finally, examine interfaces.
+  for (int i = 0; i < interface_count; ++i)
+    {
+      int f_count = interfaces[i]->_getMethods (result, offset);
+      count += f_count;
+      offset += f_count;
+    }
+
+  return count;
+}
+
 JArray<java::lang::reflect::Method *> *
 java::lang::Class::getMethods (void)
 {
-  JvFail ("java::lang::Class::getMethods not implemented");
+  using namespace java::lang::reflect;
+
+  // FIXME: security checks.
+
+  // This will overestimate the size we need.
+  jint count = _getMethods (NULL, 0);
+
+  JArray<Method *> *result
+    = ((JArray<Method *> *) JvNewObjectArray (count, &MethodClass, NULL));
+
+  // When filling the array for real, we get the actual count.  Then
+  // we resize the array.
+  jint real_count = _getMethods (result, 0);
+
+  if (real_count != count)
+    {
+      JArray<Method *> *r2
+	= ((JArray<Method *> *) JvNewObjectArray (real_count, &MethodClass,
+						  NULL));
+      
+      Method **destp = elements (r2);
+      Method **srcp = elements (result);
+
+      for (int i = 0; i < real_count; ++i)
+	*destp++ = *srcp++;
+
+      result = r2;
+    }
+
+  return result;
 }
 
 jboolean


More information about the Java-patches mailing list