This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
gcj patch: class initialization optimization
- To: gcc-patches at gcc dot gnu dot org
- Subject: gcj patch: class initialization optimization
- From: Anthony Green <green at cygnus dot com>
- Date: Mon, 14 Feb 2000 00:33:24 -0800
- Reply-to: green at redhat dot com
This patch is an implementation of the optimization described in this
note:
http://sourceware.cygnus.com/ml/java-discuss/1999-q3/msg00124.html
2000-02-13 Anthony Green <green@cygnus.com>
* class.c (init_test_hash_newfunc): New function.
(decl_hash): New function.
(decl_compare): New function.
* decl.c (emit_init_test_initialization): New function.
(complete_start_java_method): Traverse the init test hashtable,
calling emit_init_test_initialization.
(always_initialize_class_p): Define.
* expr.c (build_class_init): Use initialization tests when
emitting class initialization code.
(always_initialize_class_p): Declare.
* jcf-parse.c (parse_class_file): Set always_initialize_class_p to
1.
* java-tree.h: Include hash.h.
(DECL_FUNCTION_INIT_TEST_TABLE): Define.
(struct lang_decl): Add init_test_table field.
(init_test_hash_entry): Define.
Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/class.c,v
retrieving revision 1.53
diff -u -r1.53 class.c
--- class.c 2000/01/21 20:57:00 1.53
+++ class.c 2000/02/14 08:16:50
@@ -389,7 +389,7 @@
CLASS_HAS_SUPER (this_class) = 1;
}
pop_obstacks ();
-
+
if (access_flags & ACC_PUBLIC) CLASS_PUBLIC (class_decl) = 1;
if (access_flags & ACC_FINAL) CLASS_FINAL (class_decl) = 1;
if (access_flags & ACC_SUPER) CLASS_SUPER (class_decl) = 1;
@@ -548,6 +548,40 @@
return build_method_type (CLASS_TO_HANDLE_TYPE (this_class), fntype);
}
+static struct hash_entry *
+init_test_hash_newfunc (entry, table, string)
+ struct hash_entry *entry;
+ struct hash_table *table;
+ hash_table_key string ATTRIBUTE_UNUSED;
+{
+ struct init_test_hash_entry *ret = (struct init_test_hash_entry *) entry;
+ if (ret == NULL)
+ {
+ ret = ((struct init_test_hash_entry *)
+ hash_allocate (table, sizeof (struct init_test_hash_entry)));
+ if (ret == NULL)
+ return NULL;
+ }
+ ret->init_test_decl = 0;
+ return (struct hash_entry *) ret;
+}
+
+static unsigned long
+decl_hash (k)
+ hash_table_key k;
+{
+ return (long) k;
+}
+
+static boolean
+decl_compare (k1, k2)
+ hash_table_key k1;
+ hash_table_key k2;
+{
+ return ((char*) k1 == (char*) k2);
+}
+
+
tree
add_method_1 (handle_class, access_flags, name, function_type)
tree handle_class;
@@ -567,6 +601,11 @@
DECL_LANG_SPECIFIC (fndecl)
= (struct lang_decl *) permalloc (sizeof (struct lang_decl));
bzero ((PTR) DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl));
+
+ /* Initialize the static initializer test table. */
+ hash_table_init (&DECL_FUNCTION_INIT_TEST_TABLE (fndecl),
+ init_test_hash_newfunc, decl_hash,
+ decl_compare);
TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
TYPE_METHODS (handle_class) = fndecl;
Index: gcc/java/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/decl.c,v
retrieving revision 1.46
diff -u -r1.46 decl.c
--- decl.c 2000/02/09 20:38:02 1.46
+++ decl.c 2000/02/14 08:16:51
@@ -48,6 +48,10 @@
static tree push_promoted_type PARAMS ((const char *, tree));
static struct binding_level *make_binding_level PARAMS ((void));
+/* Set to non-zero value in order to emit class initilization code
+ before static field references. */
+extern int always_initialize_class_p;
+
#ifndef INT_TYPE_SIZE
#define INT_TYPE_SIZE BITS_PER_WORD
#endif
@@ -1623,6 +1627,24 @@
return (DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, restype));
}
+
+/* Called for every element in DECL_FUNCTION_INIT_TEST_TABLE in order
+ to emit initialization code for each test flag. */
+
+static boolean
+emit_init_test_initialization (entry, key)
+ struct hash_entry *entry;
+ hash_table_key key;
+{
+ struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
+ expand_decl (ite->init_test_decl);
+
+ expand_expr_stmt (build (MODIFY_EXPR, boolean_type_node,
+ ite->init_test_decl, boolean_false_node));
+
+ return true;
+}
+
void
complete_start_java_method (fndecl)
tree fndecl;
@@ -1634,6 +1656,11 @@
/* Set up parameters and prepare for return, for the function. */
expand_function_start (fndecl, 0);
+
+ /* Emit initialization code for test flags. */
+ if (! always_initialize_class_p)
+ hash_traverse (&DECL_FUNCTION_INIT_TEST_TABLE (fndecl),
+ emit_init_test_initialization, 0);
}
/* Allocate further tree nodes temporarily during compilation
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/expr.c,v
retrieving revision 1.58
diff -u -r1.58 expr.c
--- expr.c 2000/02/09 14:08:44 1.58
+++ expr.c 2000/02/14 08:16:52
@@ -83,6 +83,10 @@
static tree operand_type[59];
extern struct obstack permanent_obstack;
+/* Set to non-zero value in order to emit class initilization code
+ before static field references. */
+int always_initialize_class_p;
+
void
init_expr_processing()
{
@@ -1476,14 +1480,46 @@
build_class_init (clas, expr)
tree clas, expr;
{
- tree init;
+ tree init, call;
+ struct init_test_hash_entry *ite;
if (inherits_from_p (current_class, clas))
return expr;
- init = build (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE, build_class_ref (clas)),
- NULL_TREE);
- TREE_SIDE_EFFECTS (init) = 1;
+
+ if (always_initialize_class_p)
+ {
+ init = build (CALL_EXPR, void_type_node,
+ build_address_of (soft_initclass_node),
+ build_tree_list (NULL_TREE, build_class_ref (clas)),
+ NULL_TREE);
+ TREE_SIDE_EFFECTS (init) = 1;
+ }
+ else
+ {
+ ite = (struct init_test_hash_entry *)
+ hash_lookup (&DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl),
+ (const hash_table_key) clas,
+ TRUE, NULL);
+
+ if (ite->init_test_decl == 0)
+ ite->init_test_decl = build_decl (VAR_DECL, NULL_TREE,
+ boolean_type_node);
+
+ init = build (CALL_EXPR, void_type_node,
+ build_address_of (soft_initclass_node),
+ build_tree_list (NULL_TREE, build_class_ref (clas)),
+ NULL_TREE);
+ TREE_SIDE_EFFECTS (init) = 1;
+ call = build (COMPOUND_EXPR, TREE_TYPE (expr), init,
+ build (MODIFY_EXPR, boolean_type_node,
+ ite->init_test_decl, boolean_true_node));
+ TREE_SIDE_EFFECTS (call) = 1;
+ init = build (COND_EXPR, void_type_node,
+ build (EQ_EXPR, boolean_type_node,
+ ite->init_test_decl, boolean_false_node),
+ call, integer_zero_node);
+ TREE_SIDE_EFFECTS (init) = 1;
+ }
+
if (expr != NULL_TREE)
{
expr = build (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/java-tree.h,v
retrieving revision 1.52
diff -u -r1.52 java-tree.h
--- java-tree.h 2000/02/09 14:08:44 1.52
+++ java-tree.h 2000/02/14 08:16:53
@@ -25,6 +25,8 @@
/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */
+#include "hash.h"
+
/* Java language-specific tree codes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
enum java_tree_code {
@@ -368,6 +370,12 @@
/* How specific the function is (for method selection - Java source
code front-end */
#define DECL_SPECIFIC_COUNT(DECL) DECL_ARG_SLOT_COUNT(DECL)
+/* For each function decl, init_test_table contains a hash table whose
+ entries are keyed on class names, and whose values are local
+ boolean decls. The variables are intended to be TRUE when the
+ class has been initialized in this function, and FALSE otherwise. */
+#define DECL_FUNCTION_INIT_TEST_TABLE(DECL) \
+ (DECL_LANG_SPECIFIC(DECL)->init_test_table)
/* In a LABEL_DECL, a TREE_VEC that saves the type_map at that point. */
#define LABEL_TYPE_STATE(NODE) (DECL_INITIAL (NODE))
@@ -443,7 +451,17 @@
tree function_decl_body; /* Hold all function's statements */
tree called_constructor; /* When decl is a constructor, the
list of other constructor it calls. */
+ struct hash_table init_test_table;
+ /* Class initialization test variables. */
};
+
+/* init_test_table hash table entry structure. */
+struct init_test_hash_entry
+{
+ struct hash_entry root;
+ tree init_test_decl;
+};
+
/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */
struct lang_decl_var
Index: gcc/java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/jcf-parse.c,v
retrieving revision 1.41
diff -u -r1.41 jcf-parse.c
--- jcf-parse.c 2000/01/21 20:57:00 1.41
+++ jcf-parse.c 2000/02/14 08:16:54
@@ -57,6 +57,10 @@
extern struct obstack temporary_obstack;
extern struct obstack permanent_obstack;
+/* Set to non-zero value in order to emit class initilization code
+ before static field references. */
+extern int always_initialize_class_p;
+
/* The class we are currently processing. */
tree current_class = NULL_TREE;
@@ -656,6 +660,10 @@
lineno = 0;
debug_start_source_file (input_filename);
init_outgoing_cpool ();
+
+ /* Currently we always have to emit calls to _Jv_InitClass when
+ compiling from class files. */
+ always_initialize_class_p = 1;
for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class));
method != NULL_TREE; method = TREE_CHAIN (method))
--
Anthony Green Red Hat
Sunnyvale, California