Commit 4009bb7d by Alexandre Petit-Bianco Committed by Alexandre Petit-Bianco

check-init.c (flags.h): Include

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
parent 6351543d
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> 2001-08-06 Richard Henderson <rth@redhat.com>
* class.c (emit_register_classes): Pass a symbol_ref and priority * class.c (emit_register_classes): Pass a symbol_ref and priority
......
...@@ -25,6 +25,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ ...@@ -25,6 +25,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "config.h" #include "config.h"
#include "system.h" #include "system.h"
#include "tree.h" #include "tree.h"
#include "flags.h" /* Needed for optimize. */
#include "java-tree.h" #include "java-tree.h"
#include "toplev.h" /* Needed for fatal. */ #include "toplev.h" /* Needed for fatal. */
...@@ -370,7 +371,12 @@ check_init (exp, before) ...@@ -370,7 +371,12 @@ check_init (exp, before)
if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE) if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE)
{ {
int index = DECL_BIT_INDEX (exp); 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 parse_error_context
(wfl, "Variable `%s' may not have been initialized", (wfl, "Variable `%s' may not have been initialized",
...@@ -398,8 +404,13 @@ check_init (exp, before) ...@@ -398,8 +404,13 @@ check_init (exp, before)
if (index >= 0) if (index >= 0)
SET_BIT (before, index); SET_BIT (before, index);
/* Minor optimization. See comment for start_current_locals. */ /* Minor optimization. See comment for start_current_locals.
if (index >= 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) && index == num_current_locals - 1)
{ {
num_current_locals--; num_current_locals--;
...@@ -732,10 +743,35 @@ check_init (exp, before) ...@@ -732,10 +743,35 @@ check_init (exp, before)
} }
} }
void unsigned int
check_for_initialization (body) check_for_initialization (body)
tree body; tree body;
{ {
word before = 0; word before = 0;
check_init (body, &before); 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;
} }
...@@ -673,6 +673,18 @@ add_method_1 (handle_class, access_flags, name, function_type) ...@@ -673,6 +673,18 @@ add_method_1 (handle_class, access_flags, name, function_type)
init_test_hash_newfunc, java_hash_hash_tree_node, init_test_hash_newfunc, java_hash_hash_tree_node,
java_hash_compare_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); TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
TYPE_METHODS (handle_class) = fndecl; TYPE_METHODS (handle_class) = fndecl;
...@@ -1484,18 +1496,11 @@ finish_class () ...@@ -1484,18 +1496,11 @@ finish_class ()
{ {
if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0) if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0)
{ {
/* It's a deferred inline method. Decide if we need to emit it. */ output_inline_function (method);
if (flag_keep_inline_functions /* Scan the list again to see if there are any earlier
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (method)) methods to emit. */
|| ! METHOD_PRIVATE (method) method = type_methods;
|| saw_native_method) 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); method = TREE_CHAIN (method);
} }
......
...@@ -49,8 +49,6 @@ static tree push_jvm_slot PARAMS ((int, tree)); ...@@ -49,8 +49,6 @@ static tree push_jvm_slot PARAMS ((int, tree));
static tree lookup_name_current_level PARAMS ((tree)); static tree lookup_name_current_level PARAMS ((tree));
static tree push_promoted_type PARAMS ((const char *, tree)); static tree push_promoted_type PARAMS ((const char *, tree));
static struct binding_level *make_binding_level PARAMS ((void)); 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 create_primitive_vtable PARAMS ((const char *));
static tree check_local_named_variable PARAMS ((tree, tree, int, int *)); static tree check_local_named_variable PARAMS ((tree, tree, int, int *));
static tree check_local_unnamed_variable PARAMS ((tree, tree, tree)); static tree check_local_unnamed_variable PARAMS ((tree, tree, tree));
...@@ -1639,35 +1637,6 @@ build_result_decl (fndecl) ...@@ -1639,35 +1637,6 @@ build_result_decl (fndecl)
return (DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, restype)); 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 void
complete_start_java_method (fndecl) complete_start_java_method (fndecl)
tree fndecl; tree fndecl;
...@@ -1679,11 +1648,6 @@ complete_start_java_method (fndecl) ...@@ -1679,11 +1648,6 @@ complete_start_java_method (fndecl)
/* Set up parameters and prepare for return, for the function. */ /* Set up parameters and prepare for return, for the function. */
expand_function_start (fndecl, 0); 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 #if 0
...@@ -1871,6 +1835,9 @@ lang_mark_tree (t) ...@@ -1871,6 +1835,9 @@ lang_mark_tree (t)
ggc_mark_tree (ld->function_decl_body); ggc_mark_tree (ld->function_decl_body);
ggc_mark_tree (ld->called_constructor); ggc_mark_tree (ld->called_constructor);
ggc_mark_tree (ld->inner_access); 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)) else if (TYPE_P (t))
......
...@@ -82,6 +82,8 @@ static tree build_java_check_indexed_type PARAMS ((tree, tree)); ...@@ -82,6 +82,8 @@ static tree build_java_check_indexed_type PARAMS ((tree, tree));
static tree java_array_data_offset PARAMS ((tree)); static tree java_array_data_offset PARAMS ((tree));
static tree case_identity PARAMS ((tree, tree)); static tree case_identity PARAMS ((tree, tree));
static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int)); 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]; static tree operand_type[59];
extern struct obstack permanent_obstack; extern struct obstack permanent_obstack;
...@@ -1710,10 +1712,20 @@ build_class_init (clas, expr) ...@@ -1710,10 +1712,20 @@ build_class_init (clas, expr)
TRUE, NULL); TRUE, NULL);
if (ite->init_test_decl == 0) if (ite->init_test_decl == 0)
ite->init_test_decl = build_decl (VAR_DECL, NULL_TREE, {
boolean_type_node); /* Build a declaration and mark it as a flag used to track
/* Tell the check-init code to ignore this decl. */ static class initializations. */
DECL_BIT_INDEX(ite->init_test_decl) = -1; 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, init = build (CALL_EXPR, void_type_node,
build_address_of (soft_initclass_node), build_address_of (soft_initclass_node),
...@@ -2459,16 +2471,31 @@ java_lang_expand_expr (exp, target, tmode, modifier) ...@@ -2459,16 +2471,31 @@ java_lang_expand_expr (exp, target, tmode, modifier)
{ {
tree local; tree local;
tree body = BLOCK_EXPR_BODY (exp); 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 */ pushlevel (2); /* 2 and above */
expand_start_bindings (0); expand_start_bindings (0);
local = BLOCK_EXPR_DECLS (exp); local = BLOCK_EXPR_DECLS (exp);
while (local) while (local)
{ {
tree next = TREE_CHAIN (local); tree next = TREE_CHAIN (local);
found_class_initialization_flag +=
LOCAL_CLASS_INITIALIZATION_FLAG_P (local);
layout_decl (local, 0); layout_decl (local, 0);
expand_decl (pushdecl (local)); expand_decl (pushdecl (local));
local = next; 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. */ /* Avoid deep recursion for long block. */
while (TREE_CODE (body) == COMPOUND_EXPR) while (TREE_CODE (body) == COMPOUND_EXPR)
{ {
...@@ -3335,3 +3362,37 @@ force_evaluation_order (node) ...@@ -3335,3 +3362,37 @@ force_evaluation_order (node)
} }
return 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;
}
...@@ -356,6 +356,14 @@ compiling a class with native methods, and these methods are implemented ...@@ -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 using JNI, then you must use @code{-fjni}. This option causes
@code{gcj} to generate stubs which will invoke the underlying JNI @code{gcj} to generate stubs which will invoke the underlying JNI
methods. 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 @end table
......
...@@ -186,6 +186,10 @@ extern int flag_hash_synchronization; ...@@ -186,6 +186,10 @@ extern int flag_hash_synchronization;
/* When non zero, generate checks for references to NULL. */ /* When non zero, generate checks for references to NULL. */
extern int flag_check_references; 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. */ /* Encoding used for source files. */
extern const char *current_encoding; extern const char *current_encoding;
...@@ -704,6 +708,16 @@ struct lang_identifier ...@@ -704,6 +708,16 @@ struct lang_identifier
class has been initialized in this function, and FALSE otherwise. */ class has been initialized in this function, and FALSE otherwise. */
#define DECL_FUNCTION_INIT_TEST_TABLE(DECL) \ #define DECL_FUNCTION_INIT_TEST_TABLE(DECL) \
(DECL_LANG_SPECIFIC(DECL)->init_test_table) (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> /* The Number of Artificial Parameters (NAP) DECL contains. this$<n>
is excluded, because sometimes created as a parameter before the is excluded, because sometimes created as a parameter before the
function decl exists. */ function decl exists. */
...@@ -815,11 +829,18 @@ struct lang_identifier ...@@ -815,11 +829,18 @@ struct lang_identifier
(((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->local_final) (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->local_final)
/* True if NODE is a local final. */ /* True if NODE is a local final. */
#define LOCAL_FINAL_P(NODE) (DECL_LANG_SPECIFIC (NODE) && LOCAL_FINAL (NODE)) #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)) #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) \ #define CLASS_FINAL_VARIABLE_P(NODE) \
(FIELD_FINAL (NODE) && FIELD_STATIC (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. */ /* Create a DECL_LANG_SPECIFIC if necessary. */
#define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T) \ #define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T) \
if (DECL_LANG_SPECIFIC (T) == NULL) \ if (DECL_LANG_SPECIFIC (T) == NULL) \
...@@ -858,6 +879,8 @@ struct lang_decl ...@@ -858,6 +879,8 @@ struct lang_decl
list of other constructor it calls */ list of other constructor it calls */
struct hash_table init_test_table; struct hash_table init_test_table;
/* Class initialization test variables */ /* 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 tree inner_access; /* The identifier of the access method
used for invocation from inner classes */ used for invocation from inner classes */
int nap; /* Number of artificial parameters */ int nap; /* Number of artificial parameters */
...@@ -888,6 +911,7 @@ struct lang_decl_var ...@@ -888,6 +911,7 @@ struct lang_decl_var
int final_liic : 1; /* Final locally initialized in ctors */ int final_liic : 1; /* Final locally initialized in ctors */
int final_ierr : 1; /* Initialization error already detected */ int final_ierr : 1; /* Initialization error already detected */
int local_final : 1; /* True if the decl is a local final */ 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'. */ /* Macro to access fields in `struct lang_type'. */
...@@ -1061,7 +1085,7 @@ extern void parse_error_context PARAMS ((tree cl, const char *, ...)) ...@@ -1061,7 +1085,7 @@ extern void parse_error_context PARAMS ((tree cl, const char *, ...))
extern tree build_primtype_type_ref PARAMS ((const char *)); extern tree build_primtype_type_ref PARAMS ((const char *));
extern void finish_class PARAMS ((void)); extern void finish_class PARAMS ((void));
extern void java_layout_seen_class_methods 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 tree pushdecl_top_level PARAMS ((tree));
extern int alloc_class_constant PARAMS ((tree)); extern int alloc_class_constant PARAMS ((tree));
...@@ -1129,6 +1153,8 @@ extern tree get_boehm_type_descriptor 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 unsigned long java_hash_hash_tree_node PARAMS ((hash_table_key));
extern bool java_hash_compare_tree_node PARAMS ((hash_table_key, extern bool java_hash_compare_tree_node PARAMS ((hash_table_key,
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 java_check_methods PARAMS ((tree));
extern void init_jcf_parse PARAMS((void)); extern void init_jcf_parse PARAMS((void));
extern void init_src_parse PARAMS((void)); extern void init_src_parse PARAMS((void));
...@@ -1559,6 +1585,10 @@ extern tree *type_map; ...@@ -1559,6 +1585,10 @@ extern tree *type_map;
(inherits_from_p ((TYPE), runtime_exception_type_node) \ (inherits_from_p ((TYPE), runtime_exception_type_node) \
|| inherits_from_p ((TYPE), error_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; \ extern int java_error_count; \
/* Make the current function where this macro is invoked report error /* Make the current function where this macro is invoked report error
......
...@@ -52,3 +52,5 @@ DEFINE_LANG_NAME ("Java") ...@@ -52,3 +52,5 @@ DEFINE_LANG_NAME ("Java")
N_("Warn if .class files are out of date") }, N_("Warn if .class files are out of date") },
{ "-fforce-classes-archive-check", { "-fforce-classes-archive-check",
N_("Always check for non gcj generated classes archives") }, N_("Always check for non gcj generated classes archives") },
{ "-fno-optimize-static-class-initialization",
N_("Never optimize static class initialization code") },
...@@ -146,6 +146,10 @@ int flag_extraneous_semicolon; ...@@ -146,6 +146,10 @@ int flag_extraneous_semicolon;
/* When non zero, always check for a non gcj generated classes archive. */ /* When non zero, always check for a non gcj generated classes archive. */
int flag_force_classes_archive_check; 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. /* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable. STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE ON_VALUE is the value to store in VARIABLE
...@@ -295,6 +299,15 @@ java_decode_option (argc, argv) ...@@ -295,6 +299,15 @@ java_decode_option (argc, argv)
} }
#undef ARG #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') if (p[0] == '-' && p[1] == 'f')
{ {
/* Some kind of -f option. /* Some kind of -f option.
......
...@@ -147,7 +147,9 @@ static tree java_complete_tree PARAMS ((tree)); ...@@ -147,7 +147,9 @@ static tree java_complete_tree PARAMS ((tree));
static tree maybe_generate_pre_expand_clinit PARAMS ((tree)); static tree maybe_generate_pre_expand_clinit PARAMS ((tree));
static int analyze_clinit_body PARAMS ((tree)); static int analyze_clinit_body PARAMS ((tree));
static int maybe_yank_clinit 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_complete_expand_method PARAMS ((tree));
static void java_expand_method_bodies PARAMS ((tree));
static int unresolved_type_p PARAMS ((tree, tree *)); static int unresolved_type_p PARAMS ((tree, tree *));
static void create_jdep_list PARAMS ((struct parser_ctxt *)); static void create_jdep_list PARAMS ((struct parser_ctxt *));
static tree build_expr_block PARAMS ((tree, tree)); static tree build_expr_block PARAMS ((tree, tree));
...@@ -332,6 +334,12 @@ static void create_new_parser_context PARAMS ((int)); ...@@ -332,6 +334,12 @@ static void create_new_parser_context PARAMS ((int));
static void mark_parser_ctxt PARAMS ((void *)); static void mark_parser_ctxt PARAMS ((void *));
static tree maybe_build_class_init_for_field PARAMS ((tree, tree)); 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. */ /* Number of error found so far. */
int java_error_count; int java_error_count;
/* Number of warning found so far. */ /* Number of warning found so far. */
...@@ -7513,12 +7521,17 @@ java_complete_expand_methods (class_decl) ...@@ -7513,12 +7521,17 @@ java_complete_expand_methods (class_decl)
/* First, do the ordinary methods. */ /* First, do the ordinary methods. */
for (decl = first_decl; decl; decl = TREE_CHAIN (decl)) 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 /* Skip abstract or native methods -- but do handle native
methods when generating JNI stubs. */ methods when generating JNI stubs. */
if (METHOD_ABSTRACT (decl) if (METHOD_ABSTRACT (decl) || (! flag_jni && METHOD_NATIVE (decl)))
|| (! flag_jni && METHOD_NATIVE (decl)) {
|| DECL_CONSTRUCTOR_P (decl) || DECL_CLINIT_P (decl)) DECL_FUNCTION_BODY (decl) = NULL_TREE;
continue; continue;
}
if (METHOD_NATIVE (decl)) if (METHOD_NATIVE (decl))
{ {
...@@ -7751,6 +7764,40 @@ maybe_yank_clinit (mdecl) ...@@ -7751,6 +7764,40 @@ maybe_yank_clinit (mdecl)
return 1; 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. */ /* Complete and expand a method. */
...@@ -7758,7 +7805,7 @@ static void ...@@ -7758,7 +7805,7 @@ static void
java_complete_expand_method (mdecl) java_complete_expand_method (mdecl)
tree mdecl; tree mdecl;
{ {
int yank_clinit = 0; tree fbody, block_body, exception_copy;
current_function_decl = mdecl; current_function_decl = mdecl;
/* Fix constructors before expanding them */ /* Fix constructors before expanding them */
...@@ -7766,103 +7813,131 @@ java_complete_expand_method (mdecl) ...@@ -7766,103 +7813,131 @@ java_complete_expand_method (mdecl)
fix_constructors (mdecl); fix_constructors (mdecl);
/* Expand functions that have a body */ /* Expand functions that have a body */
if (DECL_FUNCTION_BODY (mdecl)) if (!DECL_FUNCTION_BODY (mdecl))
{ return;
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 (block_body != NULL_TREE) fbody = DECL_FUNCTION_BODY (mdecl);
{ block_body = BLOCK_EXPR_BODY (fbody);
block_body = java_complete_tree (block_body); exception_copy = NULL_TREE;
if (! flag_emit_xref && ! METHOD_NATIVE (mdecl)) current_function_decl = mdecl;
check_for_initialization (block_body);
ctxp->explicit_constructor_p = 0;
}
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 /* Install the current this */
have an error_mark_node here. */ current_this = (!METHOD_STATIC (mdecl) ?
if (block_body != error_mark_node BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE);
&& (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);
/* Check wether we could just get rid of clinit, now the picture /* Purge the `throws' list of unchecked exceptions. If we're doing
is complete. */ xref, save a copy of the list and re-install it later. */
if (!(yank_clinit = maybe_yank_clinit (mdecl))) if (flag_emit_xref)
complete_start_java_method (mdecl); 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 /* Before we check initialization, attached all class initialization
expansion */ variable to the block_body */
if (!java_error_count && !yank_clinit) hash_traverse (&DECL_FUNCTION_INIT_TEST_TABLE (mdecl),
source_end_java_method (); attach_init_test_initialization_flags, block_body);
else
if (! flag_emit_xref && ! METHOD_NATIVE (mdecl))
{ {
if (java_error_count) unsigned int state = check_for_initialization (block_body);
pushdecl_force_head (DECL_ARGUMENTS (mdecl));
poplevel (1, 0, 1); /* 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 */ /* See if we can get rid of <clinit> if MDECL happens to be <clinit> */
POP_EXCEPTIONS(); maybe_yank_clinit (mdecl);
if (currently_caught_type_list)
abort ();
if (flag_emit_xref) /* Pop the current level, with special measures if we found errors. */
DECL_FUNCTION_THROWS (mdecl) = exception_copy; 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 () ...@@ -8783,7 +8858,10 @@ java_expand_classes ()
if (flag_emit_xref) if (flag_emit_xref)
expand_xref (current_class); expand_xref (current_class);
else if (! flag_syntax_only) else if (! flag_syntax_only)
finish_class (); {
java_expand_method_bodies (current_class);
finish_class ();
}
} }
} }
} }
...@@ -8963,7 +9041,10 @@ resolve_expression_name (id, orig) ...@@ -8963,7 +9041,10 @@ resolve_expression_name (id, orig)
static_ref_err (id, DECL_NAME (decl), current_class); static_ref_err (id, DECL_NAME (decl), current_class);
return error_mark_node; 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 */ /* Otherwise build what it takes to access the field */
...@@ -10438,6 +10519,30 @@ patch_invoke (patch, method, args) ...@@ -10438,6 +10519,30 @@ patch_invoke (patch, method, args)
TREE_SIDE_EFFECTS (patch) = 1; 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; return patch;
} }
...@@ -15853,3 +15958,111 @@ init_src_parse () ...@@ -15853,3 +15958,111 @@ init_src_parse ()
/* Register roots with the garbage collector. */ /* Register roots with the garbage collector. */
ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree)); ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree));
} }
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment