This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: FYI: fix for method decompiling in gcjh


I'm checking this in.  This fixes a bug reported by a user.

Suppose you have code like this:

    public class foo implements Cloneable
    {
      public Cloneable get ()
      {
	return this;
      }
    }

Without this patch we'll erroneously decompile get() into a simple
`return'.  This fails because the C++ compiler doesn't know about
interfaces.

This patch fixes the problem by adding a cast when required.
(Actually sometimes it adds one when not required, because gcjh has no
way to read auxiliary classes to gather information it might need.
This is harmless.)

Tom

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

	* gjavah.c (method_signature): New global.
	(HANDLE_METHOD): Set it.
	(decompile_return_statement): New function.
	(decompile_method): Use it.
	(print_method_info): Removed `synth' argument.

Index: gjavah.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/gjavah.c,v
retrieving revision 1.74
diff -u -r1.74 gjavah.c
--- gjavah.c 2001/10/22 03:58:19 1.74
+++ gjavah.c 2001/11/12 21:48:12
@@ -120,7 +120,7 @@
 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, int));
+static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
 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,
@@ -151,6 +151,7 @@
 static int overloaded_jni_method_exists_p PARAMS ((const unsigned char *, int,
 						   const char *, int));
 static void jni_print_char PARAMS ((FILE *, int));
+static void decompile_return_statement PARAMS ((FILE *, JCF *, int, int, int));
 
 JCF_u2 current_field_name;
 JCF_u2 current_field_value;
@@ -187,9 +188,12 @@
 static int method_access = 0;
 static int method_printed = 0;
 static int method_synthetic = 0;
+static int method_signature = 0;
+
 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT)	\
   {									\
     method_synthetic = 0;						\
+    method_signature = SIGNATURE;					\
     if (ATTRIBUTE_COUNT)						\
       method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT,		\
 				  (const char *)"Synthetic", 9);	\
@@ -207,12 +211,12 @@
 	decompiled = 0; method_printed = 0;				\
 	if (out)							\
 	  print_method_info (out, jcf, NAME, SIGNATURE,			\
-			     ACCESS_FLAGS, method_synthetic);		\
+			     ACCESS_FLAGS);				\
       }									\
     else if (!method_synthetic)						\
       {									\
 	print_method_info (NULL, jcf, NAME, SIGNATURE,			\
-			   ACCESS_FLAGS, method_synthetic);		\
+			   ACCESS_FLAGS);				\
 	if (! stubs && ! flag_jni)					\
 	  add_class_decl (out, jcf, SIGNATURE);				\
       }									\
@@ -784,9 +788,9 @@
 
 
 static void
-DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags, synth),
+DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
       FILE *stream AND JCF* jcf
