public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@redhat.com>
To: Java Patch List <java-patches@gcc.gnu.org>
Subject: [ecj] Patch: FYI: implement more reflection methods
Date: Fri, 21 Jul 2006 23:55:00 -0000	[thread overview]
Message-ID: <m3odvimsa6.fsf@localhost.localdomain> (raw)

I'm checking this in on the gcj-eclipse branch.

This adds support for more reflection methods, and in particular
fixes PR 4105.

Also, I've filed PRs for the other to-do items for 1.5 reflection
support.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	PR libgcj/4105:
	* java/lang/natClass.cc (findInnerClassAttribute): New method.
	(findDeclaredClasses): Likewise.
	(getDeclaredClasses): Implemented.
	(getDeclaringClass): Likewise.
	(isAnonymousClass): Likewise.
	(isMemberClass): Likewise.
	(check_constant): Pass message in exception.  Allow resolved
	constants.
	(resolve_class_constant): New function.
	* defineclass.cc (read_one_class_attribute): Handle InnerClasses.
	* java/lang/Class.h (isAnonymousClass, isLocalClass,
	isMemberClass): Declare.
	* java/lang/Class.java (getSimpleName): Implemented.
	(isAnonymousClass, isLocalClass, isMemberClass): New methods.

Index: java/lang/natClass.cc
===================================================================
--- java/lang/natClass.cc	(revision 115453)
+++ java/lang/natClass.cc	(working copy)
@@ -438,25 +438,6 @@
 }
 
 JArray<jclass> *
-java::lang::Class::getDeclaredClasses (jboolean /*publicOnly*/)
-{
-  // Until we have inner classes, it always makes sense to return an
-  // empty array.
-  JArray<jclass> *result
-    = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
-					   NULL);
-  return result;
-}
-
-jclass
-java::lang::Class::getDeclaringClass (void)
-{
-  // Until we have inner classes, it makes sense to always return
-  // NULL.
-  return NULL;
-}
-
-JArray<jclass> *
 java::lang::Class::getInterfaces (void)
 {
   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
@@ -1070,12 +1051,19 @@
 }
 
 static void
-check_constant(_Jv_Constants *pool, jint cpool_index, jint type)
+check_constant (_Jv_Constants *pool, jint cpool_index, jint type)
 {
-  if (cpool_index <= 0
-      || cpool_index >= pool->size
-      || pool->tags[cpool_index] != type)
-    throw new InternalError();
+  if (cpool_index <= 0 || cpool_index >= pool->size)
+    throw new InternalError(JvNewStringLatin1("invalid constant pool index"));
+  if ((pool->tags[cpool_index] & ~JV_CONSTANT_ResolvedFlag) != type)
+    {
+      ::java::lang::StringBuffer *sb = new ::java::lang::StringBuffer();
+      sb->append(JvNewStringLatin1("expected pool constant "));
+      sb->append(type);
+      sb->append(JvNewStringLatin1(" but got "));
+      sb->append(jint (pool->tags[cpool_index]));
+      throw new InternalError(sb->toString());
+    }
 }
 
 // Forward declaration
@@ -1381,6 +1369,180 @@
   return (JArray< ::java::lang::annotation::Annotation *> *) getDeclaredAnnotations(JV_CLASS_ATTR, 0, JV_ANNOTATIONS_KIND);
 }
 
+static jclass
+resolve_class_constant (jclass klass, _Jv_Constants *pool, int cpool_index)
+{
+  check_constant (pool, cpool_index, JV_CONSTANT_Class);
+  // FIXME: what is the correct thing to do with an exception here?
+  return _Jv_Linker::resolve_pool_entry (klass, cpool_index, false).clazz;
+}
+
+jint
+java::lang::Class::findInnerClassAttribute()
+{
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return -1;
+  while (true)
+    {
+      int type = read_u1 (bytes);
+      if (type == JV_DONE_ATTR)
+	break;
+      // After the type but before the length.
+      unsigned char *save = bytes;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (type != JV_CLASS_ATTR)
+	{
+	  bytes = next;
+	  continue;
+	}
+      int kind = read_u1 (bytes, next);
+      if (kind != JV_INNER_CLASSES_KIND)
+	{
+	  bytes = next;
+	  continue;
+	}
+      return save - reflection_data;
+    }
+  return -1;
+}
+
+jint
+java::lang::Class::findDeclaredClasses(JArray<jclass> *result,
+				       jboolean publicOnly,
+				       jint offset)
+{
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  int count = 0;
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      int outer_class_index = read_u2 (bytes, next);
+      /*int inner_name_index = */ read_u2 (bytes, next);
+      int inner_flags = read_u2 (bytes, next);
+
+      if (inner_class_index == 0 || outer_class_index == 0)
+	continue;
+      if (resolve_class_constant (this, &constants, outer_class_index) == this)
+	{
+	  jclass inner = resolve_class_constant (this, &constants,
+						 inner_class_index);
+	  if (! publicOnly
+	      || ((inner_flags
+		   & java::lang::reflect::Modifier::PUBLIC) != 0))
+	    {
+	      if (result)
+		{
+		  jclass *elts = elements (result);
+		  elts[count] = inner;
+		}
+	      ++count;
+	    }
+	}
+    }
+
+  return count;
+}
+
+JArray<jclass> *
+java::lang::Class::getDeclaredClasses (jboolean publicOnly)
+{
+  int offset = findInnerClassAttribute();
+  int count;
+  if (offset == -1)
+    {
+      // No InnerClasses attribute, so no declared classes.
+      count = 0;
+    }
+  else
+    count = findDeclaredClasses(NULL, publicOnly, offset);
+  JArray<jclass> *result
+    = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$,
+					   NULL);
+  if (count > 0)
+    findDeclaredClasses(result, publicOnly, offset);
+  return result;
+}
+
+jclass
+java::lang::Class::getDeclaringClass (void)
+{
+  int offset = findInnerClassAttribute();
+  if (offset == -1)
+    return NULL;
+
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      int outer_class_index = read_u2 (bytes, next);
+      /*int inner_name_index = */read_u2 (bytes, next);
+      /*int inner_flags = */read_u2 (bytes, next);
+
+      if (inner_class_index == 0 || outer_class_index == 0)
+	continue;
+      if (resolve_class_constant (this, &constants, inner_class_index) == this)
+	return resolve_class_constant (this, &constants, outer_class_index);
+    }
+
+  return NULL;
+}
+
+jboolean
+java::lang::Class::isAnonymousClass()
+{
+  int offset = findInnerClassAttribute();
+  if (offset == -1)
+    return false;
+
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      /*int outer_class_index = */read_u2 (bytes, next);
+      int inner_name_index = read_u2 (bytes, next);
+      /*int inner_flags = */read_u2 (bytes, next);
+
+      if (inner_class_index == 0)
+	continue;
+      if (resolve_class_constant (this, &constants, inner_class_index) == this)
+	return inner_name_index == 0;
+    }
+
+  return false;
+}
+
+jboolean
+java::lang::Class::isLocalClass()
+{
+  _Jv_word indexes;
+  indexes.i = getEnclosingMethodData();
+  return indexes.i != 0;
+}
+
+jboolean
+java::lang::Class::isMemberClass()
+{
+  // FIXME: is this correct?
+  return !isLocalClass() && getDeclaringClass() != NULL;
+}
+
 \f
 
 //
