]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
check-init.c (flags.h): Include
authorAlexandre Petit-Bianco <apbianco@redhat.com>
Thu, 9 Aug 2001 04:19:12 +0000 (21:19 -0700)
committerAlexandre Petit-Bianco <apbianco@gcc.gnu.org>
Thu, 9 Aug 2001 04:19:12 +0000 (21:19 -0700)
2001-08-08  Alexandre Petit-Bianco  <apbianco@redhat.com>

* check-init.c (flags.h): Include
(check_init): Don't report uninitialized static class
initialization flags, don't free bit index when doing static class
initialization optimization.
(check_for_initialization): Return type changed to `unsigned int.'
(attach_initialized_static_class): New function.
* class.c (add_method_1): Create the initialized static class
table if necessary.
(finish_class): Always emit deferred inline methods.
* decl.c (emit_init_test_initialization): Moved to expr.c
(complete_start_java_method): Don't traverse
DECL_FUNCTION_INIT_TEST_TABLE.
(lang_mark_tree): Mark hash tables in function decls.
* expr.c (emit_init_test_initialization): Moved from decl.c.
(build_class_init): Create LAG_DECL_SPECIFIC for the static class
initialization flag, set DECL_CONTEXT and
LOCAL_CLASS_INITIALIZATION_FLAG.
(java_lang_expand_expr): Emit initialization code for static class
initialized flags when entering block, if necessary.
* gcj.texi (-fno-optimize-static-class-initialization): Documented.
* java-tree.h (flag_optimize_sci): New global variable declaration.
(DECL_FUNCTION_INITIALIZED_CLASS_TABLE): New macro.
(DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND): Likewise.
(LOCAL_FINAL_P): Fixed typo in comment.
(FINAL_VARIABLE_P): Likewise.
(LOCAL_CLASS_INITIALIZATIO_FLAG): New macro.
(LOCAL_CLASS_INITIALIZATIO_FLAG_P): Likewise.
(struct lang_decl): New fields `ict', `smic' and `cif.'
(check_for_initialization): New returned value for global.
(attach_initialized_static_class): New global function.
(STATIC_CLASS_INIT_OPT_P): New macro.
* lang-options.h (-fno-optimize-static-class-initialization): New flag.
* lang.c (java_decode_option): Handle
`-fno-optimize-static-class-initialization'
* parse.y (start_complete_expand_method): New function.
(java_expand_method_bodies): Likewise.
(attach_init_test_initialization_flags): Likewise.
(adjust_init_test_initialization): Likewise.
(emit_test_initialization): Likewise.
(java_complete_expand_methods): Nullify abstract and native method
bodies.
(java_complete_expand_method): New locals `fbody', `block_body'
and `exception_copy.' Reorganized: directly return on empty method
bodies, call `start_complete_expand_method', remember definitely
initialized static class in function, don't expand method bodies.
(java_expand_classes): Call `java_expand_method_bodies' before
`finish_class' when compiling to native.
(resolve_expression_name): Use `orig' after building outer class
field access.
(patch_invoke): Remember static method invokations.

(http://gcc.gnu.org/ml/gcc-patches/2001-08/msg00454.html)

From-SVN: r44733

gcc/java/ChangeLog
gcc/java/check-init.c
gcc/java/class.c
gcc/java/decl.c
gcc/java/expr.c
gcc/java/gcj.texi
gcc/java/java-tree.h
gcc/java/lang-options.h
gcc/java/lang.c
gcc/java/parse.y

index 5273aaf5cfa0a23a0c8e2397becf0a5fca09b33f..7734a5f1daeb655c90e73c6c37e894ea174005d7 100644 (file)
@@ -1,3 +1,56 @@
+2001-08-08  Alexandre Petit-Bianco  <apbianco@redhat.com>
+
+       * check-init.c (flags.h): Include
+       (check_init): Don't report uninitialized static class
+       initialization flags, don't free bit index when doing static class
+       initialization optimization.
+       (check_for_initialization): Return type changed to `unsigned int.'
+       (attach_initialized_static_class): New function.
+       * class.c (add_method_1): Create the initialized static class
+       table if necessary.
+       (finish_class): Always emit deferred inline methods.
+       * decl.c (emit_init_test_initialization): Moved to expr.c
+       (complete_start_java_method): Don't traverse
+       DECL_FUNCTION_INIT_TEST_TABLE.
+       (lang_mark_tree): Mark hash tables in function decls.
+       * expr.c (emit_init_test_initialization): Moved from decl.c.
+       (build_class_init): Create LAG_DECL_SPECIFIC for the static class
+       initialization flag, set DECL_CONTEXT and
+       LOCAL_CLASS_INITIALIZATION_FLAG.
+       (java_lang_expand_expr): Emit initialization code for static class
+       initialized flags when entering block, if necessary.
+       * gcj.texi (-fno-optimize-static-class-initialization): Documented.
+       * java-tree.h (flag_optimize_sci): New global variable declaration.
+       (DECL_FUNCTION_INITIALIZED_CLASS_TABLE): New macro.
+       (DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND): Likewise.
+       (LOCAL_FINAL_P): Fixed typo in comment.
+       (FINAL_VARIABLE_P): Likewise.
+       (LOCAL_CLASS_INITIALIZATIO_FLAG): New macro.
+       (LOCAL_CLASS_INITIALIZATIO_FLAG_P): Likewise.
+       (struct lang_decl): New fields `ict', `smic' and `cif.'
+       (check_for_initialization): New returned value for global.
+       (attach_initialized_static_class): New global function.
+       (STATIC_CLASS_INIT_OPT_P): New macro.
+       * lang-options.h (-fno-optimize-static-class-initialization): New flag.
+       * lang.c (java_decode_option): Handle
+       `-fno-optimize-static-class-initialization'
+       * parse.y (start_complete_expand_method): New function.
+       (java_expand_method_bodies): Likewise.
+       (attach_init_test_initialization_flags): Likewise.
+       (adjust_init_test_initialization): Likewise.
+       (emit_test_initialization): Likewise.
+       (java_complete_expand_methods): Nullify abstract and native method
+       bodies.
+       (java_complete_expand_method): New locals `fbody', `block_body'
+       and `exception_copy.' Reorganized: directly return on empty method
+       bodies, call `start_complete_expand_method', remember definitely
+       initialized static class in function, don't expand method bodies.
+       (java_expand_classes): Call `java_expand_method_bodies' before
+       `finish_class' when compiling to native.
+       (resolve_expression_name): Use `orig' after building outer class
+       field access.
+       (patch_invoke): Remember static method invokations.
+
 2001-08-06  Richard Henderson  <rth@redhat.com>
 
         * class.c (emit_register_classes): Pass a symbol_ref and priority
index 0e340dd85416a3a0c5d299eb6efd6216bae4954c..b108c45ce3a85abcde5e37e383060e5ca9310b61 100644 (file)
@@ -25,6 +25,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "config.h"
 #include "system.h"
 #include "tree.h"
+#include "flags.h" /* Needed for optimize. */
 #include "java-tree.h"
 #include "toplev.h" /* Needed for fatal. */
 
@@ -370,7 +371,12 @@ check_init (exp, before)
       if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE)
        {
          int index = DECL_BIT_INDEX (exp);
-         if (index >= 0 && ! SET_P (before, index))
+         /* We don't want to report and mark as non initialized flags
+            the are, they will be marked initialized later on when
+            assigned to `true.' */
+         if ((STATIC_CLASS_INIT_OPT_P ()
+              && ! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp))
+             && index >= 0 && ! SET_P (before, index))
            {
              parse_error_context 
                (wfl, "Variable `%s' may not have been initialized",
@@ -398,8 +404,13 @@ check_init (exp, before)
 
          if (index >= 0)
            SET_BIT (before, index);
-         /* Minor optimization.  See comment for start_current_locals. */
-         if (index >= start_current_locals
+         /* Minor optimization.  See comment for start_current_locals.
+            If we're optimizing for class initialization, we keep
+            this information to check whether the variable is
+            definitely assigned when once we checked the whole
+            function. */
+         if (! STATIC_CLASS_INIT_OPT_P ()
+             && index >= start_current_locals
              && index == num_current_locals - 1)
            {
              num_current_locals--;
@@ -732,10 +743,35 @@ check_init (exp, before)
     }
 }
 
-void
+unsigned int
 check_for_initialization (body)
      tree body;
 {
   word before = 0;
   check_init (body, &before);
+  return before;
+}
+
+/* Call for every element in DECL_FUNCTION_INITIALIZED_CLASS_TABLE of
+   a method to consider whether the type indirectly described by ENTRY
+   is definitly initialized and thus remembered as such. */
+
+bool
+attach_initialized_static_class (entry, ptr)
+     struct hash_entry *entry;
+     PTR ptr;
+{
+  struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
+  tree fndecl = DECL_CONTEXT (ite->init_test_decl);
+  int index = DECL_BIT_INDEX (ite->init_test_decl);
+
+  /* If the initializer flag has been definitly assigned (not taking
+     into account its first mandatory assignment which has been
+     already added but escaped analysis.) */
+  if (fndecl && METHOD_STATIC (fndecl)
+      && (DECL_INITIAL (ite->init_test_decl) == boolean_true_node
+         || (index >= 0 && SET_P (((word *) ptr), index))))
+    hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
+                entry->key, TRUE, NULL);
+  return true;
 }
index 8113340e3fc961cb07e33776b62e120e672de9b0..7e153b5b8f5bedad1accf218838c55c55e638df9 100644 (file)
@@ -673,6 +673,18 @@ add_method_1 (handle_class, access_flags, name, function_type)
                   init_test_hash_newfunc, java_hash_hash_tree_node, 
                   java_hash_compare_tree_node);
 
