[ecj] Implement signatures for Class.getEnclosingMethod() et al

Andrew Haley aph@redhat.com
Mon Nov 6 15:32:00 GMT 2006


Internal handling for a bunch of reflection methods.
Class.getEnclosingMethod(), Class.getGenericXX, and so on.

Andrew.


2006-11-06  Andrew Haley  <aph@redhat.com>

        * java-tree.h (CONSTANT_LazyFlag): New.
        * constants.c (build_constants_constructor): Mask CONSTANT_LazyFlag.
        * jcf-parse.c (handle_innerclass_attribute): Write attribute to
        reflection_data.
        (handle_constant): Return 0 for dummy cpool entries.
        Handle constants of kind Class.
        Handle constants of kind NameAndType.
        (handle_enclosingmethod_attribute): New.
        (handle_signature_attribute): New.
        (HANDLE_ENCLOSINGMETHOD_ATTRIBUTE): New.
        (HANDLE_SIGNATURE_ATTRIBUTE): New.
        (handle_constant): Use unmangle_classname()rather than calling
        identifier_subst() directly.

Index: java/jcf-parse.c
===================================================================
--- java/jcf-parse.c	(revision 118395)
+++ java/jcf-parse.c	(working copy)
@@ -104,7 +104,7 @@
 bitmap_obstack bit_obstack;
 
 /* Declarations of some functions used here.  */
-static void handle_innerclass_attribute (int count, JCF *);
+static void handle_innerclass_attribute (int count, JCF *, int len);
 static tree give_name_to_class (JCF *jcf, int index);
 static char *compute_class_name (struct ZipDirectory *zdir);
 static int classify_zip_file (struct ZipDirectory *zdir);
@@ -517,12 +517,15 @@
   enum cpool_tag kind;
   CPool *cpool = cpool_for_class (output_class);
   
+  if (index == 0)
+    return 0;
+
   if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
     error ("<constant pool index %d not in range>", index);
   
   kind = JPOOL_TAG (jcf, index);
 
-  if (kind != purpose)
+  if ((kind & ~CONSTANT_ResolvedFlag) != purpose)
     {
       if (purpose == CONSTANT_Class
 	  && kind == CONSTANT_Utf8)
@@ -533,19 +536,36 @@
 
   switch (kind)
     {
+    case CONSTANT_Class:
+    case CONSTANT_ResolvedClass:
+      {
+	/* For some reason I know not the what of, class names in
+	   annotations are UTF-8 strings in the constant pool but
+	   class names in EnclosingMethod attributes are real class
+	   references.  Set CONSTANT_LazyFlag here so that the VM
+	   doesn't attempt to resolve them at class initialization
+	   time.  */
+	tree resolved_class, class_name;
+	resolved_class = get_class_constant (jcf, index);
+	class_name = build_internal_class_name (resolved_class);
+	index = alloc_name_constant (CONSTANT_Class | CONSTANT_LazyFlag,
+				     (unmangle_classname 
+				      (IDENTIFIER_POINTER(class_name),
+				       IDENTIFIER_LENGTH(class_name))));
+	break;
+      }
     case CONSTANT_Utf8:
       {
 	tree utf8 = get_constant (jcf, index);
-
 	if (purpose == CONSTANT_Class)
-	  /* Create a constant pool entry for a type.  This one has
-	     '.' rather than '/' because it isn't going into a class
-	     file, it's going into a compiled object.
+	  /* Create a constant pool entry for a type signature.  This
+	     one has '.' rather than '/' because it isn't going into a
+	     class file, it's going into a compiled object.
 	     
 	     This has to match the logic in
 	     _Jv_ClassReader::prepare_pool_entry().  */
-	  utf8 = identifier_subst (utf8, "", '/', '.', "");
-
+	  utf8 = unmangle_classname (IDENTIFIER_POINTER(utf8),
+				     IDENTIFIER_LENGTH(utf8));
 	index = alloc_name_constant (kind, utf8);
       }
       break;
@@ -565,6 +585,17 @@
       index = find_constant1 (cpool, kind, JPOOL_INT (jcf, index));
       break;
       
+    case CONSTANT_NameAndType:
+      {
+	uint16 name = JPOOL_USHORT1 (jcf, index);
+	uint16 sig = JPOOL_USHORT2 (jcf, index);
+	uint32 name_index = handle_constant (jcf, name, CONSTANT_Utf8);
+	uint32 sig_index = handle_constant (jcf, sig, CONSTANT_Class);
+	jword new_index = (name_index << 16) | sig_index;
+	index = find_constant1 (cpool, kind, new_index);
+      }
+      break;
+
     default:
       abort ();
     }
@@ -805,6 +836,54 @@
   handle_element_value (jcf, 0);
 }
 
