This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java 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] Add option to reduce amount of reflection data to gcj...


Andrew Haley wrote:
David Daney writes:
> Here is my patch to optionally reduce the amount of reflection data > generated by gcj. When applied to libgcj on i686 I see about 5% > reduction in memory image size.
> > text data bss dec hex filename
> 18937435 3615244 260644 22813323 15c1a8b > /home/daney/gccsvn/native_clean/i686-pc-linux-gnu/libjava/.libs/libgcj.so.7.0.0
> 18284867 3254316 260644 21799827 14ca393 libgcj.so.7.0.0
> > On my GCC-3.4.3/mipsel-linux port of the patch when used in conjunction > with static linking I am getting about 12-15% savings on a fairly large > (1000 classes) application.
> > There are of course several caveats: By eliminating a lot of reflection > meta-data, a lot of reflection operations will fail. No big surprize > there. JNI and the binary compatibility ABI depend on complete > reflection meta-data, so they cannot be used in conjunction with reduced > reflection meta-data. The byte code interpereter, and the gij program > work on some, but not all, programs with reduced reflection meta-data.
> > Tested on i686-pc-linux-gnu (FC3).
> > When -freflection-data= is not specified, no regressions with full > bootstrap of all default languages. I generated assembly language for a > 122 class package with and without the patch and the *only* differences > were the movement of the vtables from after to before the reflection > data. This is to be expected from the patch. Adding > -freflection-data=reduced to my libgcj.spec.in, resulted in many (about > 180) failures in the libgcj testsuite. These were in some, but not all, > gij compilation tests as well as JNI, BC and some specific reflection > tests. I am considering this a pass as some things are not expected to > work with the -freflection-data=reduced option enabled.
> > OK to commit?


I don't think the -freflection-data=none option should be there in its
current form, since it breaks so much.  Perhaps this option could be
enhanced so that we don't silently generate incorrect code.  We should
report an error instead.

If it's incompatible with -findirect-dispatch, it should error if
these options are combined on the command line.

Both issues fixed with this new version of the patch.


The new option is '-freduced-reflection'.

Tested as before. No regressions without new -freduced-reflection option. with %{fjni|findirect-dispatch:;:-freduced-reflection} added to libgcj.spec.in I get 125 new failures, but they are all expected as the patch makes this sacrifice to save space.

OK to commit?

2006-03-14 David Daney <ddaney@avtrex.com>

        * lang.opt (-freduced-reflection): New option.
        * lang.c (java_post_options): Generate an error if
        -freduced-reflection used with -fjni or -findirect-dispatch.
        * java-tree.h (flag_reduced_reflection): Declare new variable.
        * boehm.c (get_boehm_type_descriptor): Indicate all pointers
        if bitmap overflows and flag_reduced_reflection set.
        * class.c (uses_jv_markobj_p): New function.
        (make_class_data): Moved generation of vtable to before
        reflection data, generate less reflection data if
        flag_reduced_reflection set.
        * gcj.texi: Document -freduced-reflection.
Index: gcc/java/class.c
===================================================================
--- gcc/java/class.c	(revision 111859)
+++ gcc/java/class.c	(working copy)
@@ -1548,6 +1548,16 @@
   return 1;
 }
 