+  /* Initialize the initialized (static) class table. */
+  if (access_flags & ACC_STATIC)
+    hash_table_init (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
+                    init_test_hash_newfunc, java_hash_hash_tree_node,
+                    java_hash_compare_tree_node);
+
+  /* Initialize the static method invocation compound table */
+  if (STATIC_CLASS_INIT_OPT_P ())
+    hash_table_init (&DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl),
+                    init_test_hash_newfunc, java_hash_hash_tree_node,
+                    java_hash_compare_tree_node);
+
   TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
   TYPE_METHODS (handle_class) = fndecl;
 
@@ -1484,18 +1496,11 @@ finish_class ()
     {
       if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0)
        {
-         /* It's a deferred inline method.  Decide if we need to emit it. */
-         if (flag_keep_inline_functions
-             || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (method))
-             || ! METHOD_PRIVATE (method)
-             || saw_native_method)
-           {
-             output_inline_function (method);
-             /* Scan the list again to see if there are any earlier
-                 methods to emit. */
-             method = type_methods;
-             continue;
-           }
+         output_inline_function (method);
+         /* Scan the list again to see if there are any earlier
+            methods to emit. */
+         method = type_methods;
+         continue;
        }
       method = TREE_CHAIN (method);
     }
index 3b856db50d87f186c15c0b98b3c6dd2955118bc0..4eb073933a995c5fa2dab3711626eb2113e3e7c6 100644 (file)
@@ -49,8 +49,6 @@ static tree push_jvm_slot PARAMS ((int, tree));
 static tree lookup_name_current_level PARAMS ((tree));
 static tree push_promoted_type PARAMS ((const char *, tree));
 static struct binding_level *make_binding_level PARAMS ((void));
-static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
-                                                     hash_table_key));
 static tree create_primitive_vtable PARAMS ((const char *));
 static tree check_local_named_variable PARAMS ((tree, tree, int, int *));
 static tree check_local_unnamed_variable PARAMS ((tree, tree, tree));
@@ -1639,35 +1637,6 @@ build_result_decl (fndecl)
   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 bool
-emit_init_test_initialization (entry, key)
-  struct hash_entry *entry;
-  hash_table_key key ATTRIBUTE_UNUSED;
-{
-  struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
-  tree klass = build_class_ref ((tree) entry->key);
-  expand_decl (ite->init_test_decl);
-
-  /* We initialize the class init check variable by looking at the
-     `state' field of the class to see if it is already initialized.
-     This makes things a bit faster if the class is already
-     initialized, which should be the common case.  */
-  expand_expr_stmt
-    (build (MODIFY_EXPR, boolean_type_node, 
-           ite->init_test_decl,
-           build (GE_EXPR, boolean_type_node,
-                  build (COMPONENT_REF, byte_type_node,
-                         build1 (INDIRECT_REF, class_type_node, klass),
-                         lookup_field (&class_type_node,
-                                       get_identifier ("state"))),
-                  build_int_2 (JV_STATE_DONE, 0))));
-
-  return true;
-}
-
 void
 complete_start_java_method (fndecl)
   tree fndecl;
@@ -1679,11 +1648,6 @@ complete_start_java_method (fndecl)
 
       /* 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);
     }
 
 #if 0
@@ -1871,6 +1835,9 @@ lang_mark_tree (t)
          ggc_mark_tree (ld->function_decl_body);
          ggc_mark_tree (ld->called_constructor);
          ggc_mark_tree (ld->inner_access);
+         ggc_mark_tree_hash_table (&ld->init_test_table);
+         ggc_mark_tree_hash_table (&ld->ict);
+         ggc_mark_tree_hash_table (&ld->smic);
        }
     }
   else if (TYPE_P (t))
index c9b4a3cd833343f28414ca0215d74531de917558..f7056fee4f4ff7ad02b93c896aeb39972dba3473 100644 (file)
@@ -82,6 +82,8 @@ static tree build_java_check_indexed_type PARAMS ((tree, tree));
 static tree java_array_data_offset PARAMS ((tree)); 
 static tree case_identity PARAMS ((tree, tree)); 
 static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int));
+static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
+                                                  PTR ptr));
 
 static tree operand_type[59];
 extern struct obstack permanent_obstack;
@@ -1710,10 +1712,20 @@ build_class_init (clas, expr)
                     TRUE, NULL);
       
       if (ite->init_test_decl == 0)
-       ite->init_test_decl = build_decl (VAR_DECL, NULL_TREE, 
-                                         boolean_type_node);
-      /* Tell the check-init code to ignore this decl.  */
-      DECL_BIT_INDEX(ite->init_test_decl) = -1;
+       {
+         /* Build a declaration and mark it as a flag used to track
+            static class initializations. */
+         ite->init_test_decl = build_decl (VAR_DECL, NULL_TREE,
+                                           boolean_type_node);
+         MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (ite->init_test_decl);
+         LOCAL_CLASS_INITIALIZATION_FLAG (ite->init_test_decl) = 1;
+         DECL_CONTEXT (ite->init_test_decl) = current_function_decl;
+
+         /* Tell the check-init code to ignore this decl when not
+             optimizing class initialization. */
+         if (!STATIC_CLASS_INIT_OPT_P ())
+           DECL_BIT_INDEX(ite->init_test_decl) = -1;
+       }
 
       init = build (CALL_EXPR, void_type_node,
                    build_address_of (soft_initclass_node),
@@ -2459,16 +2471,31 @@ java_lang_expand_expr (exp, target, tmode, modifier)
        {
          tree local;
          tree body = BLOCK_EXPR_BODY (exp);
+         /* Set to 1 or more when we found a static class
+             initialization flag. */
+         int found_class_initialization_flag = 0;
+
          pushlevel (2);        /* 2 and above */
          expand_start_bindings (0);
          local = BLOCK_EXPR_DECLS (exp);
          while (local)
            {
              tree next = TREE_CHAIN (local);
+             found_class_initialization_flag +=
+               LOCAL_CLASS_INITIALIZATION_FLAG_P (local);
              layout_decl (local, 0);
              expand_decl (pushdecl (local));
              local = next;
            }
+
+         /* Emit initialization code for test flags if we saw one. */
+         if (! always_initialize_class_p 
+             && current_function_decl
+             && found_class_initialization_flag)
+           hash_traverse 
+             (&DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl),
+              emit_init_test_initialization, NULL);
+
          /* Avoid deep recursion for long block.  */
          while (TREE_CODE (body) == COMPOUND_EXPR)
            {
@@ -3335,3 +3362,37 @@ force_evaluation_order (node)
     }
   return node;
 }
+
+/* Called for every element in DECL_FUNCTION_INIT_TEST_TABLE of a
+   method in order to emit initialization code for each test flag.  */
+
+static bool
+emit_init_test_initialization (entry, key)
+  struct hash_entry *entry;
+  hash_table_key key ATTRIBUTE_UNUSED;
+{
+  struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
+  tree klass = build_class_ref ((tree) entry->key);
+  tree rhs;
+
+  /* If the DECL_INITIAL of the test flag is set to true, it
+     means that the class is already initialized the time it
+     is in use. */
+  if (DECL_INITIAL (ite->init_test_decl) == boolean_true_node)
+    rhs = boolean_true_node;
+  /* Otherwise, we initialize the class init check variable by looking
+     at the `state' field of the class to see if it is already
+     initialized.  This makes things a bit faster if the class is
+     already initialized, which should be the common case.  */
+  else
+    rhs = build (GE_EXPR, boolean_type_node,
+                build (COMPONENT_REF, byte_type_node,
+                       build1 (INDIRECT_REF, class_type_node, klass),
+                       lookup_field (&class_type_node,
+                                     get_identifier ("state"))),
+                build_int_2 (JV_STATE_DONE, 0));
+
+  expand_expr_stmt (build (MODIFY_EXPR, boolean_type_node, 
+                          ite->init_test_decl, rhs));
+  return true;
+}
index 1ccd7c9ed1fdc7060970b804b220a3e9123691bb..6a52fc64ca59b451d8b255ffc82e01a6879f8c9e 100644 (file)
@@ -356,6 +356,14 @@ compiling a class with native methods, and these methods are implemented
 using JNI, then you must use @code{-fjni}.  This option causes
 @code{gcj} to generate stubs which will invoke the underlying JNI
 methods.
+
+@item -fno-optimize-static-class-initialization
+When the optimization level is greather or equal to @code{-O2},
+@code{gcj} will try to optimize the way calls into the runtime are made
+to initialize static classes upon their first use (this optimization
+isn't carried out if @code{-C} was specified.) When compiling to native
+code, @code{-fno-optimize-static-class-initialization} will turn this
+optimization off, regardless of the optimization level in use.
 @end table
 
 
index 03d3cc2e3e60916879beabce1508d2f3d1155bfb..d114747a8e7beb36c10fe4a99ba4e2b4c02572fd 100644 (file)
@@ -186,6 +186,10 @@ extern int flag_hash_synchronization;
 /* When non zero, generate checks for references to NULL.  */
 extern int flag_check_references;
 
+/* Used through STATIC_CLASS_INIT_OPT_P to check whether static
+   initialization optimization should be performed.  */
+extern int flag_optimize_sci;
+
 /* Encoding used for source files.  */
 extern const char *current_encoding;
 
@@ -704,6 +708,16 @@ struct lang_identifier
    class has been initialized in this function, and FALSE otherwise.  */
 #define DECL_FUNCTION_INIT_TEST_TABLE(DECL) \
   (DECL_LANG_SPECIFIC(DECL)->init_test_table)
+/* For each static function decl, itc contains a hash table whose
+   entries are keyed on class named that are definitively initialized
+   in DECL.  */
+#define DECL_FUNCTION_INITIALIZED_CLASS_TABLE(DECL) \
+  (DECL_LANG_SPECIFIC(DECL)->ict)
+/* For each static function call, smic contains contains a hash table
+   whose entries are keyed on the compound statement that encapsulate
+   the invocation.  */
+#define DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND(DECL) \
+  (DECL_LANG_SPECIFIC(DECL)->smic)
 /* The Number of Artificial Parameters (NAP) DECL contains. this$<n>
    is excluded, because sometimes created as a parameter before the
    function decl exists. */
@@ -815,11 +829,18 @@ struct lang_identifier
   (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->local_final)
 /* True if NODE is a local final. */
 #define LOCAL_FINAL_P(NODE) (DECL_LANG_SPECIFIC (NODE) && LOCAL_FINAL (NODE))
-/* True if NODE is a final variable */
+/* True if NODE is a final variable. */
 #define FINAL_VARIABLE_P(NODE) (FIELD_FINAL (NODE) && !FIELD_STATIC (NODE))
-/* True if NODE is a class final variable */
+/* True if NODE is a class final variable. */
 #define CLASS_FINAL_VARIABLE_P(NODE) \
   (FIELD_FINAL (NODE) && FIELD_STATIC (NODE))
+/* True if NODE is a class initialization flag. This macro accesses
+   the flag to read or set it.  */
+#define LOCAL_CLASS_INITIALIZATION_FLAG(NODE) \
+    (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->cif)
+/* True if NODE is a class initialization flag. */
+#define LOCAL_CLASS_INITIALIZATION_FLAG_P(NODE) \
+    (DECL_LANG_SPECIFIC (NODE) && LOCAL_CLASS_INITIALIZATION_FLAG(NODE))
 /* Create a DECL_LANG_SPECIFIC if necessary. */
 #define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T)                 \
   if (DECL_LANG_SPECIFIC (T) == NULL)                          \
@@ -858,6 +879,8 @@ struct lang_decl
                                   list of other constructor it calls */
   struct hash_table init_test_table;
                                /* Class initialization test variables  */
+  struct hash_table ict;       /* Initialized (static) Class Table */
+  struct hash_table smic;      /* Static method invocation compound */
   tree inner_access;           /* The identifier of the access method
                                   used for invocation from inner classes */
   int nap;                     /* Number of artificial parameters */
@@ -888,6 +911,7 @@ struct lang_decl_var
   int final_liic : 1;          /* Final locally initialized in ctors */
   int final_ierr : 1;          /* Initialization error already detected */
   int local_final : 1;         /* True if the decl is a local final */
+  int cif : 1;                 /* True: decl is a class initialization flag */
 };
 
 /* Macro to access fields in `struct lang_type'.  */