+/* As above, for the EnclosingMethod attribute.  */
+
+static void
+handle_enclosingmethod_attribute (int member_index, JCF *jcf, 
+			   const unsigned char *name ATTRIBUTE_UNUSED, 
+			   long len, jv_attr_type member_type)
+{
+  int new_len = len + 1;
+  uint16 index;
+  annotation_write_byte (member_type);
+  if (member_type != JV_CLASS_ATTR)
+    new_len += 2;
+  annotation_write_int (new_len);
+  annotation_write_byte (JV_ENCLOSING_METHOD_KIND);
+  if (member_type != JV_CLASS_ATTR)
+    annotation_write_short (member_index);
+
+  index = JCF_readu2 (jcf);
+  index = handle_constant (jcf, index, CONSTANT_Class);
+  annotation_write_short (index);
+
+  index = JCF_readu2 (jcf);
+  index = handle_constant (jcf, index, CONSTANT_NameAndType);
+  annotation_write_short (index);
+}
+
+/* As above, for the Signature attribute.  */
+
+static void
+handle_signature_attribute (int member_index, JCF *jcf, 
+			   const unsigned char *name ATTRIBUTE_UNUSED, 
+			   long len, jv_attr_type member_type)
+{
+  int new_len = len + 1;
+  uint16 index;
+  annotation_write_byte (member_type);
+  if (member_type != JV_CLASS_ATTR)
+    new_len += 2;
+  annotation_write_int (new_len);
+  annotation_write_byte (JV_SIGNATURE_KIND);
+  if (member_type != JV_CLASS_ATTR)
+    annotation_write_short (member_index);
+
+  index = JCF_readu2 (jcf);
+  index = handle_constant (jcf, index, CONSTANT_Utf8);
+  annotation_write_short (index);
+}
+  
 
 
 #define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX)
@@ -882,7 +961,7 @@
 /* Link seen inner classes to their outer context and register the
    inner class to its outer context. They will be later loaded.  */
 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
-  handle_innerclass_attribute (COUNT, jcf)
+  handle_innerclass_attribute (COUNT, jcf, attribute_length)
 
 #define HANDLE_SYNTHETIC_ATTRIBUTE()					\
 {									\
@@ -925,6 +1004,18 @@
   handle_default_annotation (index, jcf, name_data, attribute_length, attr_type); \
 }
 
+#define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE()				\
+{									\
+  handle_enclosingmethod_attribute (index, jcf, name_data,		\
+				    attribute_length, attr_type);	\
+}
+
+#define HANDLE_SIGNATURE_ATTRIBUTE()				\
+{								\
+  handle_signature_attribute (index, jcf, name_data,		\
+			      attribute_length, attr_type);	\
+}
+
 #include "jcf-reader.c"
 
 tree
@@ -1049,9 +1140,15 @@
    the outer context with the newly resolved innerclass.  */
 
 static void
