public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Allocate Class instancs on heap; not conservatively scan DSOs
@ 2006-04-26  8:43 Andrew Haley
  2006-04-26 13:59 ` Daniel Jacobowitz
  2006-04-26 17:05 ` Bryce McKinlay
  0 siblings, 2 replies; 7+ messages in thread
From: Andrew Haley @ 2006-04-26  8:43 UTC (permalink / raw)
  To: gcc-patches, java-patches

This is a small (!) part of a more ambitious set of changes I've been
developing on a branch.  It moves all static data out of BC-compiled
DSOs onto the heap, so we no longer need to scan static data
conservatively.  It's been tested extensively with JOnAS and Eclipse;
with Eclipse, the time spent garbage collecting is halved.

It's still not completely done & dusted, but it's good enough to be
merged onto trunk, to be improved there.

Andrew.


2006-04-21  Andrew Haley  <aph@redhat.com>

	* lang.c (java_init): Handle flag_indirect_classes.
	* jvgenmain.c: Use "class$$" instead of "class$".
	* mangle.c (java_mangle_decl): Accept RECORD_TYPEs sw well as
	DECLs.
	(mangle_class_field): Special case "class$$" as well as "class$".
	* constants.c (build_ref_from_constant_pool): If
	flag_indirect_classes, generate a ref into the heap.
	* decl.c (constants_field_decl_node,
	constants_data_field_decl_node): New.
	* class.c (build_static_class_ref): New.
	(build_classdollar_field): Factor out from build_class_ref().
	(make_field_value): Handle static fields in heap.
	(make_class_data): Make sure we get a static ref to class.
	Make class initializer const if flag_indirect_classes.
	(register_class): Build a class_ref for initialization if
	flag_indirect_classes.
	(emit_indirect_register_classes): New.

Index: gcc/java/class.c
===================================================================
--- gcc/java/class.c	(revision 113114)
+++ gcc/java/class.c	(working copy)
@@ -953,6 +953,71 @@
   return convert (promote_type (class_ptr_type), cl);
 }
 
+static tree
+build_static_class_ref (tree type)
+{
+  tree decl_name, decl, ref;
+
+  if (TYPE_SIZE (type) == error_mark_node)
+    return null_pointer_node;
+  decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
+				"", '/', '/', ".class$$");
+  decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
+  if (decl == NULL_TREE)
+    {
+      decl = build_decl (VAR_DECL, decl_name, class_type_node);
+      TREE_STATIC (decl) = 1;
+      if (! flag_indirect_classes)
+	TREE_PUBLIC (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
+      DECL_ARTIFICIAL (decl) = 1;
+      if (is_compiled_class (type) == 1)
+	DECL_EXTERNAL (decl) = 1;
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
+      DECL_CLASS_FIELD_P (decl) = 1;
+      DECL_CONTEXT (decl) = type;
+
+      /* ??? We want to preserve the DECL_CONTEXT we set just above,
+	 that that means not calling pushdecl_top_level.  */
+      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
+    }
+
+  ref = build1 (ADDR_EXPR, class_ptr_type, decl);
+  return ref;
+}
+
+static tree
+build_classdollar_field (tree type)
+{
+  tree decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
+				     "", '/', '/', ".class$");
+  tree decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
+
+  if (decl == NULL_TREE)
+    {
+      decl 
+	= build_decl (VAR_DECL, decl_name, 
+		      (build_type_variant 
+		       (build_pointer_type 
+			(build_type_variant (class_type_node, 
+					     /* const */ 1, 0)),
+			/* const */ 1, 0)));
+      TREE_STATIC (decl) = 1;
+      TREE_INVARIANT (decl) = 1;
+      TREE_CONSTANT (decl) = 1;
+      TREE_READONLY (decl) = 1;
+      TREE_PUBLIC (decl) = 1;
+      DECL_IGNORED_P (decl) = 1;
+      DECL_ARTIFICIAL (decl) = 1;
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
+      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
+      DECL_CLASS_FIELD_P (decl) = 1;
+      DECL_CONTEXT (decl) = type;
+    }
+
+  return decl;
+}
+
 /* Build a reference to the class TYPE.
    Also handles primitive types and array types. */
 
@@ -962,7 +1027,7 @@
   int is_compiled = is_compiled_class (type);
   if (is_compiled)
     {
-      tree ref, decl_name, decl;
+      tree ref, decl;
       if (TREE_CODE (type) == POINTER_TYPE)
 	type = TREE_TYPE (type);
 
@@ -971,34 +1036,15 @@
 	  && TREE_CODE (type) == RECORD_TYPE)
 	return build_indirect_class_ref (type);
 
+      if (type == output_class && flag_indirect_classes)
+	return build_classdollar_field (type);
+      
       if (TREE_CODE (type) == RECORD_TYPE)
-	{
-	  if (TYPE_SIZE (type) == error_mark_node)
-	    return null_pointer_node;
-	  decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
-					"", '/', '/', ".class");
-	  decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
-	  if (decl == NULL_TREE)
-	    {
-	      decl = build_decl (VAR_DECL, decl_name, class_type_node);
-	      TREE_STATIC (decl) = 1;
-	      TREE_PUBLIC (decl) = 1;
-	      DECL_IGNORED_P (decl) = 1;
-	      DECL_ARTIFICIAL (decl) = 1;
-	      if (is_compiled == 1)
-		DECL_EXTERNAL (decl) = 1;
-	      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
-	      DECL_CLASS_FIELD_P (decl) = 1;
-	      DECL_CONTEXT (decl) = type;
-
-	      /* ??? We want to preserve the DECL_CONTEXT we set just above,
-		 that that means not calling pushdecl_top_level.  */
-	      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
-	    }
-	}
+	return build_static_class_ref (type);
       else
 	{
 	  const char *name;
+	  tree decl_name;
 	  char buffer[25];
 	  if (flag_emit_class_files)
 	    {
@@ -1296,16 +1342,22 @@
   PUSH_FIELD_VALUE (finit, "accflags", build_int_cst (NULL_TREE, flags));
   PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
 
-  PUSH_FIELD_VALUE
-    (finit, "info",
-     build_constructor_from_list (field_info_union_node,
-	    build_tree_list
-	    ((FIELD_STATIC (fdecl)
-	      ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
-	      : TYPE_FIELDS (field_info_union_node)),
-	     (FIELD_STATIC (fdecl)
-	      ? build_address_of (fdecl)
-	      : byte_position (fdecl)))));
+  {
+    tree field_address = integer_zero_node;
+    if (! flag_indirect_classes && FIELD_STATIC (fdecl))
+      field_address = build_address_of (fdecl);
+
+    PUSH_FIELD_VALUE
+      (finit, "info",
+       build_constructor_from_list (field_info_union_node,
+	 build_tree_list
+	   ((FIELD_STATIC (fdecl)
+	     ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
+	     : TYPE_FIELDS (field_info_union_node)),
+	    (FIELD_STATIC (fdecl)
+	     ? field_address
+	     : byte_position (fdecl)))));
+  }
 
   FINISH_RECORD_CONSTRUCTOR (finit);
   return finit;
@@ -1599,7 +1651,7 @@
   tree dtable_start_offset = build_int_cst (NULL_TREE,
 					    2 * POINTER_SIZE / BITS_PER_UNIT);
 
-  this_class_addr = build_class_ref (type);
+  this_class_addr = build_static_class_ref (type);
   decl = TREE_OPERAND (this_class_addr, 0);
 
   if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
@@ -1613,7 +1665,8 @@
       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 (! flag_indirect_classes)
+	rest_of_decl_compilation (dtable_decl, 1, 0);
       if (type == class_type_node)
 	class_dtable_decl = dtable_decl;
     }
@@ -1958,8 +2011,21 @@
   if (flag_hash_synchronization && POINTER_SIZE < 64)
     DECL_ALIGN (decl) = 64; 
   
+  if (flag_indirect_classes)
+    {
+      TREE_READONLY (decl) = 1;
+      TREE_CONSTANT (DECL_INITIAL (decl)) = 1;
+    }
+
   rest_of_decl_compilation (decl, 1, 0);
   
+  {
+    tree classdollar_field = build_classdollar_field (type);
+    if (!flag_indirect_classes)
+      DECL_INITIAL (classdollar_field) = build_static_class_ref (type);
+    rest_of_decl_compilation (classdollar_field, 1, 0);
+  }
+
   TYPE_OTABLE_DECL (type) = NULL_TREE;
   TYPE_ATABLE_DECL (type) = NULL_TREE;
   TYPE_CTABLE_DECL (type) = NULL_TREE;
@@ -2465,10 +2531,65 @@
   if (!registered_class)
     registered_class = VEC_alloc (tree, gc, 8);
 
-  node = TREE_OPERAND (build_class_ref (current_class), 0);
+  if (flag_indirect_classes)
+    node = current_class;
+  else
+    node = TREE_OPERAND (build_class_ref (current_class), 0);
   VEC_safe_push (tree, gc, registered_class, node);
 }
 