@@ -1061,7 +1085,7 @@ extern void parse_error_context PARAMS ((tree cl, const char *, ...))
 extern tree build_primtype_type_ref PARAMS ((const char *));
 extern void finish_class PARAMS ((void));
 extern void java_layout_seen_class_methods PARAMS ((void));
-extern void check_for_initialization PARAMS ((tree));
+extern unsigned int check_for_initialization PARAMS ((tree));
 
 extern tree pushdecl_top_level PARAMS ((tree));
 extern int alloc_class_constant PARAMS ((tree));
@@ -1129,6 +1153,8 @@ extern tree get_boehm_type_descriptor PARAMS ((tree));
 extern unsigned long java_hash_hash_tree_node PARAMS ((hash_table_key));
 extern bool java_hash_compare_tree_node PARAMS ((hash_table_key, 
                                                    hash_table_key));
+extern bool attach_initialized_static_class PARAMS ((struct hash_entry *,
+                                                    PTR));
 extern void java_check_methods PARAMS ((tree));
 extern void init_jcf_parse PARAMS((void));
 extern void init_src_parse PARAMS((void));
@@ -1559,6 +1585,10 @@ extern tree *type_map;
   (inherits_from_p ((TYPE), runtime_exception_type_node)       \
    || inherits_from_p ((TYPE), error_exception_type_node))
 
+/* True when we can perform static class initialization optimization */
+#define STATIC_CLASS_INIT_OPT_P() \
+  (flag_optimize_sci && (optimize >= 2) && ! flag_emit_class_files)
+
 extern int java_error_count;                                   \
 
 /* Make the current function where this macro is invoked report error
index 17a16966551fd655da4808f7551112fe4a2c0732..06a4c4d69101c8f9b0a93f2522ea4ccaf41e20b7 100644 (file)
@@ -52,3 +52,5 @@ DEFINE_LANG_NAME ("Java")
     N_("Warn if .class files are out of date") },
   { "-fforce-classes-archive-check", 
     N_("Always check for non gcj generated classes archives") },
+  { "-fno-optimize-static-class-initialization",
+    N_("Never optimize static class initialization code") },
index 91f89be08e665f81c68c538130cfb50d18b3ad11..b9cb0fea7b6f64e609eb50c9a6c3cec681773ec2 100644 (file)
@@ -146,6 +146,10 @@ int flag_extraneous_semicolon;
 /* When non zero, always check for a non gcj generated classes archive.  */
 int flag_force_classes_archive_check;
 
+/* When zero, don't optimize static class initialization. This flag shouldn't
+   be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead.  */
+int flag_optimize_sci = 1;
+
 /* Table of language-dependent -f options.
    STRING is the option name.  VARIABLE is the address of the variable.
    ON_VALUE is the value to store in VARIABLE
@@ -295,6 +299,15 @@ java_decode_option (argc, argv)
     }
 #undef ARG
 
+#undef ARG
+#define ARG "-fno-optimize-static-class-initialization"
+  if (strncmp (p, ARG, sizeof (ARG) - 1) == 0)
+    {
+      flag_optimize_sci = 0;
+      return 1;
+    }
+#undef ARG
+
   if (p[0] == '-' && p[1] == 'f')
     {
       /* Some kind of -f option.
index 05be63314a8f256f05053c1e4a173184c6e59802..a1f36aaa281b1771a2b9bb6e1a4d524336ecbe0b 100644 (file)
@@ -147,7 +147,9 @@ static tree java_complete_tree PARAMS ((tree));
 static tree maybe_generate_pre_expand_clinit PARAMS ((tree));
 static int analyze_clinit_body PARAMS ((tree));
 static int maybe_yank_clinit PARAMS ((tree));
+static void start_complete_expand_method PARAMS ((tree));
 static void java_complete_expand_method PARAMS ((tree));
+static void java_expand_method_bodies PARAMS ((tree));
 static int  unresolved_type_p PARAMS ((tree, tree *));
 static void create_jdep_list PARAMS ((struct parser_ctxt *));
 static tree build_expr_block PARAMS ((tree, tree));
@@ -332,6 +334,12 @@ static void create_new_parser_context PARAMS ((int));
 static void mark_parser_ctxt PARAMS ((void *));
 static tree maybe_build_class_init_for_field PARAMS ((tree, tree));
 
+static bool attach_init_test_initialization_flags PARAMS ((struct hash_entry *,
+                                                         PTR));
+static bool adjust_init_test_initialization PARAMS ((struct hash_entry *,
+                                                    PTR));
+static bool emit_test_initialization PARAMS ((struct hash_entry *, PTR));
+
 /* Number of error found so far. */
 int java_error_count; 
 /* Number of warning found so far. */