-handle_innerclass_attribute (int count, JCF *jcf)
+handle_innerclass_attribute (int count, JCF *jcf, int attribute_length)
 {
-  int c = (count);
+  int c = count;
+
+  annotation_write_byte (JV_CLASS_ATTR);
+  annotation_write_int (attribute_length+1);
+  annotation_write_byte (JV_INNER_CLASSES_KIND);
+  annotation_write_short (count);
+
   while (c--)
     {
       /* Read inner_class_info_index. This may be 0 */
@@ -1064,6 +1161,12 @@
       int ini = JCF_readu2 (jcf);
       /* Read the access flag. */
       int acc = JCF_readu2 (jcf);
+
+      annotation_write_short (handle_constant (jcf, icii, CONSTANT_Class));
+      annotation_write_short (handle_constant (jcf, ocii, CONSTANT_Class));
+      annotation_write_short (handle_constant (jcf, ini, CONSTANT_Utf8));
+      annotation_write_short (acc);
+
       /* If icii is 0, don't try to read the class. */
       if (icii >= 0)
 	{
Index: java/constants.c
===================================================================
--- java/constants.c	(revision 118395)
+++ java/constants.c	(working copy)
@@ -495,7 +495,7 @@
   int i;
 
   for (i = outgoing_cpool->count;  --i > 0; )
-    switch (outgoing_cpool->tags[i])
+    switch (outgoing_cpool->tags[i] & ~CONSTANT_LazyFlag)
       {
       case CONSTANT_None:  /* The second half of a Double or Long on a
 			      32-bit target.  */
 	* java-tree.h (FIELD_ENUM): New.
Index: java/java-tree.h
===================================================================
--- java/java-tree.h	(revision 118418)
+++ java/java-tree.h	(working copy)
@@ -243,6 +243,11 @@
 
 #define CONSTANT_ResolvedFlag 16
 
+/* Don't eagerly resolve this entry.  When this flag is set, constant
+   pool entries are resolved only at runtime when the entry is first
+   referred to.  */
+#define CONSTANT_LazyFlag 32
+
 /* The cpool->data[i] for a ResolvedString points to a STRING_CST. */
 #define CONSTANT_ResolvedString    (CONSTANT_String+CONSTANT_ResolvedFlag)
 
2006-11-06  Andrew Haley  <aph@redhat.com>

	* defineclass.cc (prepare_pool_entry): Be careful about which
	constant pool entries have their '/' characters stripped.
	(handleGenericSignature): Likewise.
	(handleAnnotationElement): Likewise.
	(handleAnnotation): Likewise.
	(read_one_class_attribute): Likewise.
	(handleMethod): Likewise.

	* include/java-cpool.h (JV_CONSTANT_LazyFlag): New.
	* java/lang/natClass.cc (check_constant): Likewise.
	* link.cc (resolve_pool_entry): Mask JV_CONSTANT_LazyFlag.

Index: libjava/link.cc
===================================================================
--- libjava/link.cc	(revision 118387)
+++ libjava/link.cc	(working copy)
@@ -390,7 +390,7 @@
   if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
     return pool->data[index];
 
-  switch (pool->tags[index])
+  switch (pool->tags[index] & ~JV_CONSTANT_LazyFlag)
     {
     case JV_CONSTANT_Class:
       {
Index: libjava/gnu/java/nio/channels/natFileChannelPosix.cc
===================================================================
--- libjava/gnu/java/nio/channels/natFileChannelPosix.cc	(revision 118387)
+++ libjava/gnu/java/nio/channels/natFileChannelPosix.cc	(working copy)
@@ -513,6 +513,17 @@
     throw new IOException (JvNewStringLatin1 (strerror (errno)));
   buf->implPtr = reinterpret_cast<RawData*> (ptr);
   buf->implLen = size+align;
+
+  struct stat st;
+
+  if (fstat (fd, &st))
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+
+  if (size+position > st.st_size)
+    throw new IOException (JvNewStringLatin1 
+			   ("mmap: requested region not completely "
+			    "contained within file\n"));
+
   return buf;
 #else
   throw new IOException (JvNewStringUTF ("mmap not implemented"));
Index: libjava/java/lang/natClass.cc
===================================================================
--- libjava/java/lang/natClass.cc	(revision 118388)
+++ libjava/java/lang/natClass.cc	(working copy)
@@ -1058,7 +1058,8 @@
 {
   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)
+  if ((pool->tags[cpool_index] & 
+	~(JV_CONSTANT_ResolvedFlag|JV_CONSTANT_LazyFlag)) != type)
     {
       ::java::lang::StringBuffer *sb = new ::java::lang::StringBuffer();
       sb->append(JvNewStringLatin1("expected pool constant "));
Index: libjava/java/lang/VMCompiler.java
===================================================================
--- libjava/java/lang/VMCompiler.java	(revision 118387)
+++ libjava/java/lang/VMCompiler.java	(working copy)
@@ -187,7 +187,8 @@
 				   ProtectionDomain domain)
   {
     if (precompiledMapFiles == null
-	&& (! useCompiler || ! canUseCompiler))
+	&& (! useCompiler || ! canUseCompiler)
+	|| name.startsWith("$Proxy"))
       return null;
 
     byte digest[];
Index: libjava/include/java-cpool.h
===================================================================
--- libjava/include/java-cpool.h	(revision 118387)
+++ libjava/include/java-cpool.h	(working copy)
@@ -28,6 +28,7 @@
 #define JV_CONSTANT_InterfaceMethodref (11L)
 #define JV_CONSTANT_NameAndType (12L)
 #define JV_CONSTANT_ResolvedFlag (16L)
+#define JV_CONSTANT_LazyFlag (32L)
 #define JV_CONSTANT_ResolvedString (16L | 8L)
 #define JV_CONSTANT_ResolvedClass  (16L | 7L)
 
Index: libjava/defineclass.cc
===================================================================
--- libjava/defineclass.cc	(revision 118387)
+++ libjava/defineclass.cc	(working copy)
@@ -277,7 +277,8 @@
   /** and here goes the parser members defined out-of-line */
   void parse ();
   void read_constpool ();
-  void prepare_pool_entry (int index, unsigned char tag);
+  void prepare_pool_entry (int index, unsigned char tag,
+			   bool rewrite = true);
   void read_fields ();
   void read_methods ();
   void read_one_class_attribute ();
@@ -473,7 +474,7 @@
 
   int cpool_idx = read2u();
   check_tag (cpool_idx, JV_CONSTANT_Utf8);
-  prepare_pool_entry (cpool_idx, JV_CONSTANT_Utf8);
+  prepare_pool_entry (cpool_idx, JV_CONSTANT_Utf8, false);
 
   ::java::io::DataOutputStream *stream = get_reflection_stream ();
   stream->writeByte(type);
@@ -531,7 +532,7 @@
 	// Despite what the JVM spec says, compilers generate a Utf8
 	// constant here, not a String.
 	check_tag (index, JV_CONSTANT_Utf8);
-	prepare_pool_entry (index, JV_CONSTANT_Utf8);
+	prepare_pool_entry (index, JV_CONSTANT_Utf8, false);
       }
       break;
 
@@ -542,7 +543,7 @@
 	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);
+	prepare_pool_entry (const_name_index, JV_CONSTANT_Utf8, false);
       }
       break;
     case 'c':
@@ -579,7 +580,7 @@
     {
       int name_index = read2u();
       check_tag (name_index, JV_CONSTANT_Utf8);
-      prepare_pool_entry (name_index, JV_CONSTANT_Utf8);
+      prepare_pool_entry (name_index, JV_CONSTANT_Utf8, false);
       handleAnnotationElement();
     }
 }
@@ -955,7 +956,7 @@
     {
       int source_index = read2u ();
       check_tag (source_index, JV_CONSTANT_Utf8);
-      prepare_pool_entry (source_index, JV_CONSTANT_Utf8);
+      prepare_pool_entry (source_index, JV_CONSTANT_Utf8, false);
       def_interp->source_file_name = _Jv_NewStringUtf8Const
 	(def->constants.data[source_index].utf8);
     }
@@ -1041,9 +1042,15 @@
 }
 
 /* this is a recursive procedure, which will prepare pool entries as needed.
-   Which is how we avoid initializing those entries which go unused. */
+   Which is how we avoid initializing those entries which go unused. 
+   
+   REWRITE is true iff this pool entry is the Utf8 representation of a
+   class name or a signature.
+*/
+
 void
-_Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag)
+_Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag,
+				     bool rewrite)
 {
   /* these two, pool_data and pool_tags, point into the class
      structure we are currently defining */
@@ -1064,27 +1071,29 @@
     {
     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.
-
 	int len = get2u (this_data);
-	char *buffer = (char*) __builtin_alloca (len);
 	char *s = ((char*) this_data)+2;
+	pool_tags[index] = JV_CONSTANT_Utf8;
 
-	/* FIXME: avoid using a buffer here */
+	if (! rewrite)
+	  {
+	    pool_data[index].utf8 = _Jv_makeUtf8Const (s, len);
+	    break;
+	  }
+
+	// If REWRITE is set, it is because some other tag needs this
+	// utf8-entry for type information: it is a class or a
+	// signature.  Thus, we translate /'s to .'s in order to
+	// accomondate gcj's internal representation.
+	char *buffer = (char*) __builtin_alloca (len);
 	for (int i = 0; i < len; i++)
 	  {
 	    if (s[i] == '/')
 	      buffer[i] = '.';
 	    else
-	      buffer[i] = (char) s[i];
+	      buffer[i] = s[i];
 	  }
-	
 	pool_data[index].utf8 = _Jv_makeUtf8Const (buffer, len);
-	pool_tags[index] = JV_CONSTANT_Utf8;
       }
       break;
 	    
@@ -1152,8 +1161,7 @@
 	_Jv_ushort type_index = get2u (this_data+2);
 
 	check_tag (name_index, JV_CONSTANT_Utf8);
-	prepare_pool_entry (name_index, JV_CONSTANT_Utf8);	    
-
+	prepare_pool_entry (name_index, JV_CONSTANT_Utf8, false);
 	check_tag (type_index, JV_CONSTANT_Utf8);
 	prepare_pool_entry (type_index, JV_CONSTANT_Utf8);
 
@@ -1572,7 +1580,7 @@
   _Jv_Method *method = &def->methods[mth_index];
 
   check_tag (name, JV_CONSTANT_Utf8);
-  prepare_pool_entry (name, JV_CONSTANT_Utf8);
+  prepare_pool_entry (name, JV_CONSTANT_Utf8, false);
   method->name = pool_data[name].utf8;
 
   check_tag (desc, JV_CONSTANT_Utf8);



More information about the Gcc-patches mailing list