aboutsummaryrefslogtreecommitdiff
path: root/gcc/java
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/java')
-rw-r--r--gcc/java/ChangeLog20
-rw-r--r--gcc/java/class.c203
-rw-r--r--gcc/java/constants.c23
-rw-r--r--gcc/java/decl.c8
-rw-r--r--gcc/java/java-tree.h9
-rw-r--r--gcc/java/jvgenmain.c10
-rw-r--r--gcc/java/lang.c3
-rw-r--r--gcc/java/lang.opt4
-rw-r--r--gcc/java/mangle.c15
9 files changed, 247 insertions, 48 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index fe19f2c8e51..2ce57c0fdc1 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,23 @@
+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.
+
2006-04-08 Kazu Hirata <kazu@codesourcery.com>
* expr.c, gjavah.c: Fix comment typos.
diff --git a/gcc/java/class.c b/gcc/java/class.c
index a6074518f59..fe52e67d4ac 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -953,6 +953,71 @@ build_indirect_class_ref (tree type)
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 @@ build_class_ref (tree type)
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 @@ build_class_ref (tree type)
&& 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 @@ make_field_value (tree fdecl)
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 @@ make_class_data (tree type)
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 @@ make_class_data (tree type)
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 @@ make_class_data (tree type)
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 @@ register_class (void)
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 @@ emit_register_classes (tree *list_p)
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
diff --git a/gcc/java/constants.c b/gcc/java/constants.c
index 5d2f6785356..2f4c0530035 100644
--- a/gcc/java/constants.c
+++ b/gcc/java/constants.c
@@ -458,8 +458,29 @@ build_ref_from_constant_pool (int index)
{
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.
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index 06da90bff73..a16c49b7c4b 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -123,6 +123,12 @@ static GTY(()) tree pending_local_decls;
/* 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 @@ java_init_decl_processing (void)
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 @@ java_init_decl_processing (void)
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);
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index 18e1ce6006f..03a7ea2c142 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -208,6 +208,9 @@ extern int flag_check_references;
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_lang_cloneable_identifier_node;
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,
diff --git a/gcc/java/jvgenmain.c b/gcc/java/jvgenmain.c
index f3402798e55..e0cddc0d4d5 100644
--- a/gcc/java/jvgenmain.c
+++ b/gcc/java/jvgenmain.c
@@ -127,11 +127,11 @@ main (int argc, char **argv)
}
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 @@ do_mangle_classname (const char *string)
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);
}
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 58f23e9e0e5..6344c3c8707 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -368,6 +368,9 @@ java_init (void)
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. */
diff --git a/gcc/java/lang.opt b/gcc/java/lang.opt
index 6ffb0aadbd1..80b920260f6 100644
--- a/gcc/java/lang.opt
+++ b/gcc/java/lang.opt
@@ -146,6 +146,10 @@ fhash-synchronization
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
diff --git a/gcc/java/mangle.c b/gcc/java/mangle.c
index a99bfe5b56c..0fe5220b5b2 100644
--- a/gcc/java/mangle.c
+++ b/gcc/java/mangle.c
@@ -79,6 +79,9 @@ static GTY(()) tree atms;
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 @@ java_mangle_decl (tree decl)
{
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 @@ java_mangle_decl (tree decl)
/* 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 @@ mangle_member_name (tree name)
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, '$');
}