@@ -7513,12 +7521,17 @@ java_complete_expand_methods (class_decl)
   /* First, do the ordinary methods. */
   for (decl = first_decl; decl; decl = TREE_CHAIN (decl))
     {
+      /* Ctors aren't part of this batch. */
+      if (DECL_CONSTRUCTOR_P (decl) || DECL_CLINIT_P (decl))
+       continue;
+      
       /* Skip abstract or native methods -- but do handle native
         methods when generating JNI stubs.  */
-      if (METHOD_ABSTRACT (decl)
-         || (! flag_jni && METHOD_NATIVE (decl))
-         || DECL_CONSTRUCTOR_P (decl) || DECL_CLINIT_P (decl))
-       continue;
+      if (METHOD_ABSTRACT (decl) || (! flag_jni && METHOD_NATIVE (decl)))
+       {
+         DECL_FUNCTION_BODY (decl) = NULL_TREE;
+         continue;
+       }
 
       if (METHOD_NATIVE (decl))
        {
@@ -7751,6 +7764,40 @@ maybe_yank_clinit (mdecl)
   return 1;
 }
 
+/* Install the argument from MDECL. Suitable to completion and
+   expansion of mdecl's body.  */
+
+static void
+start_complete_expand_method (mdecl)
+     tree mdecl;
+{
+  tree tem, *ptr;
+
+  pushlevel (1);               /* Prepare for a parameter push */
+  ptr = &DECL_ARGUMENTS (mdecl);
+  tem  = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl));
+
+  while (tem)
+    {
+      tree next = TREE_CHAIN (tem);
+      tree type = TREE_TYPE (tem);
+      if (PROMOTE_PROTOTYPES
+         && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+         && INTEGRAL_TYPE_P (type))
+       type = integer_type_node;
+      DECL_ARG_TYPE (tem) = type;
+      layout_decl (tem, 0);
+      pushdecl (tem);
+      *ptr = tem;
+      ptr = &TREE_CHAIN (tem);
+      tem = next;
+    }
+  *ptr = NULL_TREE;
+  pushdecl_force_head (DECL_ARGUMENTS (mdecl));
+  lineno = DECL_SOURCE_LINE_FIRST (mdecl);
+  build_result_decl (mdecl);
+}
+
 
 /* Complete and expand a method.  */
 
@@ -7758,7 +7805,7 @@ static void
 java_complete_expand_method (mdecl)
      tree mdecl;
 {
-  int yank_clinit = 0;
+  tree fbody, block_body, exception_copy;
 
   current_function_decl = mdecl;
   /* Fix constructors before expanding them */
@@ -7766,103 +7813,131 @@ java_complete_expand_method (mdecl)
     fix_constructors (mdecl);
   
   /* Expand functions that have a body */
-  if (DECL_FUNCTION_BODY (mdecl))
-    {
-      tree fbody = DECL_FUNCTION_BODY (mdecl);
-      tree block_body = BLOCK_EXPR_BODY (fbody);
-      tree exception_copy = NULL_TREE;
-      tree tem, *ptr;
-
-      current_function_decl = mdecl;
-
-      if (! quiet_flag)
-       fprintf (stderr, " [%s.",
-                lang_printable_name (DECL_CONTEXT (mdecl), 0));
-      announce_function (mdecl);
-      if (! quiet_flag)
-       fprintf (stderr, "]");
-
-      pushlevel (1);           /* Prepare for a parameter push */
-      ptr = &DECL_ARGUMENTS (mdecl);
-      tem  = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl));
-      while (tem)
-       {
-         tree next = TREE_CHAIN (tem);
-         tree type = TREE_TYPE (tem);
-         if (PROMOTE_PROTOTYPES
-             && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
-             && INTEGRAL_TYPE_P (type))
-           type = integer_type_node;
-         DECL_ARG_TYPE (tem) = type;
-         layout_decl (tem, 0);
-         pushdecl (tem);
-         *ptr = tem;
-         ptr = &TREE_CHAIN (tem);
-         tem = next;
-       }
-      *ptr = NULL_TREE;
-      pushdecl_force_head (DECL_ARGUMENTS (mdecl));
-      lineno = DECL_SOURCE_LINE_FIRST (mdecl);
-
-      build_result_decl (mdecl);
-
-      current_this 
-       = (!METHOD_STATIC (mdecl) ? 
-          BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
-
-      /* Purge the `throws' list of unchecked exceptions. If we're
-        doing xref, save a copy of the list and re-install it
-        later. */
-      if (flag_emit_xref)
-       exception_copy = copy_list (DECL_FUNCTION_THROWS (mdecl));
-
-      purge_unchecked_exceptions (mdecl);
-
-      /* Install exceptions thrown with `throws' */
-      PUSH_EXCEPTIONS (DECL_FUNCTION_THROWS (mdecl));
+  if (!DECL_FUNCTION_BODY (mdecl))
+    return;
 
-      if (block_body != NULL_TREE)
-       {
-         block_body = java_complete_tree (block_body);
+  fbody = DECL_FUNCTION_BODY (mdecl);
+  block_body = BLOCK_EXPR_BODY (fbody);
+  exception_copy = NULL_TREE;
 
-         if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
-           check_for_initialization (block_body);
-         ctxp->explicit_constructor_p = 0;
-       }
+  current_function_decl = mdecl;
 
-      BLOCK_EXPR_BODY (fbody) = block_body;
+  if (! quiet_flag)
+    fprintf (stderr, " [%s.",
+            lang_printable_name (DECL_CONTEXT (mdecl), 0));
+  announce_function (mdecl);
+  if (! quiet_flag)
+    fprintf (stderr, "]");
+  
+  /* Prepare the function for tree completion */
+  start_complete_expand_method (mdecl);
 
-      /* If we saw a return but couldn't evaluate it properly, we'll
-        have an error_mark_node here. */
-      if (block_body != error_mark_node
-         && (block_body == NULL_TREE || CAN_COMPLETE_NORMALLY (block_body))
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (mdecl))) != VOID_TYPE
-         && !flag_emit_xref)
-       missing_return_error (current_function_decl);
+  /* Install the current this */
+  current_this = (!METHOD_STATIC (mdecl) ? 
+                 BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
 
-      /* Check wether we could just get rid of clinit, now the picture
-         is complete. */
-      if (!(yank_clinit = maybe_yank_clinit (mdecl)))
-       complete_start_java_method (mdecl); 
+  /* Purge the `throws' list of unchecked exceptions. If we're doing
+     xref, save a copy of the list and re-install it later. */
+  if (flag_emit_xref)
+    exception_copy = copy_list (DECL_FUNCTION_THROWS (mdecl));
+  purge_unchecked_exceptions (mdecl);
+  
+  /* Install exceptions thrown with `throws' */
+  PUSH_EXCEPTIONS (DECL_FUNCTION_THROWS (mdecl));
+  
+  if (block_body != NULL_TREE)
+    {
+      block_body = java_complete_tree (block_body);
       
-      /* Don't go any further if we've found error(s) during the
-        expansion */
-      if (!java_error_count && !yank_clinit)
-       source_end_java_method ();
-      else
+      /* Before we check initialization, attached all class initialization
+        variable to the block_body */
+      hash_traverse (&DECL_FUNCTION_INIT_TEST_TABLE (mdecl),
+                    attach_init_test_initialization_flags, block_body);
+      
+      if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
        {
-         if (java_error_count)
-           pushdecl_force_head (DECL_ARGUMENTS (mdecl));
-         poplevel (1, 0, 1);
+         unsigned int state = check_for_initialization (block_body);
+         
+         /* Go through all the flags marking the initialization of
+            static variables and see whether they're definitively
+            assigned, in which case the type is remembered as
+            definitively initialized in MDECL. */
+         if (STATIC_CLASS_INIT_OPT_P ())
+           {
+             hash_traverse (&DECL_FUNCTION_INIT_TEST_TABLE (mdecl),
+                            attach_initialized_static_class, (PTR)&state);
+
+             /* Always register the context as properly initialized in
+                MDECL. This used with caution helps removing extra
+                initialization of self. */
+             if (METHOD_STATIC (mdecl))
+               hash_lookup (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (mdecl),
+                            (hash_table_key) DECL_CONTEXT (mdecl),
+                            TRUE, NULL);
+           }
        }
+      ctxp->explicit_constructor_p = 0;
+    }
+  
+  BLOCK_EXPR_BODY (fbody) = block_body;
+  
+  /* If we saw a return but couldn't evaluate it properly, we'll have
+     an error_mark_node here. */
+  if (block_body != error_mark_node
+      && (block_body == NULL_TREE || CAN_COMPLETE_NORMALLY (block_body))
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (mdecl))) != VOID_TYPE
+      && !flag_emit_xref)
+    missing_return_error (current_function_decl);
 
