From 573b96856d8617721f382165af6215db99fd99c8 Mon Sep 17 00:00:00 2001 From: gandalf Date: Sat, 15 Jul 2006 20:42:59 +0000 Subject: [PATCH] 2006-07-15 Andrew John Hughes * Merge gcj-eclipse from 115268 to HEAD. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcj-eclipse-jmx@115486 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 95 ++++- libjava/Makefile.am | 4 +- libjava/Makefile.in | 4 +- libjava/boehm.cc | 3 + libjava/defineclass.cc | 307 +++++++++++++++- libjava/include/jvm.h | 3 + libjava/java/lang/Class.h | 42 ++- libjava/java/lang/Class.java | 254 ++++++++++++- libjava/java/lang/natClass.cc | 532 ++++++++++++++++++++++++++++ libjava/java/lang/reflect/Constructor.java | 32 +- libjava/java/lang/reflect/Field.java | 21 +- libjava/java/lang/reflect/Method.java | 54 ++- libjava/java/lang/reflect/natConstructor.cc | 23 ++ libjava/java/lang/reflect/natField.cc | 15 + libjava/java/lang/reflect/natMethod.cc | 31 ++ libjava/link.cc | 211 ++++++----- 16 files changed, 1469 insertions(+), 162 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index f7befa04104..62f55a4a075 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,96 @@ +2006-07-12 Andrew Haley + + * Makefile.am (java/lang/Object.lo): Add -fsource-filename. + (java/lang/Class.lo): Likewise. + * Makefile.in: Regenerate. + +2006-07-07 Tom Tromey + + * defineclass.cc (input_data, input_offset): New fields. + (reflection_data, data_stream): Likewise. + (get_reflection_stream): New method. + (_Jv_ClassReader): Initialize new fields. + (parse): Call finish_reflection_data. + (finish_reflection_data): New method. + (handleEnclosingMethod): Likewise. + (handleGenericSignature): Likewise. + (handleAnnotationElement): Likewise. + (handleAnnotation): Likewise. + (handleAnnotations): Likewise. + (handleMemberAnnotations): Likewise. + (handleAnnotationDefault): Likewise. + (handleParameterAnnotations): Likewise. + (read_one_field_attribute): Handle new attributes. + (read_one_method_attribute): Likewise. + (read_one_class_attribute): Likewise. + * include/jvm.h (resolve_method_entry): New method. + * java/lang/Class.h (jv_attr_type, jv_attr_kind): New enums. + (Class): Updated for new methods. Field, Method, Constructor now + friends. + (reflection_data): New field. + * java/lang/Class.java (asSubclass, cast): New methods. + (getEnclosingClass, getEnclosingConstructor): Now native. + (getEnclosingMethod): Likewise. + (getClassSignature): New method. + (getGenericInterfaces, getGenericSuperclass, getTypeParameters): + Likewise. + (Class): Implements AnnotatedElement. + (getAnnotation, isAnnotationPresent, getAnnotations): New methods. + (getDeclaredAnnotations): New method. + (getDeclaredAnnotationsInternal): Likewise. + * java/lang/reflect/natConstructor.cc (anno_a_t, anno_aa_t): New + typedefs. + (getSignature): New method. + (getDeclaredAnnotationsInternal): Likewise. + (getParameterAnnotationsInternal): Likewise. + * java/lang/reflect/natField.cc (anno_a_t): New typedef. + (getSignature): New method. + (getDeclaredAnnotationsInternal): Likewise. + * java/lang/reflect/natMethod.cc (anno_a_t, anno_aa_t): New + typedefs. + (getSignature): New method. + (getDefaultValue): Likewise. + (getDeclaredAnnotationsInternal): Likewise. + (getParameterAnnotationsInternal): Likewise. + * java/lang/reflect/Constructor.java (addTypeParameters): + Genericized. + (getSignature): Now native. + (getDeclaredAnnotations, getDeclaredAnnotationsInternal, + getParameterAnnotations, getParameterAnnotationsInternal): New + methods. + * java/lang/reflect/Field.java (getDeclaringClass, getType): + Genericized. + (getSignature): Now native. + (getDeclaredAnnotations, getDeclaredAnnotationsInternal): New + methods. + * java/lang/reflect/Method.java (getReturnType): Genericized. + (getParameterTypes, getExceptionTypes, getTypeParameters): + Likewise. + (getSignature): Now native. + (getDefaultValue, getDeclaredAnnotations, + getParameterAnnotations, getDeclaredAnnotationsInternal, + getParameterAnnotationsInternal): New methods. + * java/lang/natClass.cc (read_u1): New functions. + (read_u2): Likewise. + (read_4): New function. + (getReflectionSignature): New methods. + (getClassSignature): New method. + (getEnclosingMethodData): Likewise. + (getEnclosingClass): Likewise. + (getEnclosingMethod): Likewise. + (getEnclosingConstructor): Likewise. + (check_constant): New function. + (parseAnnotationElement): Likewise. + (parseAnnotation): Likewise. + (parseAnnotations): Likewise. + (parseParameterAnnotations): Likewise. + (getMethodDefaultValue): New method. + (getDeclaredAnnotations): New methods. + (getDeclaredAnnotationsInternal): New method. + * boehm.cc (_Jv_MarkObj): Mark 'reflection_data' field. + * link.cc (resolve_method_entry): New method. + (resolve_pool_entry): Use it. + 2006-07-07 Andrew John Hughes * sources.am, Makefile.in: Rebuilt. @@ -11,7 +104,7 @@ * prims.cc: (_Jv_CreateJavaVM): Retain start time and input arguments. - + 2006-07-07 Andrew Haley * Makefile.am: Use -fsource-filename when compiling libgcj. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index b6bbe0a521c..f4bdaec9400 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -327,10 +327,10 @@ lib-gnu-awt-xlib.la: $(lib_gnu_awt_xlib_la_OBJECTS) $(lib_gnu_awt_xlib_la_DEPEND $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(here)/classpath/lib/classes -MT $@ -MD -MP -MF $(basename $@).deps @$< java/lang/Object.lo: classpath/lib/java/lang/Object.class - $(LTGCJCOMPILE) -c -o $@ $< + $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(srcdir)/$(basename $@).java $< java/lang/Class.lo: classpath/lib/java/lang/Class.class - $(LTGCJCOMPILE) -c -o $@ $< + $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(srcdir)/$(basename $@).java $< ## ################################################################ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index a6a383ae03f..62e8f657905 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -9000,10 +9000,10 @@ lib-gnu-awt-xlib.la: $(lib_gnu_awt_xlib_la_OBJECTS) $(lib_gnu_awt_xlib_la_DEPEND $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(here)/classpath/lib/classes -MT $@ -MD -MP -MF $(basename $@).deps @$< java/lang/Object.lo: classpath/lib/java/lang/Object.class - $(LTGCJCOMPILE) -c -o $@ $< + $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(srcdir)/$(basename $@).java $< java/lang/Class.lo: classpath/lib/java/lang/Class.class - $(LTGCJCOMPILE) -c -o $@ $< + $(LTGCJCOMPILE) -c -o $@ -fsource-filename=$(srcdir)/$(basename $@).java $< gnu-CORBA.lo: $(gnu_CORBA_source_files) @find classpath/lib/gnu/CORBA -name '*.class' > gnu-CORBA.list diff --git a/libjava/boehm.cc b/libjava/boehm.cc index a6f7fdf4826..85af3b133b0 100644 --- a/libjava/boehm.cc +++ b/libjava/boehm.cc @@ -167,6 +167,9 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void *env) MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->aux_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + + p = (GC_PTR) c->reflection_data; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } else { diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 03d73a2c266..8bc792ca4d5 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -40,6 +40,8 @@ details. */ #include #include #include +#include +#include using namespace gcj; @@ -87,6 +89,10 @@ struct _Jv_ClassReader bool verify; + // original input data. + jbyteArray input_data; + jint input_offset; + // input data. unsigned char *bytes; int len; @@ -111,6 +117,10 @@ struct _Jv_ClassReader // True if this is a 1.5 class file. bool is_15; + // Buffer holding extra reflection data. + ::java::io::ByteArrayOutputStream *reflection_data; + ::java::io::DataOutputStream *data_stream; + /* check that the given number of input bytes are available */ inline void check (int num) @@ -126,7 +136,7 @@ struct _Jv_ClassReader pos += num; } - /* read an unsignend 1-byte unit */ + /* read an unsigned 1-byte unit */ inline static jint get1u (unsigned char* bytes) { return bytes[0]; @@ -226,6 +236,16 @@ struct _Jv_ClassReader throw_class_format_error ("erroneous type descriptor"); } + ::java::io::DataOutputStream *get_reflection_stream () + { + if (reflection_data == NULL) + { + reflection_data = new ::java::io::ByteArrayOutputStream(); + data_stream = new ::java::io::DataOutputStream(reflection_data); + } + return data_stream; + } + _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length, java::security::ProtectionDomain *pd, _Jv_Utf8Const **name_result) @@ -234,6 +254,8 @@ struct _Jv_ClassReader throw_internal_error ("arguments to _Jv_DefineClass"); verify = true; + input_data = data; + input_offset = offset; bytes = (unsigned char*) (elements (data)+offset); len = length; pos = 0; @@ -241,6 +263,8 @@ struct _Jv_ClassReader def = klass; found_name = name_result; + reflection_data = NULL; + data_stream = NULL; def->size_in_bytes = -1; def->vtable_method_count = -1; @@ -260,6 +284,16 @@ struct _Jv_ClassReader void read_one_field_attribute (int field); void throw_class_format_error (const char *msg); + void handleEnclosingMethod(int); + void handleGenericSignature(jv_attr_type, unsigned short, int); + void handleAnnotationElement(); + void handleAnnotation(); + void handleAnnotations(); + void handleMemberAnnotations(jv_attr_type, int, int); + void handleAnnotationDefault(int, int); + void handleParameterAnnotations(int, int); + void finish_reflection_data (); + /** check an utf8 entry, without creating a Utf8Const object */ bool is_attribute_name (int index, const char *name); @@ -377,6 +411,8 @@ _Jv_ClassReader::parse () if (pos != len) throw_class_format_error ("unused data before end of file"); + finish_reflection_data (); + // Tell everyone we're done. def->state = JV_STATE_READ; if (gcj::verbose_class_flag) @@ -384,6 +420,229 @@ _Jv_ClassReader::parse () def->notifyAll (); } +void +_Jv_ClassReader::finish_reflection_data () +{ + if (data_stream == NULL) + return; + data_stream->writeByte(JV_DONE_ATTR); + data_stream->flush(); + int nbytes = reflection_data->count; + unsigned char *new_bytes = (unsigned char *) _Jv_AllocBytes (nbytes); + memcpy (new_bytes, elements (reflection_data->buf), nbytes); + def->reflection_data = new_bytes; +} + +void +_Jv_ClassReader::handleEnclosingMethod (int len) +{ + if (len != 4) + throw_class_format_error ("invalid EnclosingMethod attribute"); + // FIXME: only allow one... + + int class_index = read2u(); + check_tag (class_index, JV_CONSTANT_Class); + prepare_pool_entry (class_index, JV_CONSTANT_Class); + + int method_index = read2u(); + // Zero is ok and means no enclosing method. + if (method_index != 0) + { + check_tag (method_index, JV_CONSTANT_NameAndType); + prepare_pool_entry (method_index, JV_CONSTANT_NameAndType); + } + + ::java::io::DataOutputStream *stream = get_reflection_stream (); + stream->writeByte(JV_CLASS_ATTR); + stream->writeInt(5); + stream->writeByte(JV_ENCLOSING_METHOD_KIND); + stream->writeShort(class_index); + stream->writeShort(method_index); +} + +void +_Jv_ClassReader::handleGenericSignature (jv_attr_type type, + unsigned short index, + int len) +{ + if (len != 2) + throw_class_format_error ("invalid Signature attribute"); + + int cpool_idx = read2u(); + check_tag (cpool_idx, JV_CONSTANT_Utf8); + prepare_pool_entry (cpool_idx, JV_CONSTANT_Utf8); + + ::java::io::DataOutputStream *stream = get_reflection_stream (); + stream->writeByte(type); + int attrlen = 3; + if (type != JV_CLASS_ATTR) + attrlen += 2; + stream->writeInt(attrlen); + if (type != JV_CLASS_ATTR) + stream->writeShort(index); + stream->writeByte(JV_SIGNATURE_KIND); + stream->writeShort(cpool_idx); +} + +void +_Jv_ClassReader::handleAnnotationElement() +{ + int tag = read1u(); + switch (tag) + { + case 'B': + case 'C': + case 'S': + case 'Z': + case 'I': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_Integer); + prepare_pool_entry (index, JV_CONSTANT_Integer); + } + break; + case 'D': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_Double); + prepare_pool_entry (index, JV_CONSTANT_Double); + } + break; + case 'F': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_Float); + prepare_pool_entry (index, JV_CONSTANT_Float); + } + break; + case 'J': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_Long); + prepare_pool_entry (index, JV_CONSTANT_Long); + } + break; + case 's': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_String); + prepare_pool_entry (index, JV_CONSTANT_String); + } + break; + + case 'e': + { + int type_name_index = read2u(); + int const_name_index = read2u (); + check_tag (type_name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (type_name_index, JV_CONSTANT_Utf8); + check_tag (const_name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (const_name_index, JV_CONSTANT_Utf8); + } + break; + case 'c': + { + int index = read2u(); + check_tag (index, JV_CONSTANT_Utf8); + prepare_pool_entry (index, JV_CONSTANT_Utf8); + } + break; + case '@': + handleAnnotation(); + break; + case '[': + { + int n_array_elts = read2u (); + for (int i = 0; i < n_array_elts; ++i) + handleAnnotationElement(); + } + break; + default: + throw_class_format_error ("invalid annotation element"); + } +} + +void +_Jv_ClassReader::handleAnnotation() +{ + int type_index = read2u(); + check_tag (type_index, JV_CONSTANT_Utf8); + prepare_pool_entry (type_index, JV_CONSTANT_Utf8); + + int npairs = read2u(); + for (int i = 0; i < npairs; ++i) + { + int name_index = read2u(); + check_tag (name_index, JV_CONSTANT_Utf8); + handleAnnotationElement(); + } +} + +void +_Jv_ClassReader::handleAnnotations() +{ + int num = read2u(); + while (num--) + handleAnnotation(); +} + +void +_Jv_ClassReader::handleMemberAnnotations(jv_attr_type member_type, + int member_index, + int len) +{ + // We're going to copy the bytes in verbatim. But first we want to + // make sure the attribute is well-formed, and we want to prepare + // the constant pool. So, we save our starting point. + int orig_pos = pos; + + handleAnnotations(); + // FIXME: check that we read all LEN bytes? + + ::java::io::DataOutputStream *stream = get_reflection_stream (); + stream->writeByte(member_type); + int newLen = len + 1; + if (member_type != JV_CLASS_ATTR) + newLen += 2; + stream->writeInt(newLen); + if (member_type != JV_CLASS_ATTR) + stream->writeShort(member_index); + stream->writeByte(JV_ANNOTATIONS_KIND); + // Write the data as-is. + stream->write(input_data, input_offset + orig_pos, len); +} + +void +_Jv_ClassReader::handleAnnotationDefault(int member_index, int len) +{ + int orig_pos = pos; + handleAnnotationElement(); + + ::java::io::DataOutputStream *stream = get_reflection_stream (); + stream->writeByte(JV_METHOD_ATTR); + stream->writeInt(len + 3); + stream->writeByte(JV_ANNOTATION_DEFAULT_KIND); + stream->writeShort(member_index); + stream->write(input_data, input_offset + orig_pos, len); +} + +void +_Jv_ClassReader::handleParameterAnnotations(int member_index, int len) +{ + int orig_pos = pos; + + int n_params = read1u(); + for (int i = 0; i < n_params; ++i) + handleAnnotations(); + + ::java::io::DataOutputStream *stream = get_reflection_stream (); + stream->writeByte(JV_METHOD_ATTR); + stream->writeByte(len + 3); + stream->writeByte(JV_PARAMETER_ANNOTATIONS_KIND); + stream->writeShort(member_index); + stream->write(input_data, input_offset + orig_pos, len); +} + void _Jv_ClassReader::read_constpool () { tags = (unsigned char*) _Jv_AllocBytes (pool_count); @@ -495,22 +754,23 @@ void _Jv_ClassReader::read_one_field_attribute (int field_index) || tags[cv] == JV_CONSTANT_Long || tags[cv] == JV_CONSTANT_Double || tags[cv] == JV_CONSTANT_String)) - { - handleConstantValueAttribute (field_index, cv); - } - else - { - throw_class_format_error ("erroneous ConstantValue attribute"); - } - - if (length != 2) + { + handleConstantValueAttribute (field_index, cv); + } + else + { throw_class_format_error ("erroneous ConstantValue attribute"); - } + } - else - { - skip (length); - } + if (length != 2) + throw_class_format_error ("erroneous ConstantValue attribute"); + } + else if (is_attribute_name (name, "Signature")) + handleGenericSignature(JV_FIELD_ATTR, field_index, length); + else if (is_attribute_name (name, "RuntimeVisibleAnnotations")) + handleMemberAnnotations(JV_FIELD_ATTR, field_index, length); + else + skip (length); } void _Jv_ClassReader::read_methods () @@ -634,7 +894,14 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index) if ((pos - start_off) != length) throw_class_format_error ("code attribute too short"); } - + else if (is_attribute_name (name, "Signature")) + handleGenericSignature(JV_METHOD_ATTR, method_index, length); + else if (is_attribute_name (name, "RuntimeVisibleAnnotations")) + handleMemberAnnotations(JV_METHOD_ATTR, method_index, length); + else if (is_attribute_name (name, "RuntimeVisibleParameterAnnotations")) + handleParameterAnnotations(method_index, length); + else if (is_attribute_name (name, "AnnotationDefault")) + handleAnnotationDefault(method_index, length); else { /* ignore unknown attributes */ @@ -684,6 +951,12 @@ void _Jv_ClassReader::read_one_class_attribute () def_interp->source_file_name = _Jv_NewStringUtf8Const (def->constants.data[source_index].utf8); } + else if (is_attribute_name (name, "Signature")) + handleGenericSignature(JV_CLASS_ATTR, 0, length); + else if (is_attribute_name (name, "EnclosingMethod")) + handleEnclosingMethod(length); + else if (is_attribute_name (name, "RuntimeVisibleAnnotations")) + handleMemberAnnotations(JV_CLASS_ATTR, 0, length); else { /* Currently, we ignore most class attributes. @@ -775,6 +1048,8 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag) { case JV_CONSTANT_Utf8: { + // FIXME: this is very wrong. + // If we came here, it is because some other tag needs this // utf8-entry for type information! Thus, we translate /'s to .'s in // order to accomondate gcj's internal representation. diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 22f3e4a6382..2a23853c83d 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -280,6 +280,9 @@ public: static void print_class_loaded (jclass); static void resolve_class_ref (jclass, jclass *); static void wait_for_state(jclass, int); + static _Jv_Method *resolve_method_entry (jclass, jclass &, + int, int, + bool, bool); static _Jv_word resolve_pool_entry (jclass, int, bool =false); static void resolve_field (_Jv_Field *, java::lang::ClassLoader *); static void verify_type_assertions (jclass); diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 0e5066fa9af..16073a4f387 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -192,6 +192,24 @@ struct _Jv_TypeAssertion _Jv_Utf8Const *op2; }; +typedef enum +{ + JV_CLASS_ATTR, + JV_METHOD_ATTR, + JV_FIELD_ATTR, + JV_DONE_ATTR +} jv_attr_type; + +typedef enum +{ + JV_INNER_CLASSES_KIND, + JV_ENCLOSING_METHOD_KIND, + JV_SIGNATURE_KIND, + JV_ANNOTATIONS_KIND, + JV_PARAMETER_ANNOTATIONS_KIND, + JV_ANNOTATION_DEFAULT_KIND +} jv_attr_kind; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -288,7 +306,6 @@ class java::io::VMObjectStreamClass; void _Jv_sharedlib_register_hook (jclass klass); - class java::lang::Class : public java::lang::Object { public: @@ -335,6 +352,15 @@ private: java::lang::reflect::Method *_getMethod (jstring, JArray *); java::lang::reflect::Method *_getDeclaredMethod (jstring, JArray *); + jstring getReflectionSignature (jint /*jv_attr_type*/ type, + jint obj_index); + jstring getReflectionSignature (::java::lang::reflect::Method *); + jstring getReflectionSignature (::java::lang::reflect::Constructor *); + jstring getReflectionSignature (::java::lang::reflect::Field *); + + jstring getClassSignature(); + jobject getMethodDefaultValue (::java::lang::reflect::Method *); + public: JArray *getFields (void); @@ -397,9 +423,17 @@ public: JArray *getTypeParameters (void); + jint getEnclosingMethodData(void); java::lang::Class *getEnclosingClass (void); java::lang::reflect::Constructor *getEnclosingConstructor (void); java::lang::reflect::Method *getEnclosingMethod (void); + jobjectArray getDeclaredAnnotations(jint, jint, jint); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Method *, + jboolean); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Constructor *, + jboolean); + jobjectArray getDeclaredAnnotations(::java::lang::reflect::Field *); + JArray< ::java::lang::annotation::Annotation *> *getDeclaredAnnotationsInternal(); // FIXME: this probably shouldn't be public. jint size (void) @@ -554,6 +588,10 @@ private: friend void ::_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); + friend class java::lang::reflect::Field; + friend class java::lang::reflect::Method; + friend class java::lang::reflect::Constructor; + // Chain for class pool. This also doubles as the ABI version // number. It is only used for this purpose at class registration // time, and only for precompiled classes. @@ -636,6 +674,8 @@ private: void *aux_info; // Execution engine. _Jv_ExecutionEngine *engine; + // Reflection data. + unsigned char *reflection_data; }; // Inline functions that are friends of java::lang::Class diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 580c3391d4c..66d0d2172b1 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -38,6 +38,7 @@ exception statement from your version. */ package java.lang; +import gnu.java.lang.reflect.ClassSignatureParser; import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Constructor; @@ -53,6 +54,8 @@ import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.lang.reflect.AnnotatedElement; +import java.lang.annotation.Annotation; /** * A Class represents a Java type. There will never be multiple Class @@ -83,7 +86,8 @@ import java.util.HashSet; * @since 1.0 * @see ClassLoader */ -public final class Class implements Type, GenericDeclaration, Serializable +public final class Class + implements Type, AnnotatedElement, GenericDeclaration, Serializable { /** * Class is non-instantiable from Java code; only the VM can create @@ -932,6 +936,56 @@ public final class Class implements Type, GenericDeclaration, Serializable /** + *

+ * Casts this class to represent a subclass of the specified class. + * This method is useful for `narrowing' the type of a class so that + * the class object, and instances of that class, can match the contract + * of a more restrictive method. For example, if this class has the + * static type of Class<Object>, and a dynamic type of + * Class<Rectangle>, then, assuming Shape is + * a superclass of Rectangle, this method can be used on + * this class with the parameter, Class<Shape>, to retain + * the same instance but with the type + * Class<? extends Shape>. + *

+ *

+ * If this class can be converted to an instance which is parameterised + * over a subtype of the supplied type, U, then this method + * returns an appropriately cast reference to this object. Otherwise, + * a ClassCastException is thrown. + *

+ * + * @param klass the class object, the parameterized type (U) of + * which should be a superclass of the parameterized type of + * this instance. + * @return a reference to this object, appropriately cast. + * @throws ClassCastException if this class can not be converted to one + * which represents a subclass of the specified + * type, U. + * @since 1.5 + */ + public Class asSubclass(Class klass) + { + if (! klass.isAssignableFrom(this)) + throw new ClassCastException(); + return (Class) this; + } + + /** + * Returns the specified object, cast to this Class' type. + * + * @param obj the object to cast + * @throws ClassCastException if obj is not an instance of this class + * @since 1.5 + */ + public T cast(Object obj) + { + if (obj != null && ! isInstance(obj)) + throw new ClassCastException(); + return (T) obj; + } + + /** * Returns the enumeration constants of this class, or * null if this class is not an Enum. * @@ -1039,11 +1093,7 @@ public final class Class implements Type, GenericDeclaration, Serializable * a top-level class. * @since 1.5 */ - public Class getEnclosingClass() - { - // FIXME write real implementation - return null; - } + public native Class getEnclosingClass(); /** * Returns the constructor which immediately encloses this class. If @@ -1056,11 +1106,7 @@ public final class Class implements Type, GenericDeclaration, Serializable * is returned. * @since 1.5 */ - public Constructor getEnclosingConstructor() - { - // FIXME write real implementation - return null; - } + public native Constructor getEnclosingConstructor(); /** * Returns the method which immediately encloses this class. If @@ -1073,10 +1119,100 @@ public final class Class implements Type, GenericDeclaration, Serializable * is returned. * @since 1.5 */ - public Method getEnclosingMethod() + public native Method getEnclosingMethod(); + + private native String getClassSignature(); + + /** + *

+ * Returns an array of Type objects which represent the + * interfaces directly implemented by this class or extended by this + * interface. + *

+ *

+ * If one of the superinterfaces is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the ParameterizedType + * interface, and only if an instance has not already been created. + *

+ *

+ * The order of the interfaces in the array matches the order in which + * the interfaces are declared. For classes which represent an array, + * an array of two interfaces, Cloneable and + * Serializable, is always returned, with the objects in + * that order. A class representing a primitive type or void always + * returns an array of zero size. + *

+ * + * @return an array of interfaces implemented or extended by this class. + * @throws GenericSignatureFormatError if the generic signature of one + * of the interfaces does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if any of the superinterfaces refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if any of the interfaces + * refer to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type[] getGenericInterfaces() { - // FIXME write real implementation - return null; + if (isPrimitive()) + return new Type[0]; + + String sig = getClassSignature(); + if (sig == null) + return getInterfaces(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getInterfaceTypes(); + } + + /** + *

+ * Returns a Type object representing the direct superclass, + * whether class, interface, primitive type or void, of this class. + * If this class is an array class, then a class instance representing + * the Object class is returned. If this class is primitive, + * an interface, or a representation of either the Object + * class or void, then null is returned. + *

+ *

+ * If the superclass is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the ParameterizedType + * interface, and only if an instance has not already been created. + *

+ * + * @return the superclass of this class. + * @throws GenericSignatureFormatError if the generic signature of the + * class does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if the superclass refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if the superclass + * refers to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type getGenericSuperclass() + { + if (isArray()) + return Object.class; + + if (isPrimitive() || isInterface() || this == Object.class) + return null; + + String sig = getClassSignature(); + if (sig == null) + return getSuperclass(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getSuperclassType(); } /** @@ -1085,7 +1221,7 @@ public final class Class implements Type, GenericDeclaration, Serializable * An array of size zero is returned if this class has no type * variables. * - * @return the type variables associated with this class. + * @return the type variables associated with this class. * @throws GenericSignatureFormatError if the generic signature does * not conform to the format specified in the Virtual Machine * specification, version 3. @@ -1093,7 +1229,91 @@ public final class Class implements Type, GenericDeclaration, Serializable */ public TypeVariable>[] getTypeParameters() { - // FIXME - provide real implementation. - return new TypeVariable[0]; + String sig = getClassSignature(); + if (sig == null) + return (TypeVariable>[])new TypeVariable[0]; + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Returns this class' annotation for the specified annotation type, + * or null if no such annotation exists. + * + * @param annotationClass the type of annotation to look for. + * @return this class' annotation for the specified type, or + * null if no such annotation exists. + * @since 1.5 + */ + public A getAnnotation(Class annotationClass) + { + A foundAnnotation = null; + Annotation[] annotations = getAnnotations(); + for (Annotation annotation : annotations) + if (annotation.annotationType() == annotationClass) + foundAnnotation = (A) annotation; + return foundAnnotation; + } + + /** + * Returns all annotations associated with this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return this class' annotations. + * @since 1.5 + */ + public Annotation[] getAnnotations() + { + HashSet set = new HashSet(); + set.addAll(Arrays.asList(getDeclaredAnnotations())); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].getAnnotations())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.getAnnotations())); + return set.toArray(new Annotation[set.size()]); + } + + /** + * Returns all annotations directly defined by this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return the annotations directly defined by this class. + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; } + + private native Annotation[] getDeclaredAnnotationsInternal(); + + /** + * Returns true if an annotation for the specified type is associated + * with this class. This is primarily a short-hand for using marker + * annotations. + * + * @param annotationClass the type of annotation to look for. + * @return true if an annotation exists for the specified type. + * @since 1.5 + */ + public boolean isAnnotationPresent(Class + annotationClass) + { + return getAnnotation(annotationClass) != null; + } + } diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 40f9961ebb6..dc59bea1313 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -56,6 +56,18 @@ details. */ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -851,6 +863,526 @@ java::lang::Class::setSigners(JArray *s) +static unsigned char +read_u1 (unsigned char *&p) +{ + return *p++; +} + +static unsigned char +read_u1 (unsigned char *&p, unsigned char *next) +{ + if (next - p < 1) + throw new java::lang::InternalError(); + return *p++; +} + +static unsigned int +read_u2 (unsigned char *&p) +{ + unsigned int b1 = *p++; + unsigned int b2 = *p++; + return (b1 << 8) | b2; +} + +static unsigned int +read_u2 (unsigned char *&p, unsigned char *next) +{ + if (next - p < 2) + throw new java::lang::InternalError(); + return read_u2 (p); +} + +static int +read_4 (unsigned char *&p) +{ + int b1 = *p++; + int b2 = *p++; + int b3 = *p++; + int b4 = *p++; + return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; +} + +jstring +java::lang::Class::getReflectionSignature (jint /*jv_attr_type*/ type, + jint obj_index) +{ + // We just re-parse the bytecode for this data each time. If + // necessary we can cache results, but I suspect this is not + // performance sensitive. + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return NULL; + while (true) + { + int kind = read_u1 (bytes); + if (kind == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (kind != type) + { + bytes = next; + continue; + } + if (type != JV_CLASS_ATTR) + { + unsigned short index = read_u2 (bytes, next); + if (index != obj_index) + { + bytes = next; + continue; + } + } + int nt = read_u1 (bytes, next); + if (nt != JV_SIGNATURE_KIND) + { + bytes = next; + continue; + } + unsigned int cpool_idx = read_u2 (bytes, next); + if (cpool_idx >= (unsigned int) constants.size + || constants.tags[cpool_idx] != JV_CONSTANT_Utf8) + { + // We just ignore errors for now. It isn't clear what is + // best to do here, as an encoding error here means a bug + // either in the compiler or in defineclass.cc. + return NULL; + } + return _Jv_NewStringUtf8Const (constants.data[cpool_idx].utf8); + } +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Constructor *c) +{ + _Jv_Method *meth = _Jv_FromReflectedConstructor (c); + unsigned short meth_index = meth - methods; + return getReflectionSignature (JV_METHOD_ATTR, meth_index); +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Method *m) +{ + _Jv_Method *meth = _Jv_FromReflectedMethod (m); + unsigned short meth_index = meth - methods; + return getReflectionSignature (JV_METHOD_ATTR, meth_index); +} + +jstring +java::lang::Class::getReflectionSignature (::java::lang::reflect::Field *f) +{ + _Jv_Field *fld = _Jv_FromReflectedField (f); + unsigned short fld_index = fld - fields; + return getReflectionSignature (JV_FIELD_ATTR, fld_index); +} + +jstring +java::lang::Class::getClassSignature() +{ + return getReflectionSignature (JV_CLASS_ATTR, 0); +} + +jint +java::lang::Class::getEnclosingMethodData() +{ + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + while (true) + { + int kind = read_u1 (bytes); + if (kind == JV_DONE_ATTR) + return 0; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (kind != JV_CLASS_ATTR) + { + bytes = next; + continue; + } + int type = read_u1 (bytes, next); + if (type != JV_ENCLOSING_METHOD_KIND) + { + bytes = next; + continue; + } + int class_index = read_u2 (bytes, next); + int method_index = read_u2 (bytes, next); + _Jv_word result; + _Jv_storeIndexes (&result, class_index, method_index); + return result.i; + } +} + +jclass +java::lang::Class::getEnclosingClass() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + return NULL; + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + return _Jv_Linker::resolve_pool_entry (this, class_index).clazz; +} + +::java::lang::reflect::Method * +java::lang::Class::getEnclosingMethod() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + return NULL; + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + jclass found_class; + _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, + class_index, + method_index, + false, false); + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char *) method - (char *) found_class->methods; + rmethod->declaringClass = found_class; + return rmethod; +} + +::java::lang::reflect::Constructor * +java::lang::Class::getEnclosingConstructor() +{ + _Jv_word indexes; + indexes.i = getEnclosingMethodData(); + if (indexes.i == 0) + return NULL; + _Jv_ushort class_index, method_index; + _Jv_loadIndexes (&indexes, class_index, method_index); + jclass found_class; + _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class, + class_index, + method_index, + false, false); + using namespace java::lang::reflect; + Constructor *cons = new Constructor (); + cons->offset = (char *) method - (char *) found_class->methods; + cons->declaringClass = this; + return cons; +} + +static void +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(); +} + +// Forward declaration +static ::java::lang::annotation::Annotation * +parseAnnotation(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last); + +static jobject +parseAnnotationElement(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int tag = read_u1 (bytes, last); + jobject result; + switch (tag) + { + case 'B': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Byte::valueOf (pool->data[cindex].i); + } + break; + case 'C': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Character::valueOf (pool->data[cindex].i); + } + break; + case 'S': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Short::valueOf (pool->data[cindex].i); + } + break; + case 'Z': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Boolean::valueOf (jboolean (pool->data[cindex].i)); + } + break; + case 'I': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Integer); + result = Integer::valueOf (pool->data[cindex].i); + } + break; + case 'D': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Double); + _Jv_word2 word; + memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); + result = Double::valueOf (word.d); + } + break; + case 'F': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Float); + result = Float::valueOf (pool->data[cindex].f); + } + break; + case 'J': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Double); + _Jv_word2 word; + memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word)); + result = Long::valueOf (word.l); + } + break; + case 's': + { + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_String); + result = _Jv_Linker::resolve_pool_entry (klass, cindex).string; + } + break; + case 'e': + { + // FIXME +// uint16 type_name_index = JCF_readu2 (jcf); +// uint16 const_name_index = JCF_readu2 (jcf); + } + break; + case 'c': + { + // FIXME: should be a Utf8 here! + int cindex = read_u2 (bytes, last); + check_constant (pool, cindex, JV_CONSTANT_Class); + try + { + result + = _Jv_Linker::resolve_pool_entry (klass, cindex, false).clazz; + } + catch (NoClassDefFoundError *err) + { + throw new TypeNotPresentException(err->getMessage(), err); + } + } + break; + case '@': + result = parseAnnotation (klass, pool, bytes, last); + break; + case '[': + { + int n_array_elts = read_u2 (bytes, last); + jobjectArray aresult = _Jv_NewObjectArray (n_array_elts, + &Object::class$, NULL); + jobject *elts = elements (aresult); + for (int i = 0; i < n_array_elts; ++i) + elts[i] = parseAnnotationElement(klass, pool, bytes, last); + result = aresult; + } + break; + default: + throw new java::lang::InternalError(); + } + return result; +} + +static ::java::lang::annotation::Annotation * +parseAnnotation(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int type_index = read_u2 (bytes, last); + check_constant (pool, type_index, JV_CONSTANT_Utf8); + jclass anno_class = NULL; // FIXME ... and share code with 'c' case + + ::java::util::HashMap *hmap = new ::java::util::HashMap(); + int npairs = read_u2 (bytes, last); + for (int i = 0; i < npairs; ++i) + { + int name_index = read_u2 (bytes, last); + check_constant (pool, name_index, JV_CONSTANT_Utf8); + jstring name = _Jv_NewStringUtf8Const (pool->data[name_index].utf8); + jobject value = parseAnnotationElement (klass, pool, bytes, last); + // FIXME: any checks needed for name? + hmap->put(name, value); + } + // FIXME: use AnnotationInvocationHandler here. + // FIXME: add a static method to it for creation, that handles defaults. + return NULL; +} + +static jobjectArray +parseAnnotations(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + int num = read_u2 (bytes, last); + jobjectArray result = _Jv_NewObjectArray (num, + &::java::lang::annotation::Annotation::class$, + NULL); + jobject *elts = elements (result); + for (int i = 0; i < num; ++i) + elts[i] = parseAnnotation(klass, pool, bytes, last); + return result; +} + +static jobjectArray +parseParameterAnnotations(jclass klass, _Jv_Constants *pool, + unsigned char *&bytes, unsigned char *last) +{ + jclass anno = &::java::lang::annotation::Annotation::class$; + jclass annoary = _Jv_GetArrayClass (anno, anno->getClassLoaderInternal()); + + // FIXME: something should check the number of params versus the + // method + int n_params = read_u1 (bytes, last); + jobjectArray result = _Jv_NewObjectArray (n_params, annoary, NULL); + jobject *elts = elements (result); + for (int i = 0; i < n_params; ++i) + elts[i] = parseAnnotations(klass, pool, bytes, last); + return result; +} + +jobject +java::lang::Class::getMethodDefaultValue(::java::lang::reflect::Method *meth) +{ + // FIXME: could cache the value here... + + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + + unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; + + while (true) + { + int kind = read_u1 (bytes); + if (kind == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (kind != JV_METHOD_ATTR) + { + bytes = next; + continue; + } + int type = read_u1 (bytes, next); + if (type != JV_ANNOTATION_DEFAULT_KIND) + { + bytes = next; + continue; + } + int index = read_u2 (bytes, next); + if (meth_index != index) + { + bytes = next; + continue; + } + + // FIXME: could cache here. If we do then we have to clone any + // array result. + return parseAnnotationElement(this, &this->constants, bytes, next); + } +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(jint /* jv_attr_type */ member_type, + jint member_index, + jint /* jv_attr_kind */ kind_req) +{ + // FIXME: could cache the value here... + + unsigned char *bytes = reflection_data; + if (bytes == NULL) + return 0; + + while (true) + { + int type = read_u1 (bytes); + if (type == JV_DONE_ATTR) + return NULL; + int len = read_4 (bytes); + unsigned char *next = bytes + len; + if (type != member_type) + { + bytes = next; + continue; + } + int kind = read_u1 (bytes, next); + if (kind != kind_req) + { + bytes = next; + continue; + } + if (member_type != JV_CLASS_ATTR) + { + int index = read_u2 (bytes, next); + if (member_index != index) + { + bytes = next; + continue; + } + } + + // FIXME: could cache here. If we do then we have to clone any + // array result. + if (kind_req == JV_PARAMETER_ANNOTATIONS_KIND) + return parseParameterAnnotations (this, &this->constants, bytes, next); + return parseAnnotations (this, &this->constants, bytes, next); + } +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Method *meth, + jboolean is_param) +{ + unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods; + return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, + (is_param + ? JV_PARAMETER_ANNOTATIONS_KIND + : JV_ANNOTATIONS_KIND)); +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Constructor *cons, + jboolean is_param) +{ + unsigned short meth_index = _Jv_FromReflectedConstructor (cons) - methods; + return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index, + (is_param + ? JV_PARAMETER_ANNOTATIONS_KIND + : JV_ANNOTATIONS_KIND)); +} + +jobjectArray +java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Field *fld) +{ + unsigned short field_index = _Jv_FromReflectedField (fld) - fields; + return getDeclaredAnnotations(JV_FIELD_ATTR, field_index, + JV_ANNOTATIONS_KIND); +} + +JArray< ::java::lang::annotation::Annotation *> * +java::lang::Class::getDeclaredAnnotationsInternal() +{ + return (JArray< ::java::lang::annotation::Annotation *> *) getDeclaredAnnotations(JV_CLASS_ATTR, 0, JV_ANNOTATIONS_KIND); +} + + + // // Some class-related convenience functions. // diff --git a/libjava/java/lang/reflect/Constructor.java b/libjava/java/lang/reflect/Constructor.java index 98b0d1d46f0..42f3e0281e4 100644 --- a/libjava/java/lang/reflect/Constructor.java +++ b/libjava/java/lang/reflect/Constructor.java @@ -40,6 +40,7 @@ exception statement from your version. */ package java.lang.reflect; import gnu.java.lang.reflect.MethodSignatureParser; +import java.lang.annotation.Annotation; /** * The Constructor class represents a constructor of a class. It also allows @@ -235,8 +236,8 @@ public final class Constructor extends AccessibleObject return b.toString(); } - /* FIXME[GENERICS]: Add X extends GenericDeclaration and TypeVariable */ - static void addTypeParameters(StringBuilder sb, TypeVariable[] typeArgs) + static + void addTypeParameters(StringBuilder sb, TypeVariable[] typeArgs) { if (typeArgs.length == 0) return; @@ -333,11 +334,7 @@ public final class Constructor extends AccessibleObject * Return the String in the Signature attribute for this constructor. If there * is no Signature attribute, return null. */ - private String getSignature() - { - // FIXME: libgcj doesn't record this information yet. - return null; - } + private native String getSignature(); /** * Returns an array of Type objects that represents @@ -381,6 +378,27 @@ public final class Constructor extends AccessibleObject return p.getGenericParameterTypes(); } + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + public Annotation[][] getParameterAnnotations() + { + // FIXME: should check that we have the right number + // of parameters ...? + Annotation[][] result = getParameterAnnotationsInternal(); + if (result == null) + result = new Annotation[0][0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + private native Annotation[][] getParameterAnnotationsInternal(); + // Update cached values from method descriptor in class. private native void getType (); diff --git a/libjava/java/lang/reflect/Field.java b/libjava/java/lang/reflect/Field.java index 134ff132ecf..a501260220b 100644 --- a/libjava/java/lang/reflect/Field.java +++ b/libjava/java/lang/reflect/Field.java @@ -41,6 +41,7 @@ package java.lang.reflect; import gnu.java.lang.ClassHelper; import gnu.java.lang.reflect.FieldSignatureParser; +import java.lang.annotation.Annotation; /** * The Field class represents a member variable of a class. It also allows @@ -104,7 +105,7 @@ public final class Field * is a non-inherited member. * @return the class that declared this member */ - public Class getDeclaringClass() + public Class getDeclaringClass() { return declaringClass; } @@ -158,7 +159,7 @@ public final class Field * Gets the type of this field. * @return the type of this field */ - public native Class getType(); + public native Class getType(); /** * Compare two objects to see if they are semantically equivalent. @@ -733,15 +734,21 @@ public final class Field return p.getFieldType(); } + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + /** * Return the String in the Signature attribute for this field. If there * is no Signature attribute, return null. */ - private String getSignature() - { - // FIXME: libgcj doesn't record Signature attributes yet. - return null; - } + private native String getSignature(); native void setByte (Class caller, Object obj, byte b, boolean checkFinal) throws IllegalArgumentException, IllegalAccessException; diff --git a/libjava/java/lang/reflect/Method.java b/libjava/java/lang/reflect/Method.java index 58a6c924803..c13dd88d293 100644 --- a/libjava/java/lang/reflect/Method.java +++ b/libjava/java/lang/reflect/Method.java @@ -12,6 +12,7 @@ package java.lang.reflect; import gnu.gcj.RawData; import gnu.java.lang.reflect.MethodSignatureParser; +import java.lang.annotation.Annotation; /** * The Method class represents a member method of a class. It also allows @@ -132,7 +133,7 @@ public final class Method * Gets the return type of this method. * @return the type of this method */ - public Class getReturnType () + public Class getReturnType () { if (return_type == null) getType(); @@ -145,11 +146,11 @@ public final class Method * * @return a list of the types of the method's parameters */ - public Class[] getParameterTypes () + public Class[] getParameterTypes () { if (parameter_types == null) getType(); - return (Class[]) parameter_types.clone(); + return (Class[]) parameter_types.clone(); } /** @@ -159,11 +160,11 @@ public final class Method * * @return a list of the types in the method's throws clause */ - public Class[] getExceptionTypes () + public Class[] getExceptionTypes () { if (exception_types == null) getType(); - return (Class[]) exception_types.clone(); + return (Class[]) exception_types.clone(); } /** @@ -325,8 +326,7 @@ public final class Method * specification, version 3. * @since 1.5 */ - /* FIXME[GENERICS]: Should be TypeVariable[] */ - public TypeVariable[] getTypeParameters() + public TypeVariable[] getTypeParameters() { String sig = getSignature(); if (sig == null) @@ -339,11 +339,7 @@ public final class Method * Return the String in the Signature attribute for this method. If there * is no Signature attribute, return null. */ - private String getSignature() - { - // FIXME: libgcj doesn't record this information yet. - return null; - } + private native String getSignature(); /** * Returns an array of Type objects that represents @@ -405,6 +401,40 @@ public final class Method return p.getGenericReturnType(); } + /** + * If this method is an annotation method, returns the default + * value for the method. If there is no default value, or if the + * method is not a member of an annotation type, returns null. + * Primitive types are wrapped. + * + * @throws TypeNotPresentException if the method returns a Class, + * and the class cannot be found + * + * @since 1.5 + */ + public native Object getDefaultValue(); + + public Annotation[] getDeclaredAnnotations() + { + Annotation[] result = getDeclaredAnnotationsInternal(); + if (result == null) + result = new Annotation[0]; + return result; + } + + public Annotation[][] getParameterAnnotations() + { + // FIXME: should check that we have the right number + // of parameters ...? + Annotation[][] result = getParameterAnnotationsInternal(); + if (result == null) + result = new Annotation[0][0]; + return result; + } + + private native Annotation[] getDeclaredAnnotationsInternal(); + private native Annotation[][] getParameterAnnotationsInternal(); + private native void getType (); // Append a class name to a string buffer. We try to print the diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc index 35cf7f817ef..d04031f8d4b 100644 --- a/libjava/java/lang/reflect/natConstructor.cc +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -23,12 +23,35 @@ details. */ #include #include +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; +typedef JArray< JArray< ::java::lang::annotation::Annotation * > *> * anno_aa_t; + jint java::lang::reflect::Constructor::getModifiersInternal () { return _Jv_FromReflectedConstructor (this)->accflags; } +jstring +java::lang::reflect::Constructor::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +anno_a_t +java::lang::reflect::Constructor::getDeclaredAnnotationsInternal() +{ + anno_a_t result; + return (anno_a_t) declaringClass->getDeclaredAnnotations(this, false); +} + +anno_aa_t +java::lang::reflect::Constructor::getParameterAnnotationsInternal() +{ + anno_aa_t result; + return (anno_aa_t) declaringClass->getDeclaredAnnotations(this, true); +} + void java::lang::reflect::Constructor::getType () { diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index ae68639065b..e77b315f2a5 100644 --- a/libjava/java/lang/reflect/natField.cc +++ b/libjava/java/lang/reflect/natField.cc @@ -29,6 +29,8 @@ details. */ #include #include +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; + jint java::lang::reflect::Field::getModifiersInternal () { @@ -36,6 +38,19 @@ java::lang::reflect::Field::getModifiersInternal () } jstring +java::lang::reflect::Field::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +anno_a_t +java::lang::reflect::Field::getDeclaredAnnotationsInternal() +{ + anno_a_t result; + return (anno_a_t) declaringClass->getDeclaredAnnotations(this); +} + +jstring java::lang::reflect::Field::getName () { if (name == NULL) diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index eb7170a02be..26aa2a34a0e 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -48,6 +48,11 @@ details. */ #include #endif +typedef JArray< ::java::lang::annotation::Annotation * > * anno_a_t; +typedef JArray< JArray< ::java::lang::annotation::Annotation * > *> * anno_aa_t; + + + struct cpair { jclass prim; @@ -189,6 +194,32 @@ java::lang::reflect::Method::getModifiersInternal () } jstring +java::lang::reflect::Method::getSignature() +{ + return declaringClass->getReflectionSignature (this); +} + +jobject +java::lang::reflect::Method::getDefaultValue() +{ + return declaringClass->getMethodDefaultValue(this); +} + +anno_a_t +java::lang::reflect::Method::getDeclaredAnnotationsInternal() +{ + anno_a_t result; + return (anno_a_t) declaringClass->getDeclaredAnnotations(this, false); +} + +anno_aa_t +java::lang::reflect::Method::getParameterAnnotationsInternal() +{ + anno_aa_t result; + return (anno_aa_t) declaringClass->getDeclaredAnnotations(this, true); +} + +jstring java::lang::reflect::Method::getName () { if (name == NULL) diff --git a/libjava/link.cc b/libjava/link.cc index 7b532f9aee4..4e0eef1817d 100644 --- a/libjava/link.cc +++ b/libjava/link.cc @@ -266,6 +266,114 @@ _Jv_Linker::find_field (jclass klass, jclass owner, return the_field; } +_Jv_Method * +_Jv_Linker::resolve_method_entry (jclass klass, jclass &found_class, + int class_index, int name_and_type_index, + bool init, bool is_iface) +{ + _Jv_Constants *pool = &klass->constants; + jclass owner = resolve_pool_entry (klass, class_index).clazz; + + if (init && owner != klass) + _Jv_InitClass (owner); + + _Jv_ushort name_index, type_index; + _Jv_loadIndexes (&pool->data[name_and_type_index], + name_index, + type_index); + + _Jv_Utf8Const *method_name = pool->data[name_index].utf8; + _Jv_Utf8Const *method_signature = pool->data[type_index].utf8; + + _Jv_Method *the_method = 0; + found_class = 0; + + // We're going to cache a pointer to the _Jv_Method object + // when we find it. So, to ensure this doesn't get moved from + // beneath us, we first put all the needed Miranda methods + // into the target class. + wait_for_state (klass, JV_STATE_LOADED); + + // First search the class itself. + the_method = search_method_in_class (owner, klass, + method_name, method_signature); + + if (the_method != 0) + { + found_class = owner; + goto end_of_method_search; + } + + // If we are resolving an interface method, search the + // interface's superinterfaces (A superinterface is not an + // interface's superclass - a superinterface is implemented by + // the interface). + if (is_iface) + { + _Jv_ifaces ifaces; + ifaces.count = 0; + ifaces.len = 4; + ifaces.list = (jclass *) _Jv_Malloc (ifaces.len + * sizeof (jclass *)); + + get_interfaces (owner, &ifaces); + + for (int i = 0; i < ifaces.count; i++) + { + jclass cls = ifaces.list[i]; + the_method = search_method_in_class (cls, klass, method_name, + method_signature); + if (the_method != 0) + { + found_class = cls; + break; + } + } + + _Jv_Free (ifaces.list); + + if (the_method != 0) + goto end_of_method_search; + } + + // Finally, search superclasses. + for (jclass cls = owner->getSuperclass (); cls != 0; + cls = cls->getSuperclass ()) + { + the_method = search_method_in_class (cls, klass, method_name, + method_signature); + if (the_method != 0) + { + found_class = cls; + break; + } + } + + end_of_method_search: + + // FIXME: if (cls->loader != klass->loader), then we + // must actually check that the types of arguments + // correspond. That is, for each argument type, and + // the return type, doing _Jv_FindClassFromSignature + // with either loader should produce the same result, + // i.e., exactly the same jclass object. JVMS 5.4.3.3 + + if (the_method == 0) + { + java::lang::StringBuffer *sb = new java::lang::StringBuffer(); + sb->append(JvNewStringLatin1("method ")); + sb->append(owner->getName()); + sb->append(JvNewStringLatin1(".")); + sb->append(_Jv_NewStringUTF(method_name->chars())); + sb->append(JvNewStringLatin1(" with signature ")); + sb->append(_Jv_NewStringUTF(method_signature->chars())); + sb->append(JvNewStringLatin1(" was not found.")); + throw new java::lang::NoSuchMethodError (sb->toString()); + } + + return the_method; +} + _Jv_word _Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy) { @@ -399,105 +507,14 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy) _Jv_loadIndexes (&pool->data[index], class_index, name_and_type_index); - jclass owner = (resolve_pool_entry (klass, class_index)).clazz; - - if (owner != klass) - _Jv_InitClass (owner); - - _Jv_ushort name_index, type_index; - _Jv_loadIndexes (&pool->data[name_and_type_index], - name_index, - type_index); - - _Jv_Utf8Const *method_name = pool->data[name_index].utf8; - _Jv_Utf8Const *method_signature = pool->data[type_index].utf8; - - _Jv_Method *the_method = 0; - jclass found_class = 0; - // We're going to cache a pointer to the _Jv_Method object - // when we find it. So, to ensure this doesn't get moved from - // beneath us, we first put all the needed Miranda methods - // into the target class. - wait_for_state (klass, JV_STATE_LOADED); - - // First search the class itself. - the_method = search_method_in_class (owner, klass, - method_name, method_signature); - - if (the_method != 0) - { - found_class = owner; - goto end_of_method_search; - } - - // If we are resolving an interface method, search the - // interface's superinterfaces (A superinterface is not an - // interface's superclass - a superinterface is implemented by - // the interface). - if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) - { - _Jv_ifaces ifaces; - ifaces.count = 0; - ifaces.len = 4; - ifaces.list = (jclass *) _Jv_Malloc (ifaces.len - * sizeof (jclass *)); - - get_interfaces (owner, &ifaces); - - for (int i = 0; i < ifaces.count; i++) - { - jclass cls = ifaces.list[i]; - the_method = search_method_in_class (cls, klass, method_name, - method_signature); - if (the_method != 0) - { - found_class = cls; - break; - } - } - - _Jv_Free (ifaces.list); - - if (the_method != 0) - goto end_of_method_search; - } - - // Finally, search superclasses. - for (jclass cls = owner->getSuperclass (); cls != 0; - cls = cls->getSuperclass ()) - { - the_method = search_method_in_class (cls, klass, method_name, - method_signature); - if (the_method != 0) - { - found_class = cls; - break; - } - } + _Jv_Method *the_method; + jclass found_class; + the_method = resolve_method_entry (klass, found_class, + class_index, name_and_type_index, + true, + pool->tags[index] == JV_CONSTANT_InterfaceMethodref); - end_of_method_search: - - // FIXME: if (cls->loader != klass->loader), then we - // must actually check that the types of arguments - // correspond. That is, for each argument type, and - // the return type, doing _Jv_FindClassFromSignature - // with either loader should produce the same result, - // i.e., exactly the same jclass object. JVMS 5.4.3.3 - - if (the_method == 0) - { - java::lang::StringBuffer *sb = new java::lang::StringBuffer(); - sb->append(JvNewStringLatin1("method ")); - sb->append(owner->getName()); - sb->append(JvNewStringLatin1(".")); - sb->append(_Jv_NewStringUTF(method_name->chars())); - sb->append(JvNewStringLatin1(" with signature ")); - sb->append(_Jv_NewStringUTF(method_signature->chars())); - sb->append(JvNewStringLatin1(" was not found.")); - throw new java::lang::NoSuchMethodError (sb->toString()); - } - pool->data[index].rmethod = klass->engine->resolve_method(the_method, found_class, -- 2.11.4.GIT