+/* Emit a function that calls _Jv_NewClassFromInitializer for every
+   class.  */
+
+static void
+emit_indirect_register_classes (tree *list_p)
+{
+  tree klass, t, register_class_fn;
+  int i;
+
+  tree init = NULL_TREE;
+  int size = VEC_length (tree, registered_class) * 2 + 1;
+  tree class_array_type
+    = build_prim_array_type (ptr_type_node, size);
+  tree cdecl = build_decl (VAR_DECL, get_identifier ("_Jv_CLS"),
+			   class_array_type);
+  tree reg_class_list;
+  for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
+    {
+      init = tree_cons (NULL_TREE, 
+			fold_convert (ptr_type_node, 
+				      build_static_class_ref (klass)), init);
+      init = tree_cons 
+	(NULL_TREE, 
+	 fold_convert (ptr_type_node, 
+		       build_address_of (build_classdollar_field (klass))),
+	 init);
+    }
+  init = tree_cons (NULL_TREE, integer_zero_node, init); 
+  DECL_INITIAL (cdecl) = build_constructor_from_list (class_array_type,
+						      nreverse (init));
+  TREE_CONSTANT (DECL_INITIAL (cdecl)) = 1;
+  TREE_STATIC (cdecl) = 1;
+  DECL_ARTIFICIAL (cdecl) = 1;
+  DECL_IGNORED_P (cdecl) = 1;
+  TREE_READONLY (cdecl) = 1;
+  TREE_CONSTANT (cdecl) = 1;
+  rest_of_decl_compilation (cdecl, 1, 0);
+  reg_class_list = fold_convert (ptr_type_node, build_address_of (cdecl));
+
+  t = build_function_type_list (void_type_node, 
+				build_pointer_type (ptr_type_node), NULL);
+  t = build_decl (FUNCTION_DECL, 
+		  get_identifier ("_Jv_RegisterNewClasses"), t);
+  TREE_PUBLIC (t) = 1;
+  DECL_EXTERNAL (t) = 1;
+  register_class_fn = t;
+  t = tree_cons (NULL, reg_class_list, NULL);
+  t = build_function_call_expr (register_class_fn, t);
+  append_to_statement_list (t, list_p);
+}
+
+
 /* Emit something to register classes at start-up time.
 
    The preferred mechanism is through the .jcr section, which contain
@@ -2485,6 +2606,12 @@
   if (registered_class == NULL)
     return;
 
+  if (flag_indirect_classes)
+    {
+      emit_indirect_register_classes (list_p);
+      return;
+    }
+
   /* TARGET_USE_JCR_SECTION defaults to 1 if SUPPORTS_WEAK and
      TARGET_ASM_NAMED_SECTION, else 0.  Some targets meet those conditions
      but lack suitable crtbegin/end objects or linker support.  These
Index: gcc/java/decl.c
===================================================================
--- gcc/java/decl.c	(revision 113114)
+++ gcc/java/decl.c	(working copy)
@@ -123,6 +123,12 @@
 /* The decl for "_Jv_ResolvePoolEntry".  */
 tree soft_resolvepoolentry_node;
 
+/* The decl for the .constants field of an instance of Class.  */
+tree constants_field_decl_node;
+
+/* The decl for the .data field of an instance of Class.  */
+tree constants_data_field_decl_node;
+
 #if defined(DEBUG_JAVA_BINDING_LEVELS)
 int binding_depth = 0;
 int is_class_level = 0;
@@ -883,6 +889,7 @@
   PUSH_FIELD (constants_type_node, field, "size", unsigned_int_type_node);
   PUSH_FIELD (constants_type_node, field, "tags", ptr_type_node);
   PUSH_FIELD (constants_type_node, field, "data", ptr_type_node);
+  constants_data_field_decl_node = field;
   FINISH_RECORD (constants_type_node);
   build_decl (TYPE_DECL, get_identifier ("constants"), constants_type_node);
 
@@ -924,6 +931,7 @@
   PUSH_FIELD (class_type_node, field, "accflags", access_flags_type_node);
   PUSH_FIELD (class_type_node, field, "superclass", class_ptr_type);
   PUSH_FIELD (class_type_node, field, "constants", constants_type_node);
+  constants_field_decl_node = field;
   PUSH_FIELD (class_type_node, field, "methods", method_ptr_type_node);
   PUSH_FIELD (class_type_node, field, "method_count", short_type_node);
   PUSH_FIELD (class_type_node, field, "vtable_method_count", short_type_node);
Index: gcc/java/constants.c
===================================================================
--- gcc/java/constants.c	(revision 113114)
+++ gcc/java/constants.c	(working copy)
@@ -458,8 +458,29 @@
 {
   tree d = build_constant_data_ref ();
   tree i = build_int_cst (NULL_TREE, index);
-  return build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
+  if (flag_indirect_classes)
+    {
+      tree decl = build_class_ref (output_class);
+      tree klass = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (decl)),
+			   decl);
+      tree constants = build3 (COMPONENT_REF, 
+			       TREE_TYPE (constants_field_decl_node), klass,
+			       constants_field_decl_node,
+			       NULL_TREE);
+      tree data = build3 (COMPONENT_REF, 
+			  TREE_TYPE (constants_data_field_decl_node), 
+			  constants,
+			  constants_data_field_decl_node,
+			  NULL_TREE);
+      data = fold_convert (build_pointer_type (TREE_TYPE (d)), data);
+      d = build1 (INDIRECT_REF, TREE_TYPE (d), data);
+      /* FIXME: These should be cached.  */
+      TREE_INVARIANT (d) = 1;
+    }
+  d = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
 		 NULL_TREE, NULL_TREE);
+  TREE_INVARIANT (d) = 1;
+  return d;
 }
 
 /* Build an initializer for the constants field of the current constant pool.
Index: gcc/java/lang.opt
===================================================================
--- gcc/java/lang.opt	(revision 113114)
+++ gcc/java/lang.opt	(working copy)
@@ -146,6 +146,10 @@
 Java Var(flag_hash_synchronization)
 Assume the runtime uses a hash table to map an object to its synchronization structure
 
+findirect-classes
+Java Var(flag_indirect_classes) Init(1)
+Generate instances of Class at runtime
+
 findirect-dispatch
 Java Var(flag_indirect_dispatch)
 Use offset tables for virtual method calls
Index: gcc/java/mangle.c
===================================================================
--- gcc/java/mangle.c	(revision 113114)
+++ gcc/java/mangle.c	(working copy)
@@ -79,6 +79,9 @@
 void
 java_mangle_decl (tree decl)
 {
+  if (TREE_CODE (decl) == RECORD_TYPE)
+    mangle_type (decl);
+
   /* A copy of the check from the beginning of lhd_set_decl_assembler_name.
      Only FUNCTION_DECLs and VAR_DECLs for variables with static storage
      duration need a real DECL_ASSEMBLER_NAME.  */
@@ -99,7 +102,7 @@
 	    {
 	      if (DECL_CLASS_FIELD_P (decl))
 		{
-		  mangle_class_field (DECL_CONTEXT (decl));
+		  mangle_class_field (decl);
 		  break;
 		}
 	      else if (DECL_VTABLE_P (decl))
@@ -130,10 +133,14 @@
 /* Beginning of the helper functions */
 
 static void
-mangle_class_field (tree type)
+mangle_class_field (tree decl)
 {
+  tree type = DECL_CONTEXT (decl);
   mangle_record_type (type, /* for_pointer = */ 0);
-  MANGLE_RAW_STRING ("6class$");
+  if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+    MANGLE_RAW_STRING ("6class$");
+  else
+    MANGLE_RAW_STRING ("7class$$");
   obstack_1grow (mangle_obstack, 'E');
 }
 
@@ -229,7 +236,7 @@
   append_gpp_mangled_name (IDENTIFIER_POINTER (name),
 			   IDENTIFIER_LENGTH (name));
 
-  /* If NAME happens to be a C++ keyword, add `$'. */
+  /* If NAME happens to be a C++ keyword, add `$'.  */
   if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
     obstack_1grow (mangle_obstack, '$');
 }
Index: gcc/java/jvgenmain.c
===================================================================
--- gcc/java/jvgenmain.c	(revision 113114)
+++ gcc/java/jvgenmain.c	(working copy)
@@ -127,11 +127,11 @@
     }
   fprintf (stream, "  0\n};\n\n");
 
-  fprintf (stream, "extern int %s;\n", mangled_classname);
   fprintf (stream, "int main (int argc, const char **argv)\n");
   fprintf (stream, "{\n");
   fprintf (stream, "   _Jv_Compiler_Properties = props;\n");
-  fprintf (stream, "   JvRunMain (&%s, argc, argv);\n", mangled_classname);
+  fprintf (stream, "   extern void *%s;\n", mangled_classname);
+  fprintf (stream, "   JvRunMain (%s, argc, argv);\n", mangled_classname);
   fprintf (stream, "}\n");
   if (stream != stdout && fclose (stream) != 0)
     {
@@ -153,16 +153,16 @@
 
   for (ptr = string; *ptr; ptr++ )
     {
-      if (ptr[0] == '.')
+      if (*ptr == '.')
 	{
-	  append_gpp_mangled_name (&ptr [-count], count);
+	  append_gpp_mangled_name (ptr - count, count);
 	  count = 0;
 	}
       else
 	count++;
     }
   append_gpp_mangled_name (&ptr [-count], count);
-  obstack_grow (mangle_obstack, "6class$E", 8);
+  obstack_grow (mangle_obstack, "7class$$E", strlen ("7class$$E"));
   obstack_1grow (mangle_obstack, '\0');
   return obstack_finish (mangle_obstack);
 }
Index: gcc/java/lang.c
===================================================================
--- gcc/java/lang.c	(revision 113114)
+++ gcc/java/lang.c	(working copy)
@@ -368,6 +368,9 @@
   if (flag_indirect_dispatch)
     always_initialize_class_p = true;
 
+  if (!flag_indirect_dispatch)
+    flag_indirect_classes = false;
+
   /* Force minimum function alignment if g++ uses the least significant
      bit of function pointers to store the virtual bit. This is required
      to keep vtables compatible.  */
Index: gcc/java/java-tree.h
===================================================================
--- gcc/java/java-tree.h	(revision 113114)
+++ gcc/java/java-tree.h	(working copy)
@@ -208,6 +208,9 @@
    initialization optimization should be performed.  */
 extern int flag_optimize_sci;
 
+/* Generate instances of Class at runtime.  */
+extern int flag_indirect_classes;
+
 /* When nonzero, use offset tables for virtual method calls
    in order to improve binary compatibility. */
 extern int flag_indirect_dispatch;
@@ -270,6 +273,12 @@
 extern GTY(()) tree java_io_serializable_identifier_node;
 extern GTY(()) tree gcj_abi_version;
 