Index: java/lang/Class.java
===================================================================
--- java/lang/Class.java	(revision 115453)
+++ java/lang/Class.java	(working copy)
@@ -1081,8 +1081,22 @@
    */
   public String getSimpleName()
   {
-    // FIXME write real implementation
-    return "";
+    StringBuffer sb = new StringBuffer();
+    Class klass = this;
+    int arrayCount = 0;
+    while (klass.isArray())
+      {
+	klass = klass.getComponentType();
+	++arrayCount;
+      }
+    if (! klass.isAnonymousClass())
+      {
+	String fullName = klass.getName();
+	sb.append(fullName, fullName.lastIndexOf(".") + 1, fullName.length());
+      }
+    while (arrayCount-- > 0)
+      sb.append("[]");
+    return sb.toString();
   }
 
   /**
@@ -1316,4 +1330,27 @@
     return getAnnotation(annotationClass) != null;
   }
 
+  /**
+   * Returns true if this object represents an anonymous class.
+   *
+   * @return true if this object represents an anonymous class.
+   * @since 1.5
+   */
+  public native boolean isAnonymousClass();
+
+  /**
+   * Returns true if this object represents an local class.
+   *
+   * @return true if this object represents an local class.
+   * @since 1.5
+   */
+  public native boolean isLocalClass();
+
+  /**
+   * Returns true if this object represents an member class.
+   *
+   * @return true if this object represents an member class.
+   * @since 1.5
+   */
+  public native boolean isMemberClass();
 }
Index: java/lang/Class.h
===================================================================
--- java/lang/Class.h	(revision 115453)
+++ java/lang/Class.h	(working copy)
@@ -435,6 +435,10 @@
   jobjectArray getDeclaredAnnotations(::java::lang::reflect::Field *);
   JArray< ::java::lang::annotation::Annotation *> *getDeclaredAnnotationsInternal();
 
+  jboolean isAnonymousClass();
+  jboolean isLocalClass();
+  jboolean isMemberClass();
+
   // FIXME: this probably shouldn't be public.
   jint size (void)
   {
@@ -471,6 +475,9 @@
     notifyAll ();
   }
 
+  jint findInnerClassAttribute();
+  jint findDeclaredClasses(JArray<jclass> *, jboolean, jint);
+
   // Friend functions implemented in natClass.cc.
   friend _Jv_Method *::_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
 					   _Jv_Utf8Const *signature);
Index: defineclass.cc
===================================================================
--- defineclass.cc	(revision 115453)
+++ defineclass.cc	(working copy)
@@ -957,10 +957,18 @@
     handleEnclosingMethod(length);
   else if (is_attribute_name (name, "RuntimeVisibleAnnotations"))
     handleMemberAnnotations(JV_CLASS_ATTR, 0, length);
+  else if (is_attribute_name (name, "InnerClasses"))
+    {
+      ::java::io::DataOutputStream *stream = get_reflection_stream ();
+      stream->writeByte(JV_CLASS_ATTR);
+      stream->writeInt(length + 1);
+      stream->writeByte(JV_INNER_CLASSES_KIND);
+      stream->write(input_data, input_offset + pos, length);
+      skip (length);
+    }
   else
     {
-      /* Currently, we ignore most class attributes.
-         FIXME: Add inner-classes attributes support. */
+      /* Currently, we ignore most class attributes. */
      skip (length);
     }
 }

                 reply	other threads:[~2006-07-21 23:55 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m3odvimsa6.fsf@localhost.localdomain \
    --to=tromey@redhat.com \
    --cc=java-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).