Allocate Class instancs on heap; not conservatively scan DSOs

Andrew Haley aph@redhat.com
Fri Apr 21 18:06:00 GMT 2006


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);
+
 
 
 // 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;
 }
+
+
+
+#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.



More information about the Java mailing list