+/* The decl for the .constants field of an instance of Class.  */
+extern GTY(()) tree constants_field_decl_node;
+
+/* The decl for the .data field of an instance of Class.  */
+extern GTY(()) tree constants_data_field_decl_node;
+
 enum java_tree_index
 {
   JTI_PROMOTED_BYTE_TYPE_NODE,


2006-04-21  Andrew Haley  <aph@redhat.com>

	* include/execution.h (struct _Jv_CompiledEngine): Define for
	compiled classes.
	* java/lang/natClassLoader.cc (_Jv_RegisterClasses): Call
	_Jv_RegisterLibForGc.
	(_Jv_RegisterClasses_Counted): Likewise.
	(_Jv_NewClassFromInitializer): New.
	(_Jv_RegisterNewClasses): New.
	* sources.am: Regenerate.
	* boehm.cc (_Jv_GC_has_static_roots): new.
	(_Jv_InitGC): Call GC_register_has_static_roots_callback.
	(filename_node, find_file, _Jv_print_gc_store, new_node,
	_Jv_GC_has_static_roots, _Jv_RegisterLibForGc): New.
	* scripts/makemake.tcl: Add -fno-indirect-classes.
	* Makefile.in: Regenerate.
	* link.cc (resolve_pool_entry): Allocate constant pool.
	Allocate fields.
	
Index: libjava/link.cc
===================================================================
--- libjava/link.cc	(revision 113114)
+++ libjava/link.cc	(working copy)
@@ -21,6 +21,12 @@
 
 #include <java-interp.h>
 
+// Set GC_DEBUG before including gc.h!
+#ifdef LIBGCJ_GC_DEBUG
+# define GC_DEBUG
+#endif
+#include <gc.h>
+
 #include <jvm.h>
 #include <gcj/cni.h>
 #include <string.h>
@@ -265,6 +271,21 @@
 {
   using namespace java::lang::reflect;
 
+  if (GC_base (klass) && klass->constants.data
+      && ! GC_base (klass->constants.data))
+    {
+      jsize count = klass->constants.size;
+      if (count)
+	{
+	  _Jv_word* constants
+	    = (_Jv_word*) _Jv_AllocRawObj (count * sizeof (_Jv_word));
+	  memcpy ((void*)constants,
+		  (void*)klass->constants.data,
+		  count * sizeof (_Jv_word));
+	  klass->constants.data = constants;
+	}
+    }
+
   _Jv_Constants *pool = &klass->constants;
 
   if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
@@ -1893,6 +1914,21 @@
   java::lang::Thread *save = klass->thread;
   klass->thread = self;
 
+  // Allocate memory for static fields and constants.
+  if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
+    {
+      jsize count = klass->field_count;
+      if (count)
+	{
+	  _Jv_Field* fields 
+	    = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
+	  memcpy ((void*)fields,
+		  (void*)klass->fields,
+		  count * sizeof (_Jv_Field));
+	  klass->fields = fields;
+	}
+    }
+      
   // Print some debugging info if requested.  Interpreted classes are
   // handled in defineclass, so we only need to handle the two
   // pre-compiled cases here.
Index: libjava/scripts/makemake.tcl
===================================================================
--- libjava/scripts/makemake.tcl	(revision 113114)
+++ libjava/scripts/makemake.tcl	(working copy)
@@ -224,7 +224,7 @@
     set omit "| grep -v $exclusion_map($package)"
   }
   puts  "\t@find classpath/lib/$package -name '*.class'${omit} > $tname"
-  puts "\t\$(LTGCJCOMPILE) -fjni -findirect-dispatch -c -o $loname @$tname"
+  puts "\t\$(LTGCJCOMPILE) -fjni -findirect-dispatch -fno-indirect-classes -c -o $loname @$tname"
   puts "\t@rm -f $tname"
   puts ""
 
Index: libjava/gnu/gcj/runtime/natSharedLibLoader.cc
===================================================================
--- libjava/gnu/gcj/runtime/natSharedLibLoader.cc	(revision 113114)
+++ libjava/gnu/gcj/runtime/natSharedLibLoader.cc	(working copy)
@@ -21,6 +21,7 @@
 
 #ifdef HAVE_DLOPEN
 #include <dlfcn.h>
+#include <link.h>
 
 /* Only used during dlopen, while having a lock on Class.class. */
 static java::lang::ClassLoader *curLoader;
Index: libjava/boehm.cc
===================================================================
--- libjava/boehm.cc	(revision 113114)
+++ libjava/boehm.cc	(working copy)
@@ -32,6 +32,13 @@
 #undef PACKAGE_TARNAME
 #undef PACKAGE_VERSION
 
+#ifdef HAVE_DLFCN_H
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <link.h>
+#endif
+
 extern "C"
 {
 #include <gc_config.h>
@@ -64,6 +71,8 @@
 // Freelist used for Java arrays.
 static void **array_free_list;
 
+static int _Jv_GC_has_static_roots (const char *filename, void *, size_t);
+
 \f
 
 // This is called by the GC during the mark phase.  It marks a Java
@@ -468,10 +477,21 @@
 _Jv_InitGC (void)
 {
   int proc;
+  static bool gc_initialized;
+
+  if (gc_initialized)
+    return;
+
+  gc_initialized = 1;
 
   // Ignore pointers that do not point to the start of an object.
   GC_all_interior_pointers = 0;
 
+#ifdef HAVE_DLFCN_H
+  // Tell the collector to ask us before scanning DSOs.
+  GC_register_has_static_roots_callback (_Jv_GC_has_static_roots);
+#endif
+
   // Configure the collector to use the bitmap marking descriptors that we
   // stash in the class vtable.
   // We always use mark proc descriptor 0, since the compiler knows
@@ -559,3 +579,98 @@
   // For now, always reclaim soft references.  FIXME.
   return true;
 }
+
+\f
+
+#ifdef HAVE_DLFCN_H
+
+// We keep a store of the filenames of DSOs that need to be
+// conservatively scanned by the garbage collector.  During collection
+// the gc calls _Jv_GC_has_static_roots() to see if the data segment
+// of a DSO should be scanned.
+typedef struct filename_node
+{
+  char *name;
+  struct filename_node *link;
+} filename_node;
+
+#define FILENAME_STORE_SIZE 17
+static filename_node *filename_store[FILENAME_STORE_SIZE];
+
+// Find a filename in filename_store.
+static filename_node **
+find_file (const char *filename)
+{
+  int index = strlen (filename) % FILENAME_STORE_SIZE;
+  filename_node **node = &filename_store[index];
+  
+  while (*node)
+    {
+      if (strcmp ((*node)->name, filename) == 0)
+	return node;
+      node = &(*node)->link;
+    }
+
+  return node;
+}  
+
+// Print the store of filenames of DSOs that need collection.
+void
+_Jv_print_gc_store (void)
+{
+  for (int i = 0; i < FILENAME_STORE_SIZE; i++)
+    {
+      filename_node *node = filename_store[i];
+      while (node)
+	{
+	  fprintf (stderr, "%s\n", node->name);
+	  node = node->link;
+	}
+    }
+}
+
+// Create a new node in the store of libraries to collect.
+static filename_node *
+new_node (const char *filename)
+{
+  filename_node *node = (filename_node*)_Jv_Malloc (sizeof (filename_node));
+  node->name = (char *)_Jv_Malloc (strlen (filename) + 1);
+  node->link = NULL;
+  strcpy (node->name, filename);
+  
+  return node;
+}
+
+// Nonzero if the gc should scan this lib.
+static int 
+_Jv_GC_has_static_roots (const char *filename, void *, size_t)
+{
+  if (filename == NULL || strlen (filename) == 0)
+    // No filename; better safe than sorry.
+    return 1;
+
+  filename_node **node = find_file (filename);
+  if (*node)
+    return 1;
+
+  return 0;
+}
+
+#endif
+
+// Register the DSO that contains p for collection.
+void
+_Jv_RegisterLibForGc (const void *p __attribute__ ((__unused__)))
+{
+#ifdef HAVE_DLFCN_H
+  Dl_info info;
+  
+  if (dladdr (p, &info) != 0)
+    {
+      filename_node **node = find_file (info.dli_fname);
+      if (! *node)
+	*node = new_node (info.dli_fname);
+    }
+#endif
+}
+
Index: libjava/java/lang/natClassLoader.cc
===================================================================
--- libjava/java/lang/natClassLoader.cc	(revision 113114)
+++ libjava/java/lang/natClassLoader.cc	(working copy)
@@ -45,14 +45,17 @@
 #include <gnu/gcj/runtime/BootClassLoader.h>
 #include <gnu/gcj/runtime/SystemClassLoader.h>
 
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <link.h>
+
 // Size of local hash table.
 #define HASH_LEN 1013
 
 // Hash function for Utf8Consts.
 #define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN)
 
-static jclass loaded_classes[HASH_LEN];
-
 // This records classes which will be registered with the system class
 // loader when it is initialized.
 static jclass system_class_list;
@@ -62,6 +65,8 @@
 // no longer pay attention to the system abi flag.
 #define SYSTEM_LOADER_INITIALIZED ((jclass) -1)
 
+static jclass loaded_classes[HASH_LEN];
+
 // This is the root of a linked list of classes
 static jclass stack_head;
 
@@ -164,6 +169,8 @@
 void
 _Jv_RegisterClasses (const jclass *classes)
 {
+  _Jv_RegisterLibForGc (classes);
+
   for (; *classes; ++classes)
     {
       jclass klass = *classes;
@@ -178,6 +185,9 @@
 _Jv_RegisterClasses_Counted (const jclass * classes, size_t count)
 {
   size_t i;
+
+  _Jv_RegisterLibForGc (classes);
+
   for (i = 0; i < count; i++)
     {
       jclass klass = classes[i];
@@ -187,6 +197,41 @@
     }
 }
 
+// Create a class on the heap from an initializer struct.
+jclass
+_Jv_NewClassFromInitializer (const jclass class_initializer)
+{
+  jclass new_class = (jclass)_Jv_AllocObj (sizeof *new_class,
+					   &java::lang::Class::class$);  
+  memcpy ((void*)new_class, (void*)class_initializer, sizeof *new_class);
+
+  if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version))
+    (*_Jv_RegisterClassHook) (new_class);
+  
+  return new_class;
+}
+
+// Called by compiler-generated code at DSO initialization.  CLASSES
+// is an array of pairs: the first item of each pair is a pointer to
+// the initialized data that is a class initializer in a DSO, and the
+// second is a pointer to a class reference.
+// _Jv_NewClassFromInitializer() creates the new class (on the Java
+// heap) and we write the address of the new class into the address
+// pointed to by the second word.
+void
+_Jv_RegisterNewClasses (void **classes)
+{
+  _Jv_InitGC ();
+
+  jclass initializer;
+
+  while ((initializer = (jclass)*classes++))
+    {
+      jclass *class_ptr = (jclass *)*classes++;
+      *class_ptr = _Jv_NewClassFromInitializer (initializer);
+    }      
+}
+  
 void
 _Jv_RegisterClassHookDefault (jclass klass)
 {
@@ -389,6 +434,12 @@
 static jshort array_depth = 0;
 static jclass *array_ancestors = NULL;
 
+static jclass interfaces[] =
+{
+  &java::lang::Cloneable::class$,
+  &java::io::Serializable::class$
+};
+
 // Create a class representing an array of ELEMENT and store a pointer to it
 // in element->arrayclass. LOADER is the ClassLoader which _initiated_ the 
 // instantiation of this array. ARRAY_VTABLE is the vtable to use for the new 
@@ -464,11 +515,6 @@
   array_class->element_type = element;
 
   // Register our interfaces.
-  static jclass interfaces[] =
-    {
-      &java::lang::Cloneable::class$,
-      &java::io::Serializable::class$
-    };
   array_class->interfaces = interfaces;
   array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
 
Index: libjava/java/lang/Class.h
===================================================================
--- libjava/java/lang/Class.h	(revision 113114)
+++ libjava/java/lang/Class.h	(working copy)
@@ -39,6 +39,9 @@
 
 // We declare these here to avoid including gcj/cni.h.
 extern "C" void _Jv_InitClass (jclass klass);
+extern "C" jclass _Jv_NewClassFromInitializer 
+   (const jclass class_initializer);
+extern "C" void _Jv_RegisterNewClasses (void **classes);
 extern "C" void _Jv_RegisterClasses (const jclass *classes);
 extern "C" void _Jv_RegisterClasses_Counted (const jclass *classes,
 					     size_t count);
@@ -286,7 +289,7 @@
   JArray<jclass> *getClasses (void);
 
   java::lang::ClassLoader *getClassLoader (void);
-
+public:
   // This is an internal method that circumvents the usual security
   // checks when getting the class loader.
   java::lang::ClassLoader *getClassLoaderInternal (void)
@@ -427,6 +430,8 @@
 					       int method_idx);
 
   friend void ::_Jv_InitClass (jclass klass);
+  friend java::lang::Class* ::_Jv_NewClassFromInitializer (const jclass class_initializer);
+  friend void _Jv_RegisterNewClasses (void **classes);
 
   friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, 
 						 _Jv_Utf8Const*, jclass *);
Index: libjava/include/execution.h
===================================================================
--- libjava/include/execution.h	(revision 113114)
+++ libjava/include/execution.h	(working copy)
@@ -55,9 +55,25 @@
     return NULL;
   }
 