-      AND int name_index AND int sig_index AND JCF_u2 flags AND int synth)
+      AND int name_index AND int sig_index AND JCF_u2 flags)
 {
   const unsigned char *str;
   int length, is_init = 0;
@@ -799,10 +803,6 @@
   str = JPOOL_UTF_DATA (jcf, name_index);
   length = JPOOL_UTF_LENGTH (jcf, name_index);
 
-  /* Ignore synthetic methods. */
-  if (synth)
-    return;
-
   if (str[0] == '<')
     {
       /* Ignore the internally generated method <clinit>. However,
@@ -892,6 +892,132 @@
     free (override);
 }
 
+/* A helper for the decompiler which prints a `return' statement where
+   the type is a reference type.  If METHODTYPE and OBJECTTYPE are not
+   identical, we emit a cast.  We do this because the C++ compiler
+   doesn't know that a reference can be cast to the type of an
+   interface it implements.  METHODTYPE is the index of the method's
+   signature.  NAMEINDEX is the index of the field name; -1 for
+   `this'.  OBJECTTYPE is the index of the object's type.  */
+static void
+decompile_return_statement (out, jcf, methodtype, nameindex, objecttype)
+     FILE *out;
+     JCF *jcf;
+     int methodtype, nameindex, objecttype;
+{
+  int cast = 0;
+  int obj_name_len, method_name_len;
+  const unsigned char *obj_data, *method_data;
+
+  obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype);
+  obj_data = JPOOL_UTF_DATA (jcf, objecttype);
+
+  method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype);
+  method_data = JPOOL_UTF_DATA (jcf, methodtype);
+
+  /* Skip forward to return type part of method.  */
+  while (*method_data != ')')
+    {
+      ++method_data;
+      --method_name_len;
+    }
+  /* Skip past `)'.  */
+  ++method_data;
+  --method_name_len;
+
+  /* If we see an `L', skip it and the trailing `;'.  */
+  if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';')
+    {
+      ++method_data;
+      method_name_len -= 2;
+    }
+  if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';')
+    {
+      ++obj_data;
+      obj_name_len -= 2;
+    }
+
+  /* FIXME: if METHODTYPE is a superclass of OBJECTTYPE then we don't
+     need a cast.  Right now there is no way to determine if this is
+     the case.  */
+  if (method_name_len != obj_name_len)
+    cast = 1;
+  else
+    {
+      int i;
+      for (i = 0; i < method_name_len; ++i)
+	{
+	  if (method_data[i] != obj_data[i])
+	    {
+	      cast = 1;
+	      break;
+	    }
+	}
+    }
+
+  fputs (" { return ", out);
+
+  if (cast)
+    {
+      int array_depth = 0;
+      const unsigned char *limit;
+
+      fputs ("reinterpret_cast<", out);
+
+      while (*method_data == '[')
+	{
+	  ++method_data;
+	  ++array_depth;
+	  --method_name_len;
+	  fputs ("JArray<", out);
+	}
+
+      fputs ("::", out);
+
+      /* If we see an `L', skip it and the trailing `;'.  Only do this
+	 if we've seen an array specification.  If we don't have an
+	 array then the `L' was stripped earlier.  */
+      if (array_depth && method_data[0] == 'L'
+	  && method_data[method_name_len - 1] == ';')
+	{
+	  ++method_data;
+	  method_name_len -= 2;
+	}
+
+      limit = method_data + method_name_len;
+      while (method_data < limit)
+	{
+	  int ch = UTF8_GET (method_data, limit);
+	  if (ch == '/')
+	    fputs ("::", out);
+	  else
+	    jcf_print_char (out, ch);
+	}
+      fputs (" *", out);
+
+      /* Close each array.  */
+      while (array_depth > 0)
+	{
+	  fputs ("> *", out);
+	  --array_depth;
+	}
+
+      /* Close the cast.  */
+      fputs ("> (", out);
+    }
+
+  if (nameindex == -1)
+    fputs ("this", out);
+  else
+    print_field_name (out, jcf, nameindex, 0);
+
+  if (cast)
+    fputs (")", out);
+
+  fputs ("; }", out);
+}
+
+
 /* Try to decompile a method body.  Right now we just try to handle a
    simple case that we can do.  Expand as desired.  */
 static void
@@ -918,24 +1044,29 @@
 	  || codes[4] == OPCODE_lreturn))
     {
       /* Found code like `return FIELD'.  */
-      fputs (" { return ", out);
       index = (codes[2] << 8) | codes[3];
       /* FIXME: ensure that tag is CONSTANT_Fieldref.  */
-      /* FIXME: ensure that the field's class is this class.  */
       name_and_type = JPOOL_USHORT2 (jcf, index);
       /* FIXME: ensure that tag is CONSTANT_NameAndType.  */
       name = JPOOL_USHORT1 (jcf, name_and_type);
-      /* FIXME: flags.  */
-      print_field_name (out, jcf, name, 0);
-      fputs ("; }", out);
+      if (codes[4] == OPCODE_areturn)
+	decompile_return_statement (out, jcf, method_signature,
+				    name, JPOOL_USHORT2 (jcf, name_and_type));
+      else
+	{
+	  fputs (" { return ", out);
+	  /* FIXME: flags.  */
+	  print_field_name (out, jcf, name, 0);
+	  fputs ("; }", out);
+	}
       decompiled = 1;
     }
   else if (code_len == 2
 	   && codes[0] == OPCODE_aload_0
 	   && codes[1] == OPCODE_areturn)
     {
-      /* Found `return this'.  */
-      fputs (" { return this; }", out);
+      decompile_return_statement (out, jcf, method_signature, -1,
+				  JPOOL_USHORT1 (jcf, jcf->this_class));
       decompiled = 1;
     }
   else if (code_len == 1 && codes[0] == OPCODE_return)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]