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


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

Re: Allocate Class instancs on heap; not conservatively scan DSOs


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);
+

// 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.


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