-  static void do_allocate_static_fields (jclass, int, int)
-  {
-    // Compiled classes don't need this.
+  static void do_allocate_static_fields (jclass klass,
+					 int pointer_size,
+					 int other_size)
+  {
+    // Splitting the allocations here lets us scan reference fields
+    // and avoid scanning non-reference fields.
+    char *reference_fields = (char *) _Jv_AllocRawObj (pointer_size);
+    char *non_reference_fields = (char *) _Jv_AllocBytes (other_size);
+
+    for (int i = 0; i < klass->field_count; i++)
+      {
+	_Jv_Field *field = &klass->fields[i];
+
+	if ((field->flags & java::lang::reflect::Modifier::STATIC) == 0)
+	  continue;
+
+	char *base = field->isRef() ? reference_fields : non_reference_fields;
+	field->u.addr  = base + field->u.boffset;
+      } 
   }
 
   static void do_create_ncode (jclass)
Index: libjava/include/boehm-gc.h
===================================================================
--- libjava/include/boehm-gc.h	(revision 113114)
+++ libjava/include/boehm-gc.h	(working copy)
@@ -19,6 +19,7 @@
 {
   void *_Jv_MarkObj (void *, void *, void *, void *);
   void *_Jv_MarkArray (void *, void *, void *, void *);
+  void _Jv_RegisterLibForGc (const void *);
 }
 
 // Enough stuff to inline _Jv_AllocObj.  Ugly.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26  8:43 Allocate Class instancs on heap; not conservatively scan DSOs Andrew Haley
@ 2006-04-26 13:59 ` Daniel Jacobowitz
  2006-04-26 14:11   ` Andrew Haley
  2006-04-26 17:05 ` Bryce McKinlay
  1 sibling, 1 reply; 7+ messages in thread
From: Daniel Jacobowitz @ 2006-04-26 13:59 UTC (permalink / raw)
  To: Andrew Haley; +Cc: gcc-patches, java-patches

On Wed, Apr 26, 2006 at 09:43:08AM +0100, Andrew Haley wrote:
> This is a small (!) part of a more ambitious set of changes I've been
> developing on a branch.  It moves all static data out of BC-compiled
> DSOs onto the heap, so we no longer need to scan static data
> conservatively.  It's been tested extensively with JOnAS and Eclipse;
> with Eclipse, the time spent garbage collecting is halved.

Nice!

> It's still not completely done & dusted, but it's good enough to be
> merged onto trunk, to be improved there.

You've got discretion on this as a front end maintainer; but we are in
Stage 3... is there enough time to get this done & dusted before we
branch for 4.2.0?

-- 
Daniel Jacobowitz
CodeSourcery

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26 13:59 ` Daniel Jacobowitz
@ 2006-04-26 14:11   ` Andrew Haley
  2006-04-26 16:32     ` Daniel Jacobowitz
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Haley @ 2006-04-26 14:11 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gcc-patches, java-patches

Daniel Jacobowitz writes:
 > On Wed, Apr 26, 2006 at 09:43:08AM +0100, Andrew Haley wrote:
 > > This is a small (!) part of a more ambitious set of changes I've been
 > > developing on a branch.  It moves all static data out of BC-compiled
 > > DSOs onto the heap, so we no longer need to scan static data
 > > conservatively.  It's been tested extensively with JOnAS and Eclipse;
 > > with Eclipse, the time spent garbage collecting is halved.
 > 
 > Nice!
 > 
 > > It's still not completely done & dusted, but it's good enough to be
 > > merged onto trunk, to be improved there.
 > 
 > You've got discretion on this as a front end maintainer; but we are in
 > Stage 3... is there enough time to get this done & dusted before we
 > branch for 4.2.0?

I certainly hope so.

gcj is a less mature project than C and C++ and our development
process is a very bad fit with the gcc release schedules.  Because of
that (and the fact that gcj bugs are not release-critical) the rules
regarding Stage 3 are somewhat more relaxed.  We discussed this at the
GCC Summit a few years back, and the SC agreed to give gcj maintainers
leeway to make our own decisions in this area.

If this patch doesn't turn out to be sufficiently stable for a real
release it can be disabled with a one-line change.

Andrew.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26 14:11   ` Andrew Haley
@ 2006-04-26 16:32     ` Daniel Jacobowitz
  0 siblings, 0 replies; 7+ messages in thread
From: Daniel Jacobowitz @ 2006-04-26 16:32 UTC (permalink / raw)
  To: Andrew Haley; +Cc: gcc-patches, java-patches

On Wed, Apr 26, 2006 at 03:11:04PM +0100, Andrew Haley wrote:
> I certainly hope so.
> 
> gcj is a less mature project than C and C++ and our development
> process is a very bad fit with the gcc release schedules.  Because of
> that (and the fact that gcj bugs are not release-critical) the rules
> regarding Stage 3 are somewhat more relaxed.  We discussed this at the
> GCC Summit a few years back, and the SC agreed to give gcj maintainers
> leeway to make our own decisions in this area.

OK, thanks.  Just checking!

-- 
Daniel Jacobowitz
CodeSourcery

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26  8:43 Allocate Class instancs on heap; not conservatively scan DSOs Andrew Haley
  2006-04-26 13:59 ` Daniel Jacobowitz
@ 2006-04-26 17:05 ` Bryce McKinlay
  2006-04-26 17:16   ` Andrew Haley
  2006-05-10 17:37   ` Andrew Haley
  1 sibling, 2 replies; 7+ messages in thread
From: Bryce McKinlay @ 2006-04-26 17:05 UTC (permalink / raw)
  To: Andrew Haley; +Cc: gcc-patches, java-patches

Very nice!

For a long time we've talked about putting the class data in a 
pointer-free format, instead of storing them as static jclasses. It 
looks like this patch has taken care of much of the hard work and will 
make changing the class data format easier.

One suggestion - I think it would be good to make the comments a bit 
more clear on which libgcj functions are called by the compiler to 
register classes for the -findirect-classes case, and which are for the 
non-indirect case. Its obvious from reading the patch why there is both 
a _Jv_RegisterClasses and  _Jv_RegisterNewClasses, but it may not be for 
someone browsing the code later.

Also, the comment on emit_indirect_register_classes() doesn't look right 
- it doesn't call _Jv_NewClassFromInitailizer directly.

Bryce


Andrew Haley wrote:
> This is a small (!) part of a more ambitious set of changes I've been
> developing on a branch.  It moves all static data out of BC-compiled
> DSOs onto the heap, so we no longer need to scan static data
> conservatively.  It's been tested extensively with JOnAS and Eclipse;
> with Eclipse, the time spent garbage collecting is halved.
>
> It's still not completely done & dusted, but it's good enough to be
> merged onto trunk, to be improved there.
>
> Andrew.
>
>
> 2006-04-21  Andrew Haley  <aph@redhat.com>
>
> 	* lang.c (java_init): Handle flag_indirect_classes.
> 	* jvgenmain.c: Use "class$$" instead of "class$".
> 	* mangle.c (java_mangle_decl): Accept RECORD_TYPEs sw well as
> 	DECLs.
> 	(mangle_class_field): Special case "class$$" as well as "class$".
> 	* constants.c (build_ref_from_constant_pool): If
> 	flag_indirect_classes, generate a ref into the heap.
> 	* decl.c (constants_field_decl_node,
> 	constants_data_field_decl_node): New.
> 	* class.c (build_static_class_ref): New.
> 	(build_classdollar_field): Factor out from build_class_ref().
> 	(make_field_value): Handle static fields in heap.
> 	(make_class_data): Make sure we get a static ref to class.
> 	Make class initializer const if flag_indirect_classes.
> 	(register_class): Build a class_ref for initialization if
> 	flag_indirect_classes.
> 	(emit_indirect_register_classes): New.
>
> Index: gcc/java/class.c
> ===================================================================
> --- gcc/java/class.c	(revision 113114)
> +++ gcc/java/class.c	(working copy)
> @@ -953,6 +953,71 @@
>    return convert (promote_type (class_ptr_type), cl);
>  }
>  
> +static tree
> +build_static_class_ref (tree type)
> +{
> +  tree decl_name, decl, ref;
> +
> +  if (TYPE_SIZE (type) == error_mark_node)
> +    return null_pointer_node;
> +  decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
> +				"", '/', '/', ".class$$");
> +  decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
> +  if (decl == NULL_TREE)
> +    {
> +      decl = build_decl (VAR_DECL, decl_name, class_type_node);
> +      TREE_STATIC (decl) = 1;
> +      if (! flag_indirect_classes)
> +	TREE_PUBLIC (decl) = 1;
> +      DECL_IGNORED_P (decl) = 1;
> +      DECL_ARTIFICIAL (decl) = 1;
> +      if (is_compiled_class (type) == 1)
> +	DECL_EXTERNAL (decl) = 1;
> +      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
> +      DECL_CLASS_FIELD_P (decl) = 1;
> +      DECL_CONTEXT (decl) = type;
> +
> +      /* ??? We want to preserve the DECL_CONTEXT we set just above,
> +	 that that means not calling pushdecl_top_level.  */
> +      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
> +    }
> +
> +  ref = build1 (ADDR_EXPR, class_ptr_type, decl);
> +  return ref;
> +}
> +
> +static tree
> +build_classdollar_field (tree type)
> +{
> +  tree decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
> +				     "", '/', '/', ".class$");
> +  tree decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
> +
> +  if (decl == NULL_TREE)
> +    {
> +      decl 
> +	= build_decl (VAR_DECL, decl_name, 
> +		      (build_type_variant 
> +		       (build_pointer_type 
> +			(build_type_variant (class_type_node, 
> +					     /* const */ 1, 0)),
> +			/* const */ 1, 0)));
> +      TREE_STATIC (decl) = 1;
> +      TREE_INVARIANT (decl) = 1;
> +      TREE_CONSTANT (decl) = 1;
> +      TREE_READONLY (decl) = 1;
> +      TREE_PUBLIC (decl) = 1;
> +      DECL_IGNORED_P (decl) = 1;
> +      DECL_ARTIFICIAL (decl) = 1;
> +      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
> +      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
> +      DECL_CLASS_FIELD_P (decl) = 1;
> +      DECL_CONTEXT (decl) = type;
> +    }
> +
> +  return decl;
> +}
> +
>  /* Build a reference to the class TYPE.
>     Also handles primitive types and array types. */
>  
> @@ -962,7 +1027,7 @@
>    int is_compiled = is_compiled_class (type);
>    if (is_compiled)
>      {
> -      tree ref, decl_name, decl;
> +      tree ref, decl;
>        if (TREE_CODE (type) == POINTER_TYPE)
>  	type = TREE_TYPE (type);
>  
> @@ -971,34 +1036,15 @@
>  	  && TREE_CODE (type) == RECORD_TYPE)
>  	return build_indirect_class_ref (type);
>  
> +      if (type == output_class && flag_indirect_classes)
> +	return build_classdollar_field (type);
> +      
>        if (TREE_CODE (type) == RECORD_TYPE)
> -	{
> -	  if (TYPE_SIZE (type) == error_mark_node)
> -	    return null_pointer_node;
> -	  decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)),
> -					"", '/', '/', ".class");
> -	  decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
> -	  if (decl == NULL_TREE)
> -	    {
> -	      decl = build_decl (VAR_DECL, decl_name, class_type_node);
> -	      TREE_STATIC (decl) = 1;
> -	      TREE_PUBLIC (decl) = 1;
> -	      DECL_IGNORED_P (decl) = 1;
> -	      DECL_ARTIFICIAL (decl) = 1;
> -	      if (is_compiled == 1)
> -		DECL_EXTERNAL (decl) = 1;
> -	      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
> -	      DECL_CLASS_FIELD_P (decl) = 1;
> -	      DECL_CONTEXT (decl) = type;
> -
> -	      /* ??? We want to preserve the DECL_CONTEXT we set just above,
> -		 that that means not calling pushdecl_top_level.  */
> -	      IDENTIFIER_GLOBAL_VALUE (decl_name) = decl;
> -	    }
> -	}
> +	return build_static_class_ref (type);
>        else
>  	{
>  	  const char *name;
> +	  tree decl_name;
>  	  char buffer[25];
>  	  if (flag_emit_class_files)
>  	    {
> @@ -1296,16 +1342,22 @@
>    PUSH_FIELD_VALUE (finit, "accflags", build_int_cst (NULL_TREE, flags));
>    PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
>  
> -  PUSH_FIELD_VALUE
> -    (finit, "info",
> -     build_constructor_from_list (field_info_union_node,
> -	    build_tree_list
> -	    ((FIELD_STATIC (fdecl)
> -	      ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
> -	      : TYPE_FIELDS (field_info_union_node)),
> -	     (FIELD_STATIC (fdecl)
> -	      ? build_address_of (fdecl)
> -	      : byte_position (fdecl)))));
> +  {
> +    tree field_address = integer_zero_node;
> +    if (! flag_indirect_classes && FIELD_STATIC (fdecl))
> +      field_address = build_address_of (fdecl);
> +
> +    PUSH_FIELD_VALUE
> +      (finit, "info",
> +       build_constructor_from_list (field_info_union_node,
> +	 build_tree_list
> +	   ((FIELD_STATIC (fdecl)
> +	     ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
> +	     : TYPE_FIELDS (field_info_union_node)),
> +	    (FIELD_STATIC (fdecl)
> +	     ? field_address
> +	     : byte_position (fdecl)))));
> +  }
>  
>    FINISH_RECORD_CONSTRUCTOR (finit);
>    return finit;
> @@ -1599,7 +1651,7 @@
>    tree dtable_start_offset = build_int_cst (NULL_TREE,
>  					    2 * POINTER_SIZE / BITS_PER_UNIT);
>  
> -  this_class_addr = build_class_ref (type);
> +  this_class_addr = build_static_class_ref (type);
>    decl = TREE_OPERAND (this_class_addr, 0);
>  
>    if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
> @@ -1613,7 +1665,8 @@
>        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 (! flag_indirect_classes)
> +	rest_of_decl_compilation (dtable_decl, 1, 0);
>        if (type == class_type_node)
>  	class_dtable_decl = dtable_decl;
>      }
> @@ -1958,8 +2011,21 @@
>    if (flag_hash_synchronization && POINTER_SIZE < 64)
>      DECL_ALIGN (decl) = 64; 
>    
> +  if (flag_indirect_classes)
> +    {
> +      TREE_READONLY (decl) = 1;
> +      TREE_CONSTANT (DECL_INITIAL (decl)) = 1;
> +    }
> +
>    rest_of_decl_compilation (decl, 1, 0);
>    
> +  {
> +    tree classdollar_field = build_classdollar_field (type);
> +    if (!flag_indirect_classes)
> +      DECL_INITIAL (classdollar_field) = build_static_class_ref (type);
> +    rest_of_decl_compilation (classdollar_field, 1, 0);
> +  }
> +
>    TYPE_OTABLE_DECL (type) = NULL_TREE;
>    TYPE_ATABLE_DECL (type) = NULL_TREE;
>    TYPE_CTABLE_DECL (type) = NULL_TREE;
> @@ -2465,10 +2531,65 @@
>    if (!registered_class)
>      registered_class = VEC_alloc (tree, gc, 8);
>  
> -  node = TREE_OPERAND (build_class_ref (current_class), 0);
> +  if (flag_indirect_classes)
> +    node = current_class;
> +  else
> +    node = TREE_OPERAND (build_class_ref (current_class), 0);
>    VEC_safe_push (tree, gc, registered_class, node);
>  }
>  
> +/* Emit a function that calls _Jv_NewClassFromInitializer for every
> +   class.  */
> +
> +static void
> +emit_indirect_register_classes (tree *list_p)
> +{
> +  tree klass, t, register_class_fn;
> +  int i;
> +
> +  tree init = NULL_TREE;
> +  int size = VEC_length (tree, registered_class) * 2 + 1;
> +  tree class_array_type
> +    = build_prim_array_type (ptr_type_node, size);
> +  tree cdecl = build_decl (VAR_DECL, get_identifier ("_Jv_CLS"),
> +			   class_array_type);
> +  tree reg_class_list;
> +  for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
> +    {
> +      init = tree_cons (NULL_TREE, 
> +			fold_convert (ptr_type_node, 
> +				      build_static_class_ref (klass)), init);
> +      init = tree_cons 
> +	(NULL_TREE, 
> +	 fold_convert (ptr_type_node, 
> +		       build_address_of (build_classdollar_field (klass))),
> +	 init);
> +    }
> +  init = tree_cons (NULL_TREE, integer_zero_node, init); 
> +  DECL_INITIAL (cdecl) = build_constructor_from_list (class_array_type,
> +						      nreverse (init));
> +  TREE_CONSTANT (DECL_INITIAL (cdecl)) = 1;
> +  TREE_STATIC (cdecl) = 1;
> +  DECL_ARTIFICIAL (cdecl) = 1;
> +  DECL_IGNORED_P (cdecl) = 1;
> +  TREE_READONLY (cdecl) = 1;
> +  TREE_CONSTANT (cdecl) = 1;
> +  rest_of_decl_compilation (cdecl, 1, 0);
> +  reg_class_list = fold_convert (ptr_type_node, build_address_of (cdecl));
> +
> +  t = build_function_type_list (void_type_node, 
> +				build_pointer_type (ptr_type_node), NULL);
> +  t = build_decl (FUNCTION_DECL, 
> +		  get_identifier ("_Jv_RegisterNewClasses"), t);
> +  TREE_PUBLIC (t) = 1;
> +  DECL_EXTERNAL (t) = 1;
> +  register_class_fn = t;
> +  t = tree_cons (NULL, reg_class_list, NULL);
> +  t = build_function_call_expr (register_class_fn, t);
> +  append_to_statement_list (t, list_p);
> +}
> +
> +
>  /* Emit something to register classes at start-up time.
>  
>     The preferred mechanism is through the .jcr section, which contain
> @@ -2485,6 +2606,12 @@
>    if (registered_class == NULL)
>      return;
>  
> +  if (flag_indirect_classes)
> +    {
> +      emit_indirect_register_classes (list_p);
> +      return;
> +    }
> +
>    /* TARGET_USE_JCR_SECTION defaults to 1 if SUPPORTS_WEAK and
>       TARGET_ASM_NAMED_SECTION, else 0.  Some targets meet those conditions
>       but lack suitable crtbegin/end objects or linker support.  These
> Index: gcc/java/decl.c
> ===================================================================
> --- gcc/java/decl.c	(revision 113114)
> +++ gcc/java/decl.c	(working copy)
> @@ -123,6 +123,12 @@
>  /* The decl for "_Jv_ResolvePoolEntry".  */
>  tree soft_resolvepoolentry_node;
>  
> +/* The decl for the .constants field of an instance of Class.  */
> +tree constants_field_decl_node;
> +
> +/* The decl for the .data field of an instance of Class.  */
> +tree constants_data_field_decl_node;
> +
>  #if defined(DEBUG_JAVA_BINDING_LEVELS)
>  int binding_depth = 0;
>  int is_class_level = 0;
> @@ -883,6 +889,7 @@
>    PUSH_FIELD (constants_type_node, field, "size", unsigned_int_type_node);
>    PUSH_FIELD (constants_type_node, field, "tags", ptr_type_node);
>    PUSH_FIELD (constants_type_node, field, "data", ptr_type_node);
> +  constants_data_field_decl_node = field;
>    FINISH_RECORD (constants_type_node);
>    build_decl (TYPE_DECL, get_identifier ("constants"), constants_type_node);
>  
> @@ -924,6 +931,7 @@
>    PUSH_FIELD (class_type_node, field, "accflags", access_flags_type_node);
>    PUSH_FIELD (class_type_node, field, "superclass", class_ptr_type);
>    PUSH_FIELD (class_type_node, field, "constants", constants_type_node);
> +  constants_field_decl_node = field;
>    PUSH_FIELD (class_type_node, field, "methods", method_ptr_type_node);
>    PUSH_FIELD (class_type_node, field, "method_count", short_type_node);
>    PUSH_FIELD (class_type_node, field, "vtable_method_count", short_type_node);
> Index: gcc/java/constants.c
> ===================================================================
> --- gcc/java/constants.c	(revision 113114)
> +++ gcc/java/constants.c	(working copy)
> @@ -458,8 +458,29 @@
>  {
>    tree d = build_constant_data_ref ();
>    tree i = build_int_cst (NULL_TREE, index);
> -  return build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
> +  if (flag_indirect_classes)
> +    {
> +      tree decl = build_class_ref (output_class);
> +      tree klass = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (decl)),
> +			   decl);
> +      tree constants = build3 (COMPONENT_REF, 
> +			       TREE_TYPE (constants_field_decl_node), klass,
> +			       constants_field_decl_node,
> +			       NULL_TREE);
> +      tree data = build3 (COMPONENT_REF, 
> +			  TREE_TYPE (constants_data_field_decl_node), 
> +			  constants,
> +			  constants_data_field_decl_node,
> +			  NULL_TREE);
> +      data = fold_convert (build_pointer_type (TREE_TYPE (d)), data);
> +      d = build1 (INDIRECT_REF, TREE_TYPE (d), data);
> +      /* FIXME: These should be cached.  */
> +      TREE_INVARIANT (d) = 1;
> +    }
> +  d = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
>  		 NULL_TREE, NULL_TREE);
> +  TREE_INVARIANT (d) = 1;
> +  return d;
>  }
>  
>  /* Build an initializer for the constants field of the current constant pool.
> Index: gcc/java/lang.opt
> ===================================================================
> --- gcc/java/lang.opt	(revision 113114)
> +++ gcc/java/lang.opt	(working copy)
> @@ -146,6 +146,10 @@
>  Java Var(flag_hash_synchronization)
>  Assume the runtime uses a hash table to map an object to its synchronization structure
>  
> +findirect-classes
> +Java Var(flag_indirect_classes) Init(1)
> +Generate instances of Class at runtime
> +
>  findirect-dispatch
>  Java Var(flag_indirect_dispatch)
>  Use offset tables for virtual method calls
> Index: gcc/java/mangle.c
> ===================================================================
> --- gcc/java/mangle.c	(revision 113114)
> +++ gcc/java/mangle.c	(working copy)
> @@ -79,6 +79,9 @@
>  void
>  java_mangle_decl (tree decl)
>  {
> +  if (TREE_CODE (decl) == RECORD_TYPE)
> +    mangle_type (decl);
> +
>    /* A copy of the check from the beginning of lhd_set_decl_assembler_name.
>       Only FUNCTION_DECLs and VAR_DECLs for variables with static storage
>       duration need a real DECL_ASSEMBLER_NAME.  */
> @@ -99,7 +102,7 @@
>  	    {
>  	      if (DECL_CLASS_FIELD_P (decl))
>  		{
> -		  mangle_class_field (DECL_CONTEXT (decl));
> +		  mangle_class_field (decl);
>  		  break;
>  		}
>  	      else if (DECL_VTABLE_P (decl))
> @@ -130,10 +133,14 @@
>  /* Beginning of the helper functions */
>  
>  static void
> -mangle_class_field (tree type)
> +mangle_class_field (tree decl)
>  {
> +  tree type = DECL_CONTEXT (decl);
>    mangle_record_type (type, /* for_pointer = */ 0);
> -  MANGLE_RAW_STRING ("6class$");
> +  if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
> +    MANGLE_RAW_STRING ("6class$");
> +  else
> +    MANGLE_RAW_STRING ("7class$$");
>    obstack_1grow (mangle_obstack, 'E');
>  }
>  
> @@ -229,7 +236,7 @@
>    append_gpp_mangled_name (IDENTIFIER_POINTER (name),
>  			   IDENTIFIER_LENGTH (name));
>  
> -  /* If NAME happens to be a C++ keyword, add `$'. */
> +  /* If NAME happens to be a C++ keyword, add `$'.  */
>    if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
>      obstack_1grow (mangle_obstack, '$');
>  }
> Index: gcc/java/jvgenmain.c
> ===================================================================
> --- gcc/java/jvgenmain.c	(revision 113114)
> +++ gcc/java/jvgenmain.c	(working copy)
> @@ -127,11 +127,11 @@
>      }
>    fprintf (stream, "  0\n};\n\n");
>  
> -  fprintf (stream, "extern int %s;\n", mangled_classname);
>    fprintf (stream, "int main (int argc, const char **argv)\n");
>    fprintf (stream, "{\n");
>    fprintf (stream, "   _Jv_Compiler_Properties = props;\n");
> -  fprintf (stream, "   JvRunMain (&%s, argc, argv);\n", mangled_classname);
> +  fprintf (stream, "   extern void *%s;\n", mangled_classname);
> +  fprintf (stream, "   JvRunMain (%s, argc, argv);\n", mangled_classname);
>    fprintf (stream, "}\n");
>    if (stream != stdout && fclose (stream) != 0)
>      {
> @@ -153,16 +153,16 @@
>  
>    for (ptr = string; *ptr; ptr++ )
>      {
> -      if (ptr[0] == '.')
> +      if (*ptr == '.')
>  	{
> -	  append_gpp_mangled_name (&ptr [-count], count);
> +	  append_gpp_mangled_name (ptr - count, count);
>  	  count = 0;
>  	}
>        else
>  	count++;
>      }
>    append_gpp_mangled_name (&ptr [-count], count);
> -  obstack_grow (mangle_obstack, "6class$E", 8);
> +  obstack_grow (mangle_obstack, "7class$$E", strlen ("7class$$E"));
>    obstack_1grow (mangle_obstack, '\0');
>    return obstack_finish (mangle_obstack);
>  }
> Index: gcc/java/lang.c
> ===================================================================
> --- gcc/java/lang.c	(revision 113114)
> +++ gcc/java/lang.c	(working copy)
> @@ -368,6 +368,9 @@
>    if (flag_indirect_dispatch)
>      always_initialize_class_p = true;
>  
> +  if (!flag_indirect_dispatch)
> +    flag_indirect_classes = false;
> +
>    /* Force minimum function alignment if g++ uses the least significant
>       bit of function pointers to store the virtual bit. This is required
>       to keep vtables compatible.  */
> Index: gcc/java/java-tree.h
> ===================================================================
> --- gcc/java/java-tree.h	(revision 113114)
> +++ gcc/java/java-tree.h	(working copy)
> @@ -208,6 +208,9 @@
>     initialization optimization should be performed.  */
>  extern int flag_optimize_sci;
>  
> +/* Generate instances of Class at runtime.  */
> +extern int flag_indirect_classes;
> +
>  /* When nonzero, use offset tables for virtual method calls
>     in order to improve binary compatibility. */
>  extern int flag_indirect_dispatch;
> @@ -270,6 +273,12 @@
>  extern GTY(()) tree java_io_serializable_identifier_node;
>  extern GTY(()) tree gcj_abi_version;
>  
> +/* The decl for the .constants field of an instance of Class.  */
> +extern GTY(()) tree constants_field_decl_node;
> +
> +/* The decl for the .data field of an instance of Class.  */
> +extern GTY(()) tree constants_data_field_decl_node;
> +
>  enum java_tree_index
>  {
>    JTI_PROMOTED_BYTE_TYPE_NODE,
>
>
> 2006-04-21  Andrew Haley  <aph@redhat.com>
>
> 	* include/execution.h (struct _Jv_CompiledEngine): Define for
> 	compiled classes.
> 	* java/lang/natClassLoader.cc (_Jv_RegisterClasses): Call
> 	_Jv_RegisterLibForGc.
> 	(_Jv_RegisterClasses_Counted): Likewise.
> 	(_Jv_NewClassFromInitializer): New.
> 	(_Jv_RegisterNewClasses): New.
> 	* sources.am: Regenerate.
> 	* boehm.cc (_Jv_GC_has_static_roots): new.
> 	(_Jv_InitGC): Call GC_register_has_static_roots_callback.
> 	(filename_node, find_file, _Jv_print_gc_store, new_node,
> 	_Jv_GC_has_static_roots, _Jv_RegisterLibForGc): New.
> 	* scripts/makemake.tcl: Add -fno-indirect-classes.
> 	* Makefile.in: Regenerate.
> 	* link.cc (resolve_pool_entry): Allocate constant pool.
> 	Allocate fields.
> 	
> Index: libjava/link.cc
> ===================================================================
> --- libjava/link.cc	(revision 113114)
> +++ libjava/link.cc	(working copy)
> @@ -21,6 +21,12 @@
>  
>  #include <java-interp.h>
>  
> +// Set GC_DEBUG before including gc.h!
> +#ifdef LIBGCJ_GC_DEBUG
> +# define GC_DEBUG
> +#endif
> +#include <gc.h>
> +
>  #include <jvm.h>
>  #include <gcj/cni.h>
>  #include <string.h>
> @@ -265,6 +271,21 @@
>  {
>    using namespace java::lang::reflect;
>  
> +  if (GC_base (klass) && klass->constants.data
> +      && ! GC_base (klass->constants.data))
> +    {
> +      jsize count = klass->constants.size;
> +      if (count)
> +	{
> +	  _Jv_word* constants
> +	    = (_Jv_word*) _Jv_AllocRawObj (count * sizeof (_Jv_word));
> +	  memcpy ((void*)constants,
> +		  (void*)klass->constants.data,
> +		  count * sizeof (_Jv_word));
> +	  klass->constants.data = constants;
> +	}
> +    }
> +
>    _Jv_Constants *pool = &klass->constants;
>  
>    if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
> @@ -1893,6 +1914,21 @@
>    java::lang::Thread *save = klass->thread;
>    klass->thread = self;
>  
> +  // Allocate memory for static fields and constants.
> +  if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
> +    {
> +      jsize count = klass->field_count;
> +      if (count)
> +	{
> +	  _Jv_Field* fields 
> +	    = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
> +	  memcpy ((void*)fields,
> +		  (void*)klass->fields,
> +		  count * sizeof (_Jv_Field));
> +	  klass->fields = fields;
> +	}
> +    }
> +      
>    // Print some debugging info if requested.  Interpreted classes are
>    // handled in defineclass, so we only need to handle the two
>    // pre-compiled cases here.
> Index: libjava/scripts/makemake.tcl
> ===================================================================
> --- libjava/scripts/makemake.tcl	(revision 113114)
> +++ libjava/scripts/makemake.tcl	(working copy)
> @@ -224,7 +224,7 @@
>      set omit "| grep -v $exclusion_map($package)"
>    }
>    puts  "\t@find classpath/lib/$package -name '*.class'${omit} > $tname"
> -  puts "\t\$(LTGCJCOMPILE) -fjni -findirect-dispatch -c -o $loname @$tname"
> +  puts "\t\$(LTGCJCOMPILE) -fjni -findirect-dispatch -fno-indirect-classes -c -o $loname @$tname"
>    puts "\t@rm -f $tname"
>    puts ""
>  
> Index: libjava/gnu/gcj/runtime/natSharedLibLoader.cc
> ===================================================================
> --- libjava/gnu/gcj/runtime/natSharedLibLoader.cc	(revision 113114)
> +++ libjava/gnu/gcj/runtime/natSharedLibLoader.cc	(working copy)
> @@ -21,6 +21,7 @@
>  
>  #ifdef HAVE_DLOPEN
>  #include <dlfcn.h>
> +#include <link.h>
>  
>  /* Only used during dlopen, while having a lock on Class.class. */
>  static java::lang::ClassLoader *curLoader;
> Index: libjava/boehm.cc
> ===================================================================
> --- libjava/boehm.cc	(revision 113114)
> +++ libjava/boehm.cc	(working copy)
> @@ -32,6 +32,13 @@
>  #undef PACKAGE_TARNAME
>  #undef PACKAGE_VERSION
>  
> +#ifdef HAVE_DLFCN_H
> +#undef _GNU_SOURCE
> +#define _GNU_SOURCE
> +#include <dlfcn.h>
> +#include <link.h>
> +#endif
> +
>  extern "C"
>  {
>  #include <gc_config.h>
> @@ -64,6 +71,8 @@
>  // Freelist used for Java arrays.
>  static void **array_free_list;
>  
> +static int _Jv_GC_has_static_roots (const char *filename, void *, size_t);
> +
>  \f
>  
>  // This is called by the GC during the mark phase.  It marks a Java
> @@ -468,10 +477,21 @@
>  _Jv_InitGC (void)
>  {
>    int proc;
> +  static bool gc_initialized;
> +
> +  if (gc_initialized)
> +    return;
> +
> +  gc_initialized = 1;
>  
>    // Ignore pointers that do not point to the start of an object.
>    GC_all_interior_pointers = 0;
>  
> +#ifdef HAVE_DLFCN_H
> +  // Tell the collector to ask us before scanning DSOs.
> +  GC_register_has_static_roots_callback (_Jv_GC_has_static_roots);
> +#endif
> +
>    // Configure the collector to use the bitmap marking descriptors that we
>    // stash in the class vtable.
>    // We always use mark proc descriptor 0, since the compiler knows
> @@ -559,3 +579,98 @@
>    // For now, always reclaim soft references.  FIXME.
>    return true;
>  }
> +
> +\f
> +
> +#ifdef HAVE_DLFCN_H
> +
> +// We keep a store of the filenames of DSOs that need to be
> +// conservatively scanned by the garbage collector.  During collection
> +// the gc calls _Jv_GC_has_static_roots() to see if the data segment
> +// of a DSO should be scanned.
> +typedef struct filename_node
> +{
> +  char *name;
> +  struct filename_node *link;
> +} filename_node;
> +
> +#define FILENAME_STORE_SIZE 17
> +static filename_node *filename_store[FILENAME_STORE_SIZE];
> +
> +// Find a filename in filename_store.
> +static filename_node **
> +find_file (const char *filename)
> +{
> +  int index = strlen (filename) % FILENAME_STORE_SIZE;
> +  filename_node **node = &filename_store[index];
> +  
> +  while (*node)
> +    {
> +      if (strcmp ((*node)->name, filename) == 0)
> +	return node;
> +      node = &(*node)->link;
> +    }
> +
> +  return node;
> +}  
> +
> +// Print the store of filenames of DSOs that need collection.
> +void
> +_Jv_print_gc_store (void)
> +{
> +  for (int i = 0; i < FILENAME_STORE_SIZE; i++)
> +    {
> +      filename_node *node = filename_store[i];
> +      while (node)
> +	{
> +	  fprintf (stderr, "%s\n", node->name);
> +	  node = node->link;
> +	}
> +    }
> +}
> +
> +// Create a new node in the store of libraries to collect.
> +static filename_node *
> +new_node (const char *filename)
> +{
> +  filename_node *node = (filename_node*)_Jv_Malloc (sizeof (filename_node));
> +  node->name = (char *)_Jv_Malloc (strlen (filename) + 1);
> +  node->link = NULL;
> +  strcpy (node->name, filename);
> +  
> +  return node;
> +}
> +
> +// Nonzero if the gc should scan this lib.
> +static int 
> +_Jv_GC_has_static_roots (const char *filename, void *, size_t)
> +{
> +  if (filename == NULL || strlen (filename) == 0)
> +    // No filename; better safe than sorry.
> +    return 1;
> +
> +  filename_node **node = find_file (filename);
> +  if (*node)
> +    return 1;
> +
> +  return 0;
> +}
> +
> +#endif
> +
> +// Register the DSO that contains p for collection.
> +void
> +_Jv_RegisterLibForGc (const void *p __attribute__ ((__unused__)))
> +{
> +#ifdef HAVE_DLFCN_H
> +  Dl_info info;
> +  
> +  if (dladdr (p, &info) != 0)
> +    {
> +      filename_node **node = find_file (info.dli_fname);
> +      if (! *node)
> +	*node = new_node (info.dli_fname);
> +    }
> +#endif
> +}
> +
> Index: libjava/java/lang/natClassLoader.cc
> ===================================================================
> --- libjava/java/lang/natClassLoader.cc	(revision 113114)
> +++ libjava/java/lang/natClassLoader.cc	(working copy)
> @@ -45,14 +45,17 @@
>  #include <gnu/gcj/runtime/BootClassLoader.h>
>  #include <gnu/gcj/runtime/SystemClassLoader.h>
>  
> +#undef _GNU_SOURCE
> +#define _GNU_SOURCE
> +#include <dlfcn.h>
> +#include <link.h>
> +
>  // Size of local hash table.
>  #define HASH_LEN 1013
>  
>  // Hash function for Utf8Consts.
>  #define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN)
>  
> -static jclass loaded_classes[HASH_LEN];
> -
>  // This records classes which will be registered with the system class
>  // loader when it is initialized.
>  static jclass system_class_list;
> @@ -62,6 +65,8 @@
>  // no longer pay attention to the system abi flag.
>  #define SYSTEM_LOADER_INITIALIZED ((jclass) -1)
>  
> +static jclass loaded_classes[HASH_LEN];
> +
>  // This is the root of a linked list of classes
>  static jclass stack_head;
>  
> @@ -164,6 +169,8 @@
>  void
>  _Jv_RegisterClasses (const jclass *classes)
>  {
> +  _Jv_RegisterLibForGc (classes);
> +
>    for (; *classes; ++classes)
>      {
>        jclass klass = *classes;
> @@ -178,6 +185,9 @@
>  _Jv_RegisterClasses_Counted (const jclass * classes, size_t count)
>  {
>    size_t i;
> +
> +  _Jv_RegisterLibForGc (classes);
> +
>    for (i = 0; i < count; i++)
>      {
>        jclass klass = classes[i];
> @@ -187,6 +197,41 @@
>      }
>  }
>  
> +// Create a class on the heap from an initializer struct.
> +jclass
> +_Jv_NewClassFromInitializer (const jclass class_initializer)
> +{
> +  jclass new_class = (jclass)_Jv_AllocObj (sizeof *new_class,
> +					   &java::lang::Class::class$);  
> +  memcpy ((void*)new_class, (void*)class_initializer, sizeof *new_class);
> +
> +  if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version))
> +    (*_Jv_RegisterClassHook) (new_class);
> +  
> +  return new_class;
> +}
> +
> +// Called by compiler-generated code at DSO initialization.  CLASSES
> +// is an array of pairs: the first item of each pair is a pointer to
> +// the initialized data that is a class initializer in a DSO, and the
> +// second is a pointer to a class reference.
> +// _Jv_NewClassFromInitializer() creates the new class (on the Java
> +// heap) and we write the address of the new class into the address
> +// pointed to by the second word.
> +void
> +_Jv_RegisterNewClasses (void **classes)
> +{
> +  _Jv_InitGC ();
> +
> +  jclass initializer;
> +
> +  while ((initializer = (jclass)*classes++))
> +    {
> +      jclass *class_ptr = (jclass *)*classes++;
> +      *class_ptr = _Jv_NewClassFromInitializer (initializer);
> +    }      
> +}
> +  
>  void
>  _Jv_RegisterClassHookDefault (jclass klass)
>  {
> @@ -389,6 +434,12 @@
>  static jshort array_depth = 0;
>  static jclass *array_ancestors = NULL;
>  
> +static jclass interfaces[] =
> +{
> +  &java::lang::Cloneable::class$,
> +  &java::io::Serializable::class$
> +};
> +
>  // Create a class representing an array of ELEMENT and store a pointer to it
>  // in element->arrayclass. LOADER is the ClassLoader which _initiated_ the 
>  // instantiation of this array. ARRAY_VTABLE is the vtable to use for the new 
> @@ -464,11 +515,6 @@
>    array_class->element_type = element;
>  
>    // Register our interfaces.
> -  static jclass interfaces[] =
> -    {
> -      &java::lang::Cloneable::class$,
> -      &java::io::Serializable::class$
> -    };
>    array_class->interfaces = interfaces;
>    array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
>  
> Index: libjava/java/lang/Class.h
> ===================================================================
> --- libjava/java/lang/Class.h	(revision 113114)
> +++ libjava/java/lang/Class.h	(working copy)
> @@ -39,6 +39,9 @@
>  
>  // We declare these here to avoid including gcj/cni.h.
>  extern "C" void _Jv_InitClass (jclass klass);
> +extern "C" jclass _Jv_NewClassFromInitializer 
> +   (const jclass class_initializer);
> +extern "C" void _Jv_RegisterNewClasses (void **classes);
>  extern "C" void _Jv_RegisterClasses (const jclass *classes);
>  extern "C" void _Jv_RegisterClasses_Counted (const jclass *classes,
>  					     size_t count);
> @@ -286,7 +289,7 @@
>    JArray<jclass> *getClasses (void);
>  
>    java::lang::ClassLoader *getClassLoader (void);
> -
> +public:
>    // This is an internal method that circumvents the usual security
>    // checks when getting the class loader.
>    java::lang::ClassLoader *getClassLoaderInternal (void)
> @@ -427,6 +430,8 @@
>  					       int method_idx);
>  
>    friend void ::_Jv_InitClass (jclass klass);
> +  friend java::lang::Class* ::_Jv_NewClassFromInitializer (const jclass class_initializer);
> +  friend void _Jv_RegisterNewClasses (void **classes);
>  
>    friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, 
>  						 _Jv_Utf8Const*, jclass *);
> Index: libjava/include/execution.h
> ===================================================================
> --- libjava/include/execution.h	(revision 113114)
> +++ libjava/include/execution.h	(working copy)
> @@ -55,9 +55,25 @@
>      return NULL;
>    }
>  
> -  static void do_allocate_static_fields (jclass, int, int)
> -  {
> -    // Compiled classes don't need this.
> +  static void do_allocate_static_fields (jclass klass,
> +					 int pointer_size,
> +					 int other_size)
> +  {
> +    // Splitting the allocations here lets us scan reference fields
> +    // and avoid scanning non-reference fields.
> +    char *reference_fields = (char *) _Jv_AllocRawObj (pointer_size);
> +    char *non_reference_fields = (char *) _Jv_AllocBytes (other_size);
> +
> +    for (int i = 0; i < klass->field_count; i++)
> +      {
> +	_Jv_Field *field = &klass->fields[i];
> +
> +	if ((field->flags & java::lang::reflect::Modifier::STATIC) == 0)
> +	  continue;
> +
> +	char *base = field->isRef() ? reference_fields : non_reference_fields;
> +	field->u.addr  = base + field->u.boffset;
> +      } 
>    }
>  
>    static void do_create_ncode (jclass)
> Index: libjava/include/boehm-gc.h
> ===================================================================
> --- libjava/include/boehm-gc.h	(revision 113114)
> +++ libjava/include/boehm-gc.h	(working copy)
> @@ -19,6 +19,7 @@
>  {
>    void *_Jv_MarkObj (void *, void *, void *, void *);
>    void *_Jv_MarkArray (void *, void *, void *, void *);
> +  void _Jv_RegisterLibForGc (const void *);
>  }
>  
>  // Enough stuff to inline _Jv_AllocObj.  Ugly.
>   

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26 17:05 ` Bryce McKinlay
@ 2006-04-26 17:16   ` Andrew Haley
  2006-05-10 17:37   ` Andrew Haley
  1 sibling, 0 replies; 7+ messages in thread
From: Andrew Haley @ 2006-04-26 17:16 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: gcc-patches, java-patches

Bryce McKinlay writes:

 > For a long time we've talked about putting the class data in a 
 > pointer-free format, instead of storing them as static jclasses. It 
 > looks like this patch has taken care of much of the hard work and will 
 > make changing the class data format easier.

Indeed it will, yes.

 > One suggestion - I think it would be good to make the comments a bit 
 > more clear on which libgcj functions are called by the compiler to 
 > register classes for the -findirect-classes case, and which are for the 
 > non-indirect case. Its obvious from reading the patch why there is both 
 > a _Jv_RegisterClasses and  _Jv_RegisterNewClasses, but it may not be for 
 > someone browsing the code later.

That seems reasonable.

 > Also, the comment on emit_indirect_register_classes() doesn't look right 
 > - it doesn't call _Jv_NewClassFromInitailizer directly.

Oops.  TVM for looking at this.

Andrew.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Allocate Class instancs on heap; not conservatively scan DSOs
  2006-04-26 17:05 ` Bryce McKinlay
  2006-04-26 17:16   ` Andrew Haley
@ 2006-05-10 17:37   ` Andrew Haley
  1 sibling, 0 replies; 7+ messages in thread
From: Andrew Haley @ 2006-05-10 17:37 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: gcc-patches, java-patches

Bryce McKinlay writes:

 > One suggestion - I think it would be good to make the comments a bit 
 > more clear on which libgcj functions are called by the compiler to 
 > register classes for the -findirect-classes case, and which are for the 
 > non-indirect case. Its obvious from reading the patch why there is both 
 > a _Jv_RegisterClasses and  _Jv_RegisterNewClasses, but it may not be for 
 > someone browsing the code later.
 > 
 > Also, the comment on emit_indirect_register_classes() doesn't look right 
 > - it doesn't call _Jv_NewClassFromInitailizer directly.

Thanks.

Andrew.

2006-05-10  Andrew Haley  <aph@redhat.com>

	* java/lang/natClassLoader.cc: Add comments.

Index: libjava/java/lang/natClassLoader.cc
===================================================================
--- libjava/java/lang/natClassLoader.cc (revision 113674)
+++ libjava/java/lang/natClassLoader.cc (working copy)
@@ -156,6 +156,30 @@
   loader->loadedClasses->remove(klass->name->toString());
 }
 
+
+// Class registration.
+//
+// There are two kinds of functions that register classes.  
+//
+// Type 1:
+//
+// These take the address of a class that is in an object file.
+// Because these classes are not allocated on the heap, It is also
+// necessary to register the address of the object for garbage
+// collection.  This is used with the "old" C++ ABI and with
+// -findirect-dispatch -fno-indirect-classes.
+//
+// Type 2:
+//
+// These take an initializer struct, create the class, and return the
+// address of the newly created class to their caller.  These are used
+// with -findirect-dispatch.
+//
+// _Jv_RegisterClasses() and _Jv_RegisterClasses_Counted() are
+// functions of Type 1, and _Jv_NewClassFromInitializer() and
+// _Jv_RegisterNewClasses() are of Type 2.
+
+
 // This function is called many times during startup, before main() is
 // run.  At that point in time we know for certain we are running 
 // single-threaded, so we don't need to lock when adding classes to the 

2006-05-10  Andrew Haley  <aph@redhat.com>

	* class.c (emit_indirect_register_classes): Fix comment.

Index: gcc/java/class.c
===================================================================
--- gcc/java/class.c    (revision 113532)
+++ gcc/java/class.c    (working copy)
@@ -2539,8 +2539,8 @@
   VEC_safe_push (tree, gc, registered_class, node);
 }
 
-/* Emit a function that calls _Jv_NewClassFromInitializer for every
-   class.  */
+/* Emit a function that calls _Jv_RegisterNewClasses with a list of
+   all the classes we have emitted.  */
 
 static void
 emit_indirect_register_classes (tree *list_p)

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-05-10 17:37 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-04-26  8:43 Allocate Class instancs on heap; not conservatively scan DSOs Andrew Haley
2006-04-26 13:59 ` Daniel Jacobowitz
2006-04-26 14:11   ` Andrew Haley
2006-04-26 16:32     ` Daniel Jacobowitz
2006-04-26 17:05 ` Bryce McKinlay
2006-04-26 17:16   ` Andrew Haley
2006-05-10 17:37   ` Andrew Haley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).