-      /* Pop the exceptions and sanity check */
-      POP_EXCEPTIONS();
-      if (currently_caught_type_list)
-       abort ();
+  /* See if we can get rid of <clinit> if MDECL happens to be <clinit> */
+  maybe_yank_clinit (mdecl);
 
-      if (flag_emit_xref)
-       DECL_FUNCTION_THROWS (mdecl) = exception_copy;
+  /* Pop the current level, with special measures if we found errors. */
+  if (java_error_count)
+    pushdecl_force_head (DECL_ARGUMENTS (mdecl));
+  poplevel (1, 0, 1);
+
+  /* Pop the exceptions and sanity check */
+  POP_EXCEPTIONS();
+  if (currently_caught_type_list)
+    abort ();
+
+  /* Restore the copy of the list of exceptions if emitting xrefs. */
+  if (flag_emit_xref)
+    DECL_FUNCTION_THROWS (mdecl) = exception_copy;
+}
+
+/* For with each class for which there's code to generate. */
+
+static void
+java_expand_method_bodies (class)
+     tree class;
+{
+  tree decl;
+  for (decl = TYPE_METHODS (class); decl; decl = TREE_CHAIN (decl))
+    {
+      if (!DECL_FUNCTION_BODY (decl))
+       continue;
+
+      current_function_decl = decl;
+
+      /* It's time to assign the variable flagging static class
+        initialization based on which classes invoked static methods
+        are definitely initializing. This should be flagged. */
+      if (STATIC_CLASS_INIT_OPT_P ())
+       hash_traverse (&DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (decl),
+                      adjust_init_test_initialization, NULL);
+
+      /* Prepare the function for RTL expansion */  
+      start_complete_expand_method (decl);
+
+      /* Expand function start, generate initialization flag
+        assignment, and handle synchronized methods. */
+      complete_start_java_method (decl);
+
+      /* Expand the rest of the function body and terminate
+         expansion. */
+      source_end_java_method ();
     }
 }
 
@@ -8783,7 +8858,10 @@ java_expand_classes ()
          if (flag_emit_xref)
            expand_xref (current_class);
          else if (! flag_syntax_only)
-           finish_class ();
+           {
+             java_expand_method_bodies (current_class);
+             finish_class ();
+           }
        }
     }
 }
@@ -8963,7 +9041,10 @@ resolve_expression_name (id, orig)
                      static_ref_err (id, DECL_NAME (decl), current_class);
                      return error_mark_node;
                    }
-                 return build_outer_field_access (id, decl);
+                 access = build_outer_field_access (id, decl);
+                 if (orig)
+                   *orig = access;
+                 return access;
                }
 
              /* Otherwise build what it takes to access the field */
@@ -10438,6 +10519,30 @@ patch_invoke (patch, method, args)
       TREE_SIDE_EFFECTS (patch) = 1;
     }
 
+  /* In order to be able to modify PATCH later, we SAVE_EXPR it and
+     put it as the first expression of a COMPOUND_EXPR. The second
+     expression being an empty statement to be later patched if
+     necessary. We remember a TREE_LIST (the PURPOSE is the method,
+     the VALUE is the compound) in a hashtable and return a
+     COMPOUND_EXPR built so that the result of the evaluation of the
+     original PATCH node is returned. */
+  if (STATIC_CLASS_INIT_OPT_P ()
+      && current_function_decl && METHOD_STATIC (method))
+    {
+      tree list;
+      tree fndecl = current_function_decl;
+      tree save = save_expr (patch);
+      tree type = TREE_TYPE (patch);
+
+      patch = build (COMPOUND_EXPR, type, save, empty_stmt_node);
+      list = build_tree_list (method, patch);
+
+      hash_lookup (&DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl),
+                  (const hash_table_key) list, TRUE, NULL);
+
+      patch = build (COMPOUND_EXPR, type, patch, save);
+    }
+
   return patch;
 }
 
@@ -15853,3 +15958,111 @@ init_src_parse ()
   /* Register roots with the garbage collector.  */
   ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree));
 }
+
+\f
+
+/* This section deals with the functions that are called when tables
+   recording class initialization information are traversed.  */
+
+/* Attach to PTR (a block) the declaration found in ENTRY. */
+
+static bool
+attach_init_test_initialization_flags (entry, ptr)
+     struct hash_entry *entry;
+     PTR ptr;
+{
+  tree block = (tree)ptr;
+  struct init_test_hash_entry *ite = (struct init_test_hash_entry *) entry;
+  
+  TREE_CHAIN (ite->init_test_decl) = BLOCK_EXPR_DECLS (block);
+  BLOCK_EXPR_DECLS (block) = ite->init_test_decl;
+  return true;
+}
+
+/* This function is called for each statement calling a static
+   function.  ENTRY is a TREE_LIST whose PURPOSE is the called
+   function and VALUE is a compound whose second operand can be
+   patched with static class initialization flag assignments.  */
+
+static bool
+adjust_init_test_initialization (entry, info)
+     struct hash_entry *entry;
+     PTR info ATTRIBUTE_UNUSED;
+{
+  tree list = (tree)(entry->key);
+  tree called_method = TREE_PURPOSE (list);
+  tree compound = TREE_VALUE (list);
+  tree assignment_compound_list = build_tree_list (called_method, NULL);
+
+  /* For each class definitely initialized in CALLED_METHOD, fill
+     ASSIGNMENT_COMPOUND with assignment to the class initialization flag. */
+  hash_traverse (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (called_method),
+                emit_test_initialization, assignment_compound_list);
+
+  if (TREE_VALUE (assignment_compound_list))
+    TREE_OPERAND (compound, 1) = TREE_VALUE (assignment_compound_list);
+
+  return true;
+}
+
+/* This function is called for each classes that is known definitely
+   assigned when a given static method was called. This function
+   augments a compound expression (INFO) storing all assignment to
+   initialized static class flags if a flag already existed, otherwise
+   a new one is created.  */
+
+static bool
+emit_test_initialization (entry, info)
+     struct hash_entry *entry;
+     PTR info;
+{
+  tree l = (tree) info;
+  tree decl, init;
+
+  struct init_test_hash_entry *ite = (struct init_test_hash_entry *)
+    hash_lookup (&DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl),
+                entry->key, FALSE, NULL);
+
+  /* If we haven't found a flag and we're dealing with self registered
+     with current_function_decl, then don't do anything. Self is
+     always added as definitely initialized but this information is
+     valid only if used outside the current function. */
+  if (! ite)
+    {
+      if (current_function_decl != TREE_PURPOSE (l))
+       ite = (struct init_test_hash_entry *)
+         hash_lookup (&DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl),
+                      entry->key, TRUE, NULL);
+      else
+       return true;
+    }
+
+  /* If we don't have a variable, create one and install it. */
+  if (! ite->init_test_decl)
+    {
+      tree block;
+      
+      decl = build_decl (VAR_DECL, NULL_TREE, boolean_type_node);
+      MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
+      LOCAL_CLASS_INITIALIZATION_FLAG (decl) = 1;
+      DECL_CONTEXT (decl) = current_function_decl;
+      DECL_INITIAL (decl) = boolean_true_node;
+
+      /* The trick is to find the right context for it. */
+      block = BLOCK_SUBBLOCKS (GET_CURRENT_BLOCK (current_function_decl));
+      TREE_CHAIN (decl) = BLOCK_EXPR_DECLS (block);
+      BLOCK_EXPR_DECLS (block) = decl;
+      ite->init_test_decl = decl;
+    }
+  else
+    decl = ite->init_test_decl;
+
+  /* Now simply augment the compound that holds all the assignments
+     pertaining to this method invocation. */
+  init = build (MODIFY_EXPR, boolean_type_node, decl, boolean_true_node);
+  TREE_SIDE_EFFECTS (init) = 1;
+  TREE_VALUE (l) = add_stmt_to_compound (TREE_VALUE (l), void_type_node, init);
+  TREE_SIDE_EFFECTS (TREE_VALUE (l)) = 1;
+
+  return true;
+}