* [ecj] Patch: FYI: implement more reflection methods
@ 2006-07-21 23:55 Tom Tromey
0 siblings, 0 replies; only message in thread
From: Tom Tromey @ 2006-07-21 23:55 UTC (permalink / raw)
To: Java Patch List
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);
}
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-07-21 23:55 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-21 23:55 [ecj] Patch: FYI: implement more reflection methods Tom Tromey
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).