+/* The forth (index of 3) element in the vtable is the GC descriptor.
+   A value of 2 indicates that the class uses _Jv_MarkObj. */
+static int
+uses_jv_markobj_p(tree dtable)
+{
+  tree v;
+  v = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (dtable), 3)->value;
+  return (2 == TREE_INT_CST_LOW (v));
+}
+
 void
 make_class_data (tree type)
 {
@@ -1570,7 +1580,10 @@
   tree constant_pool_constructor;
   tree interfaces = null_pointer_node;
   int interface_len = 0;
+  int uses_jv_markobj = 0;
   tree type_decl = TYPE_NAME (type);
+  tree id_main = get_identifier("main");
+  tree id_class = get_identifier("java.lang.Class");
   /** Offset from start of virtual function table declaration
       to where objects actually point at, following new g++ ABI. */
   tree dtable_start_offset = build_int_cst (NULL_TREE,
@@ -1579,6 +1592,22 @@
   this_class_addr = build_class_ref (type);
   decl = TREE_OPERAND (this_class_addr, 0);
 
+  if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
+      && !flag_indirect_dispatch)
+    {
+      tree dtable = get_dispatch_table (type, this_class_addr);
+      uses_jv_markobj = uses_jv_markobj_p(dtable);
+      dtable_decl = build_dtable_decl (type);
+      DECL_INITIAL (dtable_decl) = dtable;
+      TREE_STATIC (dtable_decl) = 1;
+      DECL_ARTIFICIAL (dtable_decl) = 1;
+      DECL_IGNORED_P (dtable_decl) = 1;
+      TREE_PUBLIC (dtable_decl) = 1;
+      rest_of_decl_compilation (dtable_decl, 1, 0);
+      if (type == class_type_node)
+	class_dtable_decl = dtable_decl;
+    }
+
   /* Build Field array. */
   field = TYPE_FIELDS (type);
   while (field && DECL_ARTIFICIAL (field))
@@ -1589,9 +1618,11 @@
     {
       if (! DECL_ARTIFICIAL (field))
 	{
-	  tree init = make_field_value (field);
 	  if (FIELD_STATIC (field))
 	    {
+              /* We must always create reflection data for static fields
+                 as it is used in the creation of the field itself. */
+              tree init = make_field_value (field);
 	      tree initial = DECL_INITIAL (field);
 	      static_field_count++;
 	      static_fields = tree_cons (NULL_TREE, init, static_fields);
@@ -1603,8 +1634,9 @@
 	      rest_of_decl_compilation (field, 1, 1);
 	      DECL_INITIAL (field) = initial;
 	    }
-	  else
+	  else if (uses_jv_markobj || !flag_reduced_reflection)
 	    {
+              tree init = make_field_value (field);
 	      instance_field_count++;
 	      instance_fields = tree_cons (NULL_TREE, init, instance_fields);
 	    }
@@ -1643,9 +1675,35 @@
 	 which we don't have a .class file.  */
       if (METHOD_DUMMY (method))
 	continue;
-      init = make_method_value (method);
-      method_count++;
-      methods = tree_cons (NULL_TREE, init, methods);
+
+      /* Generate method reflection data if:
+
+          - !flag_reduced_reflection.
+
+          - <clinit> -- The runtime uses reflection to initialize the
+            class.
+
+          - Any method in class java.lang.Class -- Class.forName() and
+            perhaps other things require it.
+
+          - class$ -- It does not work if reflection data missing.
+
+          - main -- Reflection is used to find main(String[]) methods.
+
+          - public not static -- It is potentially part of an
+            interface.  The runtime uses reflection data to build
+            interface dispatch tables.  */
+      if (!flag_reduced_reflection
+          || DECL_CLINIT_P (method)
+          || DECL_NAME (type_decl) == id_class
+          || DECL_NAME (method) == id_main
+          || (METHOD_PUBLIC (method) && !METHOD_STATIC (method))
+          || TYPE_DOT_CLASS (type) == method)
+        {
+          init = make_method_value (method);
+          method_count++;
+          methods = tree_cons (NULL_TREE, init, methods);
+        }
     }
   method_array_type = build_prim_array_type (method_type_node, method_count);
   methods_decl = build_decl (VAR_DECL, mangled_classname ("_MT_", type),
@@ -1657,21 +1715,6 @@
   DECL_IGNORED_P (methods_decl) = 1;
   rest_of_decl_compilation (methods_decl, 1, 0);
 
-  if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
-      && !flag_indirect_dispatch)
-    {
-      tree dtable = get_dispatch_table (type, this_class_addr);
-      dtable_decl = build_dtable_decl (type);
-      DECL_INITIAL (dtable_decl) = dtable;
-      TREE_STATIC (dtable_decl) = 1;
-      DECL_ARTIFICIAL (dtable_decl) = 1;
-      DECL_IGNORED_P (dtable_decl) = 1;
-      TREE_PUBLIC (dtable_decl) = 1;
-      rest_of_decl_compilation (dtable_decl, 1, 0);
-      if (type == class_type_node)
-	class_dtable_decl = dtable_decl;
-    }
-
   if (class_dtable_decl == NULL_TREE)
     {
       class_dtable_decl = build_dtable_decl (class_type_node);
@@ -1781,7 +1824,8 @@
 		    CLASS_INTERFACE (type_decl) ? null_pointer_node : super);
   PUSH_FIELD_VALUE (cons, "constants", constant_pool_constructor);
   PUSH_FIELD_VALUE (cons, "methods",
-		    build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
+                    methods_decl == NULL_TREE ? null_pointer_node
+		    : build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
   PUSH_FIELD_VALUE (cons, "method_count",
 		    build_int_cst (NULL_TREE, method_count));
 
Index: gcc/java/lang.opt
===================================================================
--- gcc/java/lang.opt	(revision 111859)
+++ gcc/java/lang.opt	(working copy)
@@ -164,6 +164,10 @@
 foutput-class-dir=
 Java Joined RejectNegative
 
+freduced-reflection
+Java Var(flag_reduced_reflection)
+Reduce the amount of reflection meta-data generated
+
 fstore-check
 Java Var(flag_store_check) Init(1)
 Enable assignability checks for stores into object arrays
Index: gcc/java/lang.c
===================================================================
--- gcc/java/lang.c	(revision 111859)
+++ gcc/java/lang.c	(working copy)
@@ -608,6 +608,15 @@
   if (! flag_indirect_dispatch)
     flag_verify_invocations = true;
 
+  if (flag_reduced_reflection)
+    {
+      if (flag_indirect_dispatch)
+        error ("-findirect-dispatch is incompatible "
+               "with -freduced-reflection");
+      if (flag_jni)
+        error ("-fjni is incompatible with -freduced-reflection");
+    }
+
   /* Open input file.  */
 
   if (filename == 0 || !strcmp (filename, "-"))
Index: gcc/java/java-tree.h
===================================================================
--- gcc/java/java-tree.h	(revision 111859)
+++ gcc/java/java-tree.h	(working copy)
@@ -215,6 +215,9 @@
 /* When zero, don't generate runtime array store checks. */
 extern int flag_store_check;
 
+/* When nonzero, generate only a limited set of class meta-data. */
+extern int flag_reduced_reflection;
+
 /* Encoding used for source files.  */
 extern const char *current_encoding;
 
Index: gcc/java/gcj.texi
===================================================================
--- gcc/java/gcj.texi	(revision 111859)
+++ gcc/java/gcj.texi	(working copy)
@@ -546,6 +546,28 @@
 @code{Class.forName()} will search @samp{CLASSPATH} to find the
 desired class.
 
+@item -freduced-reflection
+This option causes the code generated by @command{gcj} to contain a
+reduced amount of the class meta-data used to support runtime
+reflection. The cost of this savings is the loss of
+the ability to use certain reflection capabilities of the standard
+Java runtime environment. When set all meta-data except for that
+which is needed to obtain correct runtime semantics is eliminated.
+
+For code that does not use reflection (i.e. the methods in the
+@code{java.lang.reflect} package), @code{-freduced-reflection}
+will result in proper operation with a savings in executable code size.
+
+JNI (@code{-fjni}) and the binary compatibility ABI
+(@code{-findirect-dispatch}) do not work properly without full
+reflection meta-data.  Because of this, it is an error to use these options
+with @code{-freduced-reflection}.
+
+@strong{Caution:} If there is no reflection meta-data, code that uses
+a @code{SecurityManager} may not work properly.  Also calling
+@code{Class.forName()} may fail if the calling method has no
+reflection meta-data.
+
 @end table
 
 
Index: gcc/java/boehm.c
===================================================================
--- gcc/java/boehm.c	(revision 111859)
+++ gcc/java/boehm.c	(working copy)
@@ -1,5 +1,5 @@
 /* Functions related to the Boehm garbage collector.
-   Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -184,7 +184,7 @@
   /* If the object is all pointers, or if the part with pointers fits
      in our bitmap, then we are ok.  Otherwise we have to allocate it
      a different way.  */
-  if (all_bits_set != -1)
+  if (all_bits_set != -1 || (pointer_after_end && flag_reduced_reflection))
     {
       /* In this case the initial part of the object is all reference
 	 fields, and the end of the object is all non-reference
@@ -193,7 +193,12 @@
 	 this:
 	 value = DS_LENGTH | WORDS_TO_BYTES (last_set_index + 1);
 	 DS_LENGTH is 0.
-	 WORDS_TO_BYTES shifts by log2(bytes-per-pointer).  */
+	 WORDS_TO_BYTES shifts by log2(bytes-per-pointer).
+
+         In the case of flag_reduced_reflection and the bitmap would
+         overflow, we tell the gc that the object is all pointers so
+         that we don't have to emit reflection data for run time
+         marking. */
       count = 0;
       low = 0;
       high = 0;

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