[PATCH] Java: miscellaneous fixes

Alexandre Petit-Bianco apbianco@cygnus.com
Mon Aug 7 20:31:00 GMT 2000


This patch fixes some front-end problems, improves gcjh (skipping
synthetic methods) and enable 1.1 support in jv-scan. If you rebuild
jc1, then you need to rebuild gcjh to be able to compile the
run-time. I'm checking this in.

./A

2000-08-07  Alexandre Petit-Bianco  <apbianco@cygnus.com

	* parse.y (build_dot_class_method_invocation): Changed parameter
	name to `type.' Build signature from `type' and convert it to a
	STRING_CST if it's an array.
	(patch_incomplete_class_ref): `build_dot_class_method_invocation'
	to use `ref_type' directly.

2000-08-01  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* parse.y (maybe_yank_clinit): When generating bytecode: non empty
	method bodies not to rule out discarding `<clinit>'; don't use
	<clinit> to initialize static fields with constant initializers.

2000-08-01  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* gjavah.c (print_method_info): Added `synth' parameter. Skip
	synthetic methods.
	(method_synthetic): New global.
	(HANDLE_METHOD): Recognize synthetic method and tell
	`print_method_info' about it.
	(HANDLE_END_METHOD): Do not issue an additional `;\n' if we're
	processing a synthetic method.
	* jcf-reader.c (skip_attribute): New function.
	( skip_attribute): Likewise.

2000-08-01  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* parse.y (build_outer_field_access): Fixed comments.
	(fix_constructors): Emit the initialization of this$<n> before
	calling $finit$.
	(resolve_qualified_expression_name): Build an access to `decl' if
	necessary.

2000-07-31  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* parse-scan.y (curent_class): Non longer const.
	(inner_qualifier, inner_qualifier_length): Deleted.
	(current_class_length): New global.
	(bracket_count): Fixed typo in leading comment.
	(anonymous_count): New global.
	(class_instance_creation_expression:): Handle anonymous classes.
	(anonymous_class_creation:): New rule.
	(push_class_context): Rewritten.
	(pop_class_context): Likewise.
	(INNER_QUALIFIER): Macro deleted.
	(report_class_declaration): call `push_class_context' when
	entering the function. `fprintf' format modified not to use
	INNER_QUALIFIER.
	(report_class_declaration): Assign `package_name' and
	`current_class' to NULL separatly.

2000-07-31  Alexandre Petit-Bianco  <apbianco@cygnus.com>

	* expr.c (build_invokeinterface): Call layout_class_methods on
	target interface.

Index: expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/expr.c,v
retrieving revision 1.80
diff -u -p -r1.80 expr.c
--- expr.c	2000/07/07 00:49:35	1.80
+++ expr.c	2000/08/08 03:19:56
@@ -1783,6 +1783,7 @@ build_invokeinterface (dtable, method)
 		  lookup_field (&dtable_type, class_ident));
 
   interface = DECL_CONTEXT (method);
+  layout_class_methods (interface);
   
   i = 1;
   for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
Index: gjavah.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/gjavah.c,v
retrieving revision 1.57
diff -u -p -r1.57 gjavah.c
--- gjavah.c	2000/07/05 01:13:03	1.57
+++ gjavah.c	2000/08/08 03:20:00
@@ -116,7 +116,7 @@ static struct method_name *method_name_l
 static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
 static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int));
 static int  print_cxx_classname PARAMS ((FILE*, const char*, JCF*, int));
-static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
+static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2, int));
 static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *,
 				  int));
 static void print_stub_or_jni PARAMS ((FILE*, JCF*, int, int, int,
@@ -182,26 +182,45 @@ static int method_pass;
 static int method_declared = 0;
 static int method_access = 0;
 static int method_printed = 0;
-#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)	      \
-  if (method_pass)							      \
-    {									      \
-      decompiled = 0; method_printed = 0;				      \
-      if (out)								      \
-        print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS);	      \
-    }									      \
-  else                                                                       \
-    {                                                                        \
-      print_method_info (NULL, jcf, NAME, SIGNATURE, ACCESS_FLAGS);          \
-      if (! stubs && ! flag_jni)                                             \
-       add_class_decl (out, jcf, SIGNATURE);                                 \
-    }
+static int method_synthetic = 0;
+#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)	\
+  {									\
+    method_synthetic = 0;						\
+    if (ATTRIBUTE_COUNT)						\
+      method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT,		\
+				  (const char *)"Synthetic", 9);	\
+    /* If a synthetic methods have been declared, its attribute aren't	\
+       worth reading (and triggering side-effects). We skip them an	\
+       set ATTRIBUTE_COUNT to zero so that they'll be skipped in	\
+       jcf_parse_one_method.  */					\
+    if (method_synthetic)						\
+      {									\
+	skip_attribute (jcf, ATTRIBUTE_COUNT);				\
+	ATTRIBUTE_COUNT = 0;						\
+      } 								\
+    if (method_pass && !method_synthetic)				\
+      {									\
+	decompiled = 0; method_printed = 0;				\
+	if (out)							\
+	  print_method_info (out, jcf, NAME, SIGNATURE,			\
+			     ACCESS_FLAGS, method_synthetic);		\
+      }									\
+    else if (!method_synthetic)						\
+      {									\
+	print_method_info (NULL, jcf, NAME, SIGNATURE,			\
+			   ACCESS_FLAGS, method_synthetic);		\
+	if (! stubs && ! flag_jni)					\
+	  add_class_decl (out, jcf, SIGNATURE);				\
+      }									\
+  }
 
-#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
+#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH)	\
   if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
 
 static int decompiled = 0;
-#define HANDLE_END_METHOD() \
-  if (out && method_printed) fputs (decompiled || stubs ? "\n" : ";\n", out);
+#define HANDLE_END_METHOD()				\
+  if (out && method_printed && !method_synthetic) 	\
+    fputs (decompiled || stubs ? "\n" : ";\n", out);
 
 #include "jcf-reader.c"
 
@@ -670,9 +689,9 @@ DEFUN(print_field_info, (stream, jcf, na
 
 
 static void
-DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
+DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth),
       FILE *stream AND JCF* jcf
-      AND int name_index AND int sig_index AND JCF_u2 flags)
+      AND int name_index AND int sig_index AND JCF_u2 flags AND int synth)
 {
   const unsigned char *str;
   int length, is_init = 0;
@@ -684,10 +703,15 @@ DEFUN(print_method_info, (stream, jcf, n
     fprintf (stream, "<not a UTF8 constant>");
   str = JPOOL_UTF_DATA (jcf, name_index);
   length = JPOOL_UTF_LENGTH (jcf, name_index);
-  if (str[0] == '<' || str[0] == '$')
+
+  /* Ignore synthetic methods. */
+  if (synth)
+    return;
+
+  if (str[0] == '<')
     {
-      /* Ignore internally generated methods like <clinit> and
-	 $finit$.  However, treat <init> as a constructor.  */
+      /* Ignore the internally generated method <clinit>. However,
+         treat <init> as a constructor.  */
       if (! utf8_cmp (str, length, "<init>"))
 	is_init = 1;
       else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
Index: jcf-reader.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/jcf-reader.c,v
retrieving revision 1.11
diff -u -p -r1.11 jcf-reader.c
--- jcf-reader.c	2000/03/14 05:01:04	1.11
+++ jcf-reader.c	2000/08/08 03:20:01
@@ -27,6 +27,8 @@ The Free Software Foundation is independ
 #include "zipfile.h"
 
 static int get_attribute PARAMS ((JCF *));
+static int peek_attribute PARAMS ((JCF *, int, const char *, int));
+static void skip_attribute PARAMS ((JCF *, int));
 static int jcf_parse_preamble PARAMS ((JCF *));
 static int jcf_parse_constant_pool PARAMS ((JCF *));
 static void jcf_parse_class PARAMS ((JCF *));
@@ -34,6 +36,64 @@ static int jcf_parse_fields PARAMS ((JCF
 static int jcf_parse_one_method PARAMS ((JCF *));
 static int jcf_parse_methods PARAMS ((JCF *));
 static int jcf_parse_final_attributes PARAMS ((JCF *));
+
+/* Go through all available attribute (ATTRIBUTE_NUMER) and try to
+   identify PEEKED_NAME.  Return 1 if PEEKED_NAME was found, 0
+   otherwise. JCF is restored to its initial position before
+   returning.  */
+
+static int
+peek_attribute (jcf, attribute_number, peeked_name, peeked_name_length)
+      JCF *jcf;
+      int attribute_number;
+      const char *peeked_name;
+      int peeked_name_length;
+{
+  int to_return = 0;
+  long absolute_offset = (long)JCF_TELL (jcf);
+  int i;
+
+  for (i = 0; !to_return && i < attribute_number; i++)
+    {
+      uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf));
+      uint32 attribute_length = JCF_readu4 (jcf);
+      int name_length;
+      const unsigned char *name_data; 
+
+      JCF_FILL (jcf, (long) attribute_length);
+      if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)
+	  || JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8)
+	continue;
+
+      name_length = JPOOL_UTF_LENGTH (jcf, attribute_name);
+      name_data = JPOOL_UTF_DATA (jcf, attribute_name);
+
+      if (name_length == peeked_name_length 
+	  && ! memcmp (name_data, peeked_name, peeked_name_length)) 
+	{
+	  to_return = 1; 
+	  break;
+	}
+      
+      JCF_SKIP (jcf, attribute_length);
+    }
+
+  JCF_SEEK (jcf, absolute_offset);
+  return to_return;
+}
+
+static void
+skip_attribute (jcf, number_of_attribute)
+     JCF *jcf;
+     int number_of_attribute;
+{
+  while (number_of_attribute--)
+    {
+      JCF_FILL (jcf, 6);
+      (void) JCF_readu2 (jcf);
+      JCF_SKIP (jcf, JCF_readu4 (jcf));
+    }
+}
 
 static int
 DEFUN(get_attribute, (jcf),
Index: parse-scan.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse-scan.y,v
retrieving revision 1.17
diff -u -p -r1.17 parse-scan.y
--- parse-scan.y	2000/03/28 22:35:46	1.17
+++ parse-scan.y	2000/08/08 03:20:03
@@ -63,12 +63,11 @@ static int absorber;
 #define USE_ABSORBER absorber = 0
 
 /* Keep track of the current class name and package name.  */
-static const char *current_class;
+static char *current_class;
 static const char *package_name;
 
 /* Keep track of the current inner class qualifier. */
-static char *inner_qualifier;
-static int   inner_qualifier_length;
+static int current_class_length;
 
 /* Keep track of whether things have be listed before.  */
 static int previous_output;
@@ -76,10 +75,13 @@ static int previous_output;
 /* Record modifier uses  */
 static int modifier_value;
 
-/* Keep track of number of bracket pairs after a variable declarator
+/* Keeps track of number of bracket pairs after a variable declarator
    id.  */
 static int bracket_count; 
 
+/* Numbers anonymous classes */
+static int anonymous_count;
+
 /* Record a method declaration  */
 struct method_declarator {
   const char *method_name;
@@ -897,20 +899,22 @@ primary_no_new_array:
 class_instance_creation_expression:
 	NEW_TK class_type OP_TK argument_list CP_TK
 |	NEW_TK class_type OP_TK CP_TK
-        /* Added, JDK1.1 inner classes but modified to use
-           'class_type' instead of 'TypeName' (type_name) mentionned
-           in the documentation but doesn't exist. */
-|	NEW_TK class_type OP_TK argument_list CP_TK class_body
-|	NEW_TK class_type OP_TK CP_TK class_body         
-        /* Added, JDK1.1 inner classes, modified to use name or
-	   primary instead of primary solely which couldn't work in
-	   all situations.  */
+|	anonymous_class_creation
 |	something_dot_new identifier OP_TK CP_TK
 |	something_dot_new identifier OP_TK CP_TK class_body
 |	something_dot_new identifier OP_TK argument_list CP_TK
 |	something_dot_new identifier OP_TK argument_list CP_TK class_body
 ;
 
+anonymous_class_creation:
+	NEW_TK class_type OP_TK CP_TK
+		{ report_class_declaration (NULL); }
+	class_body         
+|	NEW_TK class_type OP_TK argument_list CP_TK
+		{ report_class_declaration (NULL); }
+	class_body
+;
+
 something_dot_new:		/* Added, not part of the specs. */
 	name DOT_TK NEW_TK
 		{ USE_ABSORBER; }
@@ -1128,29 +1132,61 @@ static void
 push_class_context (name)
     const char *name;
 {
-  size_t name_length = strlen (name);
-  inner_qualifier = xrealloc (inner_qualifier, 
-                             inner_qualifier_length + name_length+2);
-  memcpy (inner_qualifier+inner_qualifier_length, name, name_length);
-  inner_qualifier_length += name_length;
-  inner_qualifier [inner_qualifier_length] = '$';
-  inner_qualifier [++inner_qualifier_length] = '\0';
+  /* If we already have CURRENT_CLASS set, we're in an inter
+     class. Mangle its name. */
+  if (current_class)
+    {
+      const char *p;
+      char anonymous [3];
+      int additional_length;
+      
+      /* NAME set to NULL indicates an anonymous class, which are named by
+	 numbering them. */
+      if (!name)
+	{
+	  sprintf (anonymous, "%d", ++anonymous_count);
+	  p = anonymous;
+	}
+      else
+	p = name;
+      
+      additional_length = strlen (p)+1; /* +1 for `$' */
+      current_class = xrealloc (current_class, 
+				current_class_length + additional_length + 1);
+      current_class [current_class_length] = '$';
+      strcpy (&current_class [current_class_length+1], p);
+      current_class_length += additional_length;
+    }
+  else
+    {
+      if (!name)
+	return;
+      current_class_length = strlen (name);
+      current_class = xmalloc (current_class_length+1);
+      strcpy (current_class, name);
+    }
 }
 
 static void
 pop_class_context ()
 {
-  while (--inner_qualifier_length > 0
-        && inner_qualifier [inner_qualifier_length-1] != '$')
+  /* Go back to the last `$' and cut. */
+  while (--current_class_length > 0
+        && current_class [current_class_length] != '$')
     ;
-  inner_qualifier = xrealloc (inner_qualifier, inner_qualifier_length+1);
-  if (inner_qualifier_length == -1)
-    inner_qualifier_length = 0;
-  inner_qualifier [inner_qualifier_length] = '\0';
+  if (current_class_length)
+    {
+      current_class = xrealloc (current_class, current_class_length+1);
+      current_class [current_class_length] = '\0';
+    }
+  else
+    {
+      current_class = NULL;
+      anonymous_count = 0;
+    }
 }
 
 /* Actions defined here */
-#define INNER_QUALIFIER (inner_qualifier ? inner_qualifier : "")
 
 static void
 report_class_declaration (name)
@@ -1158,6 +1194,7 @@ report_class_declaration (name)
 {
   extern int flag_dump_class, flag_list_filename;
 
+  push_class_context (name);
   if (flag_dump_class)
     {
       if (!previous_output)
@@ -1168,13 +1205,10 @@ report_class_declaration (name)
 	}
 	
       if (package_name)
-	fprintf (out, "%s.%s%s ", package_name, INNER_QUALIFIER, name);
+	fprintf (out, "%s.%s ", package_name, current_class);
       else
-	fprintf (out, "%s%s ", INNER_QUALIFIER, name);
+	fprintf (out, "%s ", current_class);
     }
-
-  push_class_context (name);
-  current_class = name;
 }
 
 static void
@@ -1208,7 +1242,8 @@ report_main_declaration (declarator)
 void reset_report ()
 {
   previous_output = 0;
-  current_class = package_name = NULL;
+  package_name = NULL;
+  current_class = NULL;
 }
 
 void
Index: parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/parse.y,v
retrieving revision 1.198
diff -u -p -r1.198 parse.y
--- parse.y	2000/07/28 00:30:19	1.198
+++ parse.y	2000/08/08 03:20:38
@@ -7523,12 +7523,14 @@ maybe_yank_clinit (mdecl)
   
   if (!DECL_CLINIT_P (mdecl))
     return 0;
-  
-  /* If the body isn't empty, then we keep <clinit> */
+
+  /* If the body isn't empty, then we keep <clinit>. Note that if
+     we're emitting classfiles, this isn't enough not to rule it
+     out. */
   fbody = DECL_FUNCTION_BODY (mdecl);
   if ((bbody = BLOCK_EXPR_BODY (fbody)))
     bbody = BLOCK_EXPR_BODY (bbody);
-  if (bbody && bbody != empty_stmt_node)
+  if (bbody && ! flag_emit_class_files && bbody != empty_stmt_node)
     return 0;
   
   type = DECL_CONTEXT (mdecl);
@@ -7536,10 +7538,35 @@ maybe_yank_clinit (mdecl)
 
   for (current = (current ? TREE_CHAIN (current) : current); 
        current; current = TREE_CHAIN (current))
-    if (!(FIELD_STATIC (current) && FIELD_FINAL (current)
-	  && DECL_INITIAL (current) && TREE_CONSTANT (DECL_INITIAL (current))))
-      break;
+    {
+      tree f_init;
 
+      /* We're not interested in non static field */
+      if (!FIELD_STATIC (current))
+	continue;
+
+      /* Anything that isn't String or a basic type is ruled out -- or
+	 if we now how to deal with it (when doing things natively) we
+	 should generated an empty <clinit> so that SUID are computed
+	 correctly. */
+      if (! JSTRING_TYPE_P (TREE_TYPE (current))
+	  && ! JNUMERIC_TYPE_P (TREE_TYPE (current)))
+	break;
+	  
+      f_init = DECL_INITIAL (current);
+      /* If we're emitting native code, we want static final fields to
+	 have constant initializers. If we don't meet these
+	 conditions, we keep <clinit> */
+      if (!flag_emit_class_files
+	  && !(FIELD_FINAL (current) && f_init && TREE_CONSTANT (f_init)))
+	break;
+      /* If we're emitting bytecode, we want static fields to have
+	 constant initializers or no initializer. If we don't meet
+	 these conditions, we keep <clinit> */
+      if (flag_emit_class_files && f_init && !TREE_CONSTANT (f_init))
+	break;
+    }
+
   if (current)
     return 0;
 
@@ -7661,7 +7688,7 @@ build_outer_field_access (id, decl)
   tree ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
 
   /* If decl's class is the direct outer class of the current_class,
-     build the access as `this$<n>.<field>'. Not that we will break
+     build the access as `this$<n>.<field>'. Note that we will break
      the `private' barrier if we're not emitting bytecodes. */
   if (ctx == DECL_CONTEXT (decl) 
       && (!FIELD_PRIVATE (decl) || !flag_emit_class_files ))
@@ -7677,7 +7704,7 @@ build_outer_field_access (id, decl)
       int lc = EXPR_WFL_LINECOL (id);
 
       /* Now we chain the required number of calls to the access$0 to
-	 get a hold to the enclosing instance we need, and the we
+	 get a hold to the enclosing instance we need, and then we
 	 build the field access. */
       access = build_access_to_thisn (ctx, DECL_CONTEXT (decl), lc);
 
@@ -8269,14 +8296,21 @@ build_dot_class_method (class)
 }
 
 static tree
-build_dot_class_method_invocation (name)
-     tree name;
+build_dot_class_method_invocation (type)
+     tree type;
 {
-  tree s = make_node (STRING_CST);
-  TREE_STRING_LENGTH (s) = IDENTIFIER_LENGTH (name);
+  tree sig_id, s;
+
+  if (TYPE_ARRAY_P (type))
+    sig_id = build_java_signature (type);
+  else
+    sig_id = DECL_NAME (TYPE_NAME (type));
+
+  s = make_node (STRING_CST);
+  TREE_STRING_LENGTH (s) = IDENTIFIER_LENGTH (sig_id);
   TREE_STRING_POINTER (s) = obstack_alloc (expression_obstack,
 					   TREE_STRING_LENGTH (s)+1);
-  strcpy (TREE_STRING_POINTER (s), IDENTIFIER_POINTER (name));
+  strcpy (TREE_STRING_POINTER (s), IDENTIFIER_POINTER (sig_id));
   return build_method_invocation (build_wfl_node (get_identifier ("class$")),
 				  build_tree_list (NULL_TREE, s));
 }
@@ -8318,6 +8352,11 @@ fix_constructors (mdecl)
 	 CLASSNAME() constructor */
       start_artificial_method_body (mdecl);
       
+      /* Insert an assignment to the this$<n> hidden field, if
+         necessary */
+      if ((thisn_assign = build_thisn_assign ()))
+	java_method_add_stmt (mdecl, thisn_assign);
+
       /* We don't generate a super constructor invocation if we're
 	 compiling java.lang.Object. build_super_invocation takes care
 	 of that. */
@@ -8327,11 +8366,6 @@ fix_constructors (mdecl)
          super invocation. */
       add_instance_initializer (mdecl);
 
-      /* Insert an assignment to the this$<n> hidden field, if
-         necessary */
-      if ((thisn_assign = build_thisn_assign ()))
-	java_method_add_stmt (mdecl, thisn_assign);
-
       end_artificial_method_body (mdecl);
     }
   /* Search for an explicit constructor invocation */
@@ -8363,14 +8397,14 @@ fix_constructors (mdecl)
 	compound = add_stmt_to_compound (compound, NULL_TREE,
                                          build_super_invocation (mdecl));
       
-      /* Insert the instance initializer block right here, after the
-         super invocation. */
-      add_instance_initializer (mdecl);
-
       /* Generate the assignment to this$<n>, if necessary */
       if ((thisn_assign = build_thisn_assign ()))
         compound = add_stmt_to_compound (compound, NULL_TREE, thisn_assign);
 
+      /* Insert the instance initializer block right here, after the
+         super invocation. */
+      add_instance_initializer (mdecl);
+
       /* Fix the constructor main block if we're adding extra stmts */
       if (compound)
 	{
@@ -9170,6 +9204,8 @@ resolve_qualified_expression_name (wfl, 
 					  current_class);
 			  return 1;
 			}
+                      if (outer_field_access_p (current_class, decl))
+                        decl = build_outer_field_access (qual_wfl, decl);
 		    }
 		  else
 		    {
@@ -13114,8 +13150,7 @@ patch_incomplete_class_ref (node)
      synthetic static method `class$'. */
   if (!TYPE_DOT_CLASS (current_class))
       build_dot_class_method (current_class);
-  ref_type = 
-    build_dot_class_method_invocation (DECL_NAME (TYPE_NAME (ref_type)));
+  ref_type = build_dot_class_method_invocation (ref_type);
   return java_complete_tree (ref_type);
 }
 


More information about the Gcc-patches mailing list