This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Java: convert byte compiler to functions-as-trees
- From: Andrew Haley <aph at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 23 Jul 2003 16:28:51 +0100
- Subject: [tree-ssa] Java: convert byte compiler to functions-as-trees
Once we do this, we can beging to do tree optimizations in the byte
compiler. Such optimizations include inlining a bytecode method in
a source compiled method.
This is done by directly generating tree nodes while processing
bytecode input, rather than calling expand_foo() for each statement.
Mostly the changes are pretty obvious, but exception handling is done
in a totally different way. Unlike the source compiler, the bytecode
compiler generates BIND_EXPRs directly, which somewhat simplifies the
handling of debug information.
This isn't the end of the story, because there is still a fair bit of
cruft that I haven't removed.
As I mentioned earlier, this patch does cause a few failures in the
tree optimizers. I don't know where the bug lies; maybe in the front
end, maybe in the tree optimizers.
Andrew.
2003-07-23 Andrew Haley <aph@redhat.com>
* java-tree.h: (add_stmt_to_compound): New function.
(java_add_stmt): New function.
(java_add_local_var): New function.
(get_stmts): New function.
* java-gimplify.c (java_gimplify_block): Allow for null body.
* except.c (link_handler): Set h->stmt.
(expand_start_java_handler): Build a TRY_CATCH_EXPR for this
range; don't expand_eh_region_start.
(expand_end_java_handler): Rewrite.
* java-except.h (stmt): New field.
* expr.c (flush_quick_stack): Replace expand_assignment with
java_add_stmt.
(java_stack_dup): Replace emit_move_insn with java_add_stmt.
(build_java_athrow): Replace expand_expr_stmt with java_add_stmt.
(build_java_jsr): Replace emit_jump with java_add_stmt (build (GOTO_EXPR))
(build_java_ret): Replace expand_computed_goto with
java_add_stmt (build (GOTO_EXPR))
(expand_java_arraystore): Replace expand_assignment with
java_add_stmt.
(expand_java_return): Replace expand_return with
java_add_stmt (build (RETURN_EXPR))
(expand_load_internal): Remove layout_decl, DECL_REGISTER,
expand_decl, and expand_decl_init. Instead, add the local
variable and a MODIFY_EXPR to the current tree.
(expand_iinc): Replace expand_assignment with
java_add_stmt.
(expand_compare): Replace expand_cond with
java_add_stmt(build (COND_EXPR))
(expand_java_goto): Replace expand_goto with
java_add_stmt (build (GOTO_EXPR))
(expand_invoke): Replace expand_expr_stmt with java_add_stmt.
(build_jni_stub): Generate a BIND_EXPR to hold the block we've
created. Don't distinguish between source and byte compiler.
(expand_java_field_op): Replace expand_assignment with
java_add_stmt.
(java_expand_expr): Abort. No-one should call this function any
more.
(expand_byte_code): Replace expand_label with
java_add_stmt (build (LABEL_EXPR))
(process_jvm_instruction): Replace build (JAVA_EXC_OBJ_EXPR) with
build_exception_object_ref. Replace expand_assignment with
java_add_stmt.
* except.c (link_handler): Null stmt field.
(expand_start_java_handler): Don't expand_eh_region_start.
Instead, generate a TRY_CATCH_EXPR and insert it into the tree
we're building.
(expand_end_java_handler): Don't expand_start_all_catch. Instead,
build a TRY_FINALLY_EXPR and wrap the catch block with it.
Don't expand_end_all_catch.
* decl.c (push_jvm_slot): Call pushdecl().
(find_local_variable): Give symbolic names to unnamed local
variables.
(struct binding_level: stmts): New field.
(poplevel): If any statements have been generated at this level,
create a BIND_EXPR to hold them and copy the variables to it. If
we are at the outermost level, save this BIND_EXPR in the
DECL_SAVED_TREE of this function.
(maybe_pushlevels): Don't expand_start_bindings.
(maybe_poplevels): Don't expand_end_bindings.
(complete_start_java_method): Reorganize static initialization and
synchronization logic for source compiler. Remove pushlevel and
expand_start_bindings for byte compiler.
(end_java_method): Don't expand_end_bindings. Add static
initialization and synchronization logic for byte compiler.
Set cfun->x_whole_function_mode_p.
Call gimplify_function_tree and optimize_function_tree and
expand_expr_stmt.
(add_stmt_to_compound): New.
(java_add_stmt): New.
(java_add_local_var): New.
(get_stmts): New.
* parse.y (add_stmt_to_compound): Remove.
* jcf-parse.c (parse_class_file): Don't call expand_expr_stmt for
a native method -- we'll do that later.
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.128.2.16
diff -c -2 -p -r1.128.2.16 decl.c
*** decl.c 21 Jun 2003 18:20:59 -0000 1.128.2.16
--- decl.c 23 Jul 2003 15:14:16 -0000
*************** The Free Software Foundation is independ
*** 46,49 ****
--- 46,50 ----
#include "timevar.h"
#include "tree-inline.h"
+ #include "tree-dump.h"
#if defined (DEBUG_JAVA_BINDING_LEVELS)
*************** void
*** 95,99 ****
indent (void)
{
! register unsigned i;
for (i = 0; i < binding_depth*2; i++)
--- 96,100 ----
indent (void)
{
! register int i;
for (i = 0; i < binding_depth*2; i++)
*************** push_jvm_slot (int index, tree decl)
*** 142,145 ****
--- 143,149 ----
DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index);
TREE_VEC_ELT (decl_map, index) = decl;
+
+ if (TREE_CODE (decl) != PARM_DECL)
+ pushdecl (decl);
return decl;
}
*************** find_local_variable (int index, tree typ
*** 204,212 ****
while (decl != NULL_TREE)
{
/* Variables created in give_name_to_locals() have a name and have
a specified scope, so we can handle them specifically. We want
to use the specific decls created for those so they are assigned
the right variables in the debugging information. */
! if (DECL_NAME (decl) != NULL_TREE)
{
/* This is a variable we have a name for, so it has a scope
--- 208,221 ----
while (decl != NULL_TREE)
{
+ bool has_name = false;
+ tree name = DECL_NAME (decl);
+ if (name && IDENTIFIER_POINTER (name))
+ has_name = IDENTIFIER_POINTER (name)[0] != '#';
+
/* Variables created in give_name_to_locals() have a name and have
a specified scope, so we can handle them specifically. We want
to use the specific decls created for those so they are assigned
the right variables in the debugging information. */
! if (has_name)
{
/* This is a variable we have a name for, so it has a scope
*************** find_local_variable (int index, tree typ
*** 233,238 ****
return best;
! /* If we don't find a match, create one with the type passed in. */
! return push_jvm_slot (index, build_decl (VAR_DECL, NULL_TREE, type));
}
--- 242,259 ----
return best;
! /* If we don't find a match, create one with the type passed in.
! Ths name of the variable is #n#m, which n is the variable index
! in the local variable area and m is a dummy identifier for
! uniqueness -- multiple variables may share the same local
! variable index. */
! {
! char buf[64];
! tree name;
! static int uniq;
! sprintf (buf, "#%d#%d", index, uniq++);
! name = get_identifier (buf);
!
! return push_jvm_slot (index, build_decl (VAR_DECL, name, type));
! }
}
*************** struct binding_level
*** 277,280 ****
--- 298,304 ----
int start_pc;
+ /* The statements in this binding level. */
+ tree stmts;
+
#if defined(DEBUG_JAVA_BINDING_LEVELS)
/* Binding depth at which this level began. */
*************** static struct binding_level *global_bind
*** 307,311 ****
static const struct binding_level clear_binding_level
= {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
! NULL_BINDING_LEVEL, LARGEST_PC, 0};
#if 0
--- 331,339 ----
static const struct binding_level clear_binding_level
= {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
! NULL_BINDING_LEVEL, LARGEST_PC, 0, NULL,
! #if defined(DEBUG_JAVA_BINDING_LEVELS)
! 0,
! #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
! };
#if 0
*************** pushlevel (int unused ATTRIBUTE_UNUSED)
*** 1202,1206 ****
newlevel->binding_depth = binding_depth;
indent ();
! fprintf (stderr, "push %s level 0x%08x pc %d\n",
(is_class_level) ? "class" : "block", newlevel, current_pc);
is_class_level = 0;
--- 1230,1234 ----
newlevel->binding_depth = binding_depth;
indent ();
! fprintf (stderr, "push %s level %p pc %d\n",
(is_class_level) ? "class" : "block", newlevel, current_pc);
is_class_level = 0;
*************** poplevel (int keep, int reverse, int fun
*** 1234,1237 ****
--- 1262,1266 ----
tree block = 0;
tree decl;
+ tree bind = 0;
int block_previously_created;
*************** poplevel (int keep, int reverse, int fun
*** 1240,1248 ****
indent ();
if (current_binding_level->end_pc != LARGEST_PC)
! fprintf (stderr, "pop %s level 0x%08x pc %d (end pc %d)\n",
(is_class_level) ? "class" : "block", current_binding_level, current_pc,
current_binding_level->end_pc);
else
! fprintf (stderr, "pop %s level 0x%08x pc %d\n",
(is_class_level) ? "class" : "block", current_binding_level, current_pc);
#if 0
--- 1269,1277 ----
indent ();
if (current_binding_level->end_pc != LARGEST_PC)
! fprintf (stderr, "pop %s level %p pc %d (end pc %d)\n",
(is_class_level) ? "class" : "block", current_binding_level, current_pc,
current_binding_level->end_pc);
else
! fprintf (stderr, "pop %s level %p pc %d\n",
(is_class_level) ? "class" : "block", current_binding_level, current_pc);
#if 0
*************** poplevel (int keep, int reverse, int fun
*** 1301,1310 ****
block = current_binding_level->this_block;
else if (keep || functionbody)
! block = make_node (BLOCK);
if (block != 0)
{
! BLOCK_VARS (block) = decls;
BLOCK_SUBBLOCKS (block) = subblocks;
! }
/* In each subblock, record that this is its superior. */
--- 1330,1382 ----
block = current_binding_level->this_block;
else if (keep || functionbody)
! {
! block = make_node (BLOCK);
! TREE_TYPE (block) = void_type_node;
! }
!
if (block != 0)
{
! /* If any statements have been generated at this level, create a
! BIND_EXPR to hold them and copy the variables to it. This
! only applies to the bytecode compiler. */
! if (current_binding_level->stmts)
! {
! tree decl = decls;
! tree *var = &BLOCK_VARS (block);
!
! /* Copy decls from names list, ignoring labels. */
! while (decl)
! {
! tree next = TREE_CHAIN (decl);
! if (TREE_CODE (decl) != LABEL_DECL)
! {
! *var = decl;
! var = &TREE_CHAIN (decl);
! }
! decl = next;
! }
! *var = NULL;
!
! bind = build (BIND_EXPR, TREE_TYPE (block), BLOCK_VARS (block),
! BLOCK_EXPR_BODY (block), block);
!
! BIND_EXPR_BODY (bind) = current_binding_level->stmts;
!
! if (BIND_EXPR_BODY (bind)
! && TREE_SIDE_EFFECTS (BIND_EXPR_BODY (bind)))
! TREE_SIDE_EFFECTS (bind) = 1;
!
! /* FIXME: gimplifier brain damage. */
! if (BIND_EXPR_BODY (bind) == NULL)
! BIND_EXPR_BODY (bind) = build_java_empty_stmt ();
!
! current_binding_level->stmts = NULL;
! }
! else
! {
! BLOCK_VARS (block) = decls;
! }
BLOCK_SUBBLOCKS (block) = subblocks;
! }
/* In each subblock, record that this is its superior. */
*************** poplevel (int keep, int reverse, int fun
*** 1392,1396 ****
/* Dispose of the block that we just made inside some higher level. */
if (functionbody)
! DECL_INITIAL (current_function_decl) = block;
else if (block)
{
--- 1464,1471 ----
/* Dispose of the block that we just made inside some higher level. */
if (functionbody)
! {
! DECL_INITIAL (current_function_decl) = block;
! DECL_SAVED_TREE (current_function_decl) = bind;
! }
else if (block)
{
*************** poplevel (int keep, int reverse, int fun
*** 1408,1426 ****
= chainon (current_binding_level->blocks, subblocks);
! /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this
! binding contour so that they point to the appropriate construct, i.e.
! either to the current FUNCTION_DECL node, or else to the BLOCK node
! we just constructed.
!
! Note that for tagged types whose scope is just the formal parameter
! list for some function type specification, we can't properly set
! their TYPE_CONTEXTs here, because we don't have a pointer to the
! appropriate FUNCTION_TYPE node readily available to us. For those
! cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set
! in `grokdeclarator' as soon as we have created the FUNCTION_TYPE
! node which will represent the "scope" for these "parameter list local"
! tagged types.
! */
!
if (block)
TREE_USED (block) = 1;
--- 1483,1489 ----
= chainon (current_binding_level->blocks, subblocks);
! if (bind)
! java_add_stmt (bind);
!
if (block)
TREE_USED (block) = 1;
*************** maybe_pushlevels (int pc)
*** 1456,1460 ****
pushlevel (1);
- expand_start_bindings (0);
current_binding_level->end_pc = end_pc;
--- 1519,1522 ----
*************** maybe_poplevels (int pc)
*** 1479,1483 ****
while (current_binding_level->end_pc <= pc)
{
- expand_end_bindings (getdecls (), 1, 0);
maybe_end_try (current_binding_level->start_pc, pc);
poplevel (1, 0, 0);
--- 1541,1544 ----
*************** force_poplevels (int start_pc)
*** 1500,1504 ****
"In %s: overlapped variable and exception ranges at %d",
current_binding_level->start_pc);
- expand_end_bindings (getdecls (), 1, 0);
poplevel (1, 0, 0);
}
--- 1561,1564 ----
*************** complete_start_java_method (tree fndecl)
*** 1675,1700 ****
}
- #if 0
- /* If this fcn was already referenced via a block-scope `extern' decl (or
- an implicit decl), propagate certain information about the usage. */
- if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl)))
- TREE_ADDRESSABLE (current_function_decl) = 1;
-
- #endif
-
- if (METHOD_STATIC (fndecl) && ! METHOD_PRIVATE (fndecl)
- && ! flag_emit_class_files
- && ! DECL_CLINIT_P (fndecl)
- && ! CLASS_INTERFACE (TYPE_NAME (current_class)))
- {
- tree clas = DECL_CONTEXT (fndecl);
- tree 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;
- expand_expr_stmt (init);
- }
-
/* Push local variables. Function compiled from source code are
using a different local variables management, and for them,
--- 1735,1738 ----
*************** complete_start_java_method (tree fndecl)
*** 1703,1739 ****
{
pushlevel (2);
- if (! flag_emit_class_files)
- expand_start_bindings (1);
}
! if (METHOD_SYNCHRONIZED (fndecl) && ! flag_emit_class_files)
{
! /* Wrap function body with a monitorenter plus monitorexit cleanup. */
! tree enter, exit, lock;
! if (METHOD_STATIC (fndecl))
! lock = build_class_ref (DECL_CONTEXT (fndecl));
! else
! lock = DECL_ARGUMENTS (fndecl);
! BUILD_MONITOR_ENTER (enter, lock);
! BUILD_MONITOR_EXIT (exit, lock);
! if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl)))
! {
! expand_expr_stmt (enter);
! expand_decl_cleanup (NULL_TREE, exit);
! }
! else
{
tree function_body = DECL_FUNCTION_BODY (fndecl);
tree body = BLOCK_EXPR_BODY (function_body);
! lock = build (COMPOUND_EXPR, void_type_node,
! enter,
! build (TRY_FINALLY_EXPR, void_type_node, body, exit));
! TREE_SIDE_EFFECTS (lock) = 1;
! BLOCK_EXPR_BODY (function_body) = lock;
!
/* If we previously saved the tree for inlining,
update that too. */
! if (DECL_SAVED_TREE (fndecl) != NULL_TREE)
! DECL_SAVED_TREE (fndecl) = lock;
}
}
--- 1741,1799 ----
{
pushlevel (2);
}
! if (flag_emit_class_files)
! return;
!
! if (CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl)))
{
! tree *saved_tree = &DECL_SAVED_TREE (fndecl);
! if (METHOD_STATIC (fndecl)
! && ! flag_emit_class_files
! && ! DECL_CLINIT_P (fndecl)
! && ! CLASS_INTERFACE (TYPE_NAME (current_class)))
{
tree function_body = DECL_FUNCTION_BODY (fndecl);
tree body = BLOCK_EXPR_BODY (function_body);
! tree clas = DECL_CONTEXT (fndecl);
! tree 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;
! init = build (COMPOUND_EXPR, void_type_node, init, body);
! TREE_SIDE_EFFECTS (init) = 1;
! BLOCK_EXPR_BODY (function_body) = init;
!
/* If we previously saved the tree for inlining,
update that too. */
! if (*saved_tree != NULL_TREE)
! *saved_tree = init;
! }
!
! if (METHOD_SYNCHRONIZED (fndecl))
! {
! /* Wrap function body with a monitorenter plus monitorexit cleanup. */
! tree enter, exit, lock;
! if (METHOD_STATIC (fndecl))
! lock = build_class_ref (DECL_CONTEXT (fndecl));
! else
! lock = DECL_ARGUMENTS (fndecl);
! BUILD_MONITOR_ENTER (enter, lock);
! BUILD_MONITOR_EXIT (exit, lock);
! {
! tree function_body = DECL_FUNCTION_BODY (fndecl);
! tree body = BLOCK_EXPR_BODY (function_body);
! lock = build (COMPOUND_EXPR, void_type_node,
! enter,
! build (TRY_FINALLY_EXPR, void_type_node, body, exit));
! TREE_SIDE_EFFECTS (lock) = 1;
! BLOCK_EXPR_BODY (function_body) = lock;
!
! /* If we previously saved the tree for inlining,
! update that too. */
! if (*saved_tree != NULL_TREE)
! *saved_tree = lock;
! }
}
}
*************** end_java_method (void)
*** 1804,1808 ****
tree fndecl = current_function_decl;
! expand_end_bindings (getdecls (), 1, 0);
/* pop out of function */
poplevel (1, 1, 0);
--- 1864,1906 ----
tree fndecl = current_function_decl;
! if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl))
! && ! flag_emit_class_files)
! {
! if (METHOD_SYNCHRONIZED (fndecl))
! {
! /* Wrap function body with a monitorenter plus monitorexit cleanup. */
! tree enter, exit, lock;
! if (METHOD_STATIC (fndecl))
! lock = build_class_ref (DECL_CONTEXT (fndecl));
! else
! lock = DECL_ARGUMENTS (fndecl);
! BUILD_MONITOR_ENTER (enter, lock);
! BUILD_MONITOR_EXIT (exit, lock);
!
! {
! tree lock = build (COMPOUND_EXPR, void_type_node,
! enter,
! build (TRY_FINALLY_EXPR,
! void_type_node, *get_stmts (), exit));
! TREE_SIDE_EFFECTS (lock) = 1;
! *get_stmts () = lock;
! }
! }
!
! if (METHOD_STATIC (fndecl) && ! METHOD_PRIVATE (fndecl)
! && ! DECL_CLINIT_P (fndecl)
! && ! CLASS_INTERFACE (TYPE_NAME (current_class)))
! {
! tree *stmts = get_stmts ();
! tree clas = DECL_CONTEXT (fndecl);
! tree 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;
! *stmts = build (COMPOUND_EXPR, void_type_node, init, *stmts);
! }
! }
!
/* pop out of function */
poplevel (1, 1, 0);
*************** end_java_method (void)
*** 1813,1816 ****
--- 1911,1932 ----
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+ cfun->x_whole_function_mode_p = 1;
+
+ gimplify_function_tree (fndecl);
+ dump_function (TDI_gimple, fndecl);
+ if (optimize > 0 && !flag_disable_tree_ssa)
+ optimize_function_tree (fndecl);
+
+ if (flag_inline_trees)
+ {
+ timevar_push (TV_INTEGRATION);
+ optimize_inline_calls (fndecl);
+ timevar_pop (TV_INTEGRATION);
+ dump_function (TDI_inlined, fndecl);
+ }
+
+ /* Generate function's code. */
+ expand_expr_stmt (DECL_SAVED_TREE (fndecl));
+
/* Generate rtl for function exit. */
expand_function_end (input_filename, input_line, 0);
*************** end_java_method (void)
*** 1822,1825 ****
--- 1938,1954 ----
}
+ /* Dump FUNCTION_DECL FN as tree dump PHASE. */
+
+ void java_optimize_inline (tree fndecl)
+ {
+ if (flag_inline_trees)
+ {
+ timevar_push (TV_INTEGRATION);
+ optimize_inline_calls (fndecl);
+ timevar_pop (TV_INTEGRATION);
+ dump_function (TDI_inlined, fndecl);
+ }
+ }
+
/* We pessimistically marked all methods and fields external until we
knew what set of classes we were planning to compile. Now mark those
*************** java_mark_class_local (tree class)
*** 1850,1853 ****
--- 1979,2038 ----
java_mark_decl_local (t);
}
+
+ /* Add a statement to a compound_expr. */
+
+ tree
+ add_stmt_to_compound (existing, type, stmt)
+ tree existing, type, stmt;
+ {
+ if (!stmt)
+ return existing;
+ else if (existing)
+ {
+ tree expr = build (COMPOUND_EXPR, type, existing, stmt);
+ TREE_SIDE_EFFECTS (expr)
+ = TREE_SIDE_EFFECTS (existing) | TREE_SIDE_EFFECTS (stmt);
+ return expr;
+ }
+ else
+ return stmt;
+ }
+
+ /* Add a statement to the compound_expr currently being
+ constructed. */
+
+ tree
+ java_add_stmt (stmt)
+ tree stmt;
+ {
+ if (input_filename)
+ annotate_with_file_line (stmt, input_filename, input_line);
+
+ return current_binding_level->stmts
+ = add_stmt_to_compound (current_binding_level->stmts,
+ TREE_TYPE (stmt), stmt);
+ }
+
+ /* Add a variable to the current scope. */
+
+ tree
+ java_add_local_var (tree decl)
+ {
+ tree *vars = ¤t_binding_level->names;
+ tree next = *vars;
+ TREE_CHAIN (decl) = next;
+ *vars = decl;
+ return decl;
+ }
+
+ /* Return a pointer to the compound_expr currently being
+ constructed. */
+
+ tree *
+ get_stmts (void)
+ {
+ return ¤t_binding_level->stmts;
+ }
+
#include "gt-java-decl.h"
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/except.c,v
retrieving revision 1.27.2.7
diff -c -2 -p -r1.27.2.7 except.c
*** except.c 9 Feb 2003 21:21:58 -0000 1.27.2.7
--- except.c 23 Jul 2003 15:14:16 -0000
*************** link_handler (struct eh_range *range, st
*** 171,174 ****
--- 171,175 ----
h->next_sibling = NULL;
h->expanded = 0;
+ h->stmt = NULL;
/* Restart both from the top to avoid having to make this
function smart about reentrancy. */
*************** add_handler (int start_pc, int end_pc, t
*** 288,291 ****
--- 289,293 ----
h->next_sibling = NULL;
h->expanded = 0;
+ h->stmt = NULL;
if (prev == NULL)
*************** add_handler (int start_pc, int end_pc, t
*** 295,299 ****
}
-
/* if there are any handlers for this range, issue start of region */
static void
--- 297,300 ----
*************** expand_start_java_handler (struct eh_ran
*** 305,310 ****
current_pc, range->end_pc);
#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
range->expanded = 1;
- expand_eh_region_start ();
}
--- 306,317 ----
current_pc, range->end_pc);
#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
+ {
+ tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL);
+ TREE_SIDE_EFFECTS (new) = 1;
+ java_add_stmt (build_java_empty_stmt ());
+ range->stmt = java_add_stmt (new);
+ }
+
range->expanded = 1;
}
*************** expand_end_java_handler (struct eh_range
*** 357,362 ****
{
tree handler = range->handlers;
! force_poplevels (range->start_pc);
! expand_start_all_catch ();
for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
{
--- 364,370 ----
{
tree handler = range->handlers;
! tree compound = NULL;
!
! force_poplevels (range->start_pc);
for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
{
*************** expand_end_java_handler (struct eh_range
*** 368,379 ****
gcc-style finally clause. */
tree type = TREE_PURPOSE (handler);
if (type == NULL)
type = throwable_type_node;
! expand_start_catch (type);
! expand_goto (TREE_VALUE (handler));
! expand_end_catch ();
}
- expand_end_all_catch ();
#if defined(DEBUG_JAVA_BINDING_LEVELS)
indent ();
--- 376,425 ----
gcc-style finally clause. */
tree type = TREE_PURPOSE (handler);
+
if (type == NULL)
type = throwable_type_node;
! if (compound)
! {
! /* If we already have a COMPOUND there is more than one
! catch handler for this try block. Wrap the
! TRY_CATCH_EXPR in operand 1 of COMPOUND with another
! TRY_CATCH_EXPR. */
! tree inner_try_expr = TREE_OPERAND (compound, 1);
! tree catch_expr
! = build (CATCH_EXPR, void_type_node, type,
! build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
! tree try_expr
! = build (TRY_CATCH_EXPR, void_type_node,
! inner_try_expr, catch_expr);
! TREE_OPERAND (compound, 1) = try_expr;
! }
! else
! {
! tree *stmts = get_stmts ();
! compound = range->stmt;
! tree outer = TREE_OPERAND (compound, 0);
! tree try_expr = TREE_OPERAND (compound, 1);
! /* On the left of COMPOUND is the expresion to be evaluated
! before the try handler is entered; on the right is a
! TRY_FINALLY_EXPR with no operands as yet. In the current
! statement list is an expression that we're going to move
! inside the try handler. We'll create a new COMPOUND_EXPR
! with the outer context on the left and the TRY_FINALLY_EXPR
! on the right, then nullify both operands of COMPOUND, which
! becomes the final expression in OUTER. This new compound
! expression replaces the current statement list. */
! TREE_OPERAND (try_expr, 0) = *stmts;
! TREE_OPERAND (try_expr, 1)
! = build (CATCH_EXPR, void_type_node, type,
! build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
! TREE_SIDE_EFFECTS (try_expr) = 1;
! TREE_OPERAND (compound, 0) = build_java_empty_stmt ();
! TREE_OPERAND (compound, 1) = build_java_empty_stmt ();
! compound
! = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr);
! *stmts = compound;
! }
}
#if defined(DEBUG_JAVA_BINDING_LEVELS)
indent ();
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.147.2.14
diff -c -2 -p -r1.147.2.14 expr.c
*** expr.c 21 Jun 2003 18:21:00 -0000 1.147.2.14
--- expr.c 23 Jul 2003 15:14:17 -0000
*************** flush_quick_stack (void)
*** 234,238 ****
decl = find_stack_slot (stack_index, type);
if (decl != node)
! expand_assignment (decl, node, 0, 0);
stack_index += 1 + TYPE_IS_WIDE (type);
}
--- 234,238 ----
decl = find_stack_slot (stack_index, type);
if (decl != node)
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (node), decl, node));
stack_index += 1 + TYPE_IS_WIDE (type);
}
*************** java_stack_dup (int size, int offset)
*** 552,556 ****
tree src_decl = find_stack_slot (src_index, type);
tree dst_decl = find_stack_slot (dst_index, type);
! emit_move_insn (DECL_RTL (dst_decl), DECL_RTL (src_decl));
stack_type_map[dst_index] = type;
}
--- 552,557 ----
tree src_decl = find_stack_slot (src_index, type);
tree dst_decl = find_stack_slot (dst_index, type);
!
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (dst_decl), dst_decl, src_decl));
stack_type_map[dst_index] = type;
}
*************** build_java_athrow (tree node)
*** 572,576 ****
NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
! expand_expr_stmt (call);
java_stack_pop (stack_pointer);
}
--- 573,577 ----
NULL_TREE);
TREE_SIDE_EFFECTS (call) = 1;
! java_add_stmt (call);
java_stack_pop (stack_pointer);
}
*************** build_java_jsr (int target_pc, int retur
*** 586,591 ****
push_value (ret_label);
flush_quick_stack ();
! emit_jump (label_rtx (where));
! expand_label (ret);
if (instruction_bits [return_pc] & BCODE_VERIFIED)
load_type_state (ret);
--- 587,592 ----
push_value (ret_label);
flush_quick_stack ();
! java_add_stmt (build (GOTO_EXPR, void_type_node, where));
! java_add_stmt (build (LABEL_EXPR, void_type_node, ret));
if (instruction_bits [return_pc] & BCODE_VERIFIED)
load_type_state (ret);
*************** static void
*** 595,599 ****
build_java_ret (tree location)
{
! expand_computed_goto (location);
}
--- 596,600 ----
build_java_ret (tree location)
{
! java_add_stmt (build (GOTO_EXPR, void_type_node, location));
}
*************** expand_java_arraystore (tree rhs_type_no
*** 982,992 ****
{
tree check = build_java_arraystore_check (array, rhs_node);
! expand_expr_stmt (check);
}
!
! expand_assignment (build_java_arrayaccess (array,
! rhs_type_node,
! index),
! rhs_node, 0, 0);
}
--- 983,991 ----
{
tree check = build_java_arraystore_check (array, rhs_node);
! java_add_stmt (check);
}
!
! array = build_java_arrayaccess (array, rhs_type_node, index);
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (array), array, rhs_node));
}
*************** expand_java_return (tree type)
*** 1081,1085 ****
{
if (type == void_type_node)
! expand_null_return ();
else
{
--- 1080,1084 ----
{
if (type == void_type_node)
! java_add_stmt (build (RETURN_EXPR, void_type_node, NULL));
else
{
*************** expand_java_return (tree type)
*** 1098,1102 ****
TREE_SIDE_EFFECTS (retval) = 1;
! expand_return (retval);
}
}
--- 1097,1101 ----
TREE_SIDE_EFFECTS (retval) = 1;
! java_add_stmt (build (RETURN_EXPR, TREE_TYPE (retval), retval));
}
}
*************** expand_load_internal (int index, tree ty
*** 1116,1125 ****
copy = build_decl (VAR_DECL, NULL_TREE, type);
DECL_CONTEXT (copy) = current_function_decl;
- layout_decl (copy, 0);
- DECL_REGISTER (copy) = 1;
- expand_decl (copy);
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (copy);
! DECL_INITIAL (copy) = var;
! expand_decl_init (copy);
push_value (copy);
}
--- 1115,1123 ----
copy = build_decl (VAR_DECL, NULL_TREE, type);
DECL_CONTEXT (copy) = current_function_decl;
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (copy);
!
! java_add_local_var (copy);
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (var), copy, var));
!
push_value (copy);
}
*************** expand_iinc (unsigned int local_var_inde
*** 1276,1280 ****
constant_value = build_int_2 (ival, ival < 0 ? -1 : 0);
res = fold (build (PLUS_EXPR, int_type_node, local_var, constant_value));
! expand_assignment (local_var, res, 0, 0);
}
--- 1274,1278 ----
constant_value = build_int_2 (ival, ival < 0 ? -1 : 0);
res = fold (build (PLUS_EXPR, int_type_node, local_var, constant_value));
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
}
*************** expand_compare (enum tree_code condition
*** 1585,1591 ****
tree target = lookup_label (target_pc);
tree cond = fold (build (condition, boolean_type_node, value1, value2));
! expand_start_cond (java_truthvalue_conversion (cond), 0);
! expand_goto (target);
! expand_end_cond ();
}
--- 1583,1590 ----
tree target = lookup_label (target_pc);
tree cond = fold (build (condition, boolean_type_node, value1, value2));
! java_add_stmt
! (build (COND_EXPR, void_type_node, java_truthvalue_conversion (cond),
! build (GOTO_EXPR, void_type_node, target),
! build_java_empty_stmt ()));
}
*************** expand_java_goto (int target_pc)
*** 1621,1625 ****
tree target_label = lookup_label (target_pc);
flush_quick_stack ();
! expand_goto (target_label);
}
--- 1620,1624 ----
tree target_label = lookup_label (target_pc);
flush_quick_stack ();
! java_add_stmt (build (GOTO_EXPR, void_type_node, target_label));
}
*************** expand_invoke (int opcode, int method_re
*** 2065,2069 ****
func = build_invokeinterface (dtable, method);
}
! func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
--- 2064,2072 ----
func = build_invokeinterface (dtable, method);
}
!
! if (TREE_CODE (func) == ADDR_EXPR)
! TREE_TYPE (func) = build_pointer_type (method_type);
! else
! func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE);
*************** expand_invoke (int opcode, int method_re
*** 2078,2082 ****
if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
! expand_expr_stmt (call);
else
{
--- 2081,2085 ----
if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE)
! java_add_stmt (call);
else
{
*************** build_jni_stub (tree method)
*** 2097,2100 ****
--- 2100,2104 ----
tree method_args, res_type;
tree meth_var;
+ tree bind;
int args_size = 0;
*************** build_jni_stub (tree method)
*** 2130,2136 ****
TREE_USED (meth_var) = 1;
chainon (env_var, meth_var);
! layout_decl (meth_var, 0);
! make_decl_rtl (meth_var, NULL);
! rest_of_decl_compilation (meth_var, NULL, 0, 0);
/* One strange way that the front ends are different is that they
--- 2134,2138 ----
TREE_USED (meth_var) = 1;
chainon (env_var, meth_var);
! build_result_decl (method);
/* One strange way that the front ends are different is that they
*************** build_jni_stub (tree method)
*** 2248,2284 ****
TREE_SIDE_EFFECTS (body) = 1;
! /* Finally, do the return. When compiling from source we rely on
! patch_return to patch the return value -- because DECL_RESULT is
! not set at the time this function is called. */
! if (from_class)
! {
! res_type = void_type_node;
! if (res_var != NULL_TREE)
! {
! tree drt;
! if (! DECL_RESULT (method))
! abort ();
! /* Make sure we copy the result variable to the actual
! result. We use the type of the DECL_RESULT because it
! might be different from the return type of the function:
! it might be promoted. */
! drt = TREE_TYPE (DECL_RESULT (method));
! if (drt != TREE_TYPE (res_var))
! res_var = build1 (CONVERT_EXPR, drt, res_var);
! res_var = build (MODIFY_EXPR, drt, DECL_RESULT (method), res_var);
! TREE_SIDE_EFFECTS (res_var) = 1;
! }
! }
! else
{
! /* This is necessary to get patch_return to run. */
! res_type = NULL_TREE;
}
body = build (COMPOUND_EXPR, void_type_node, body,
build1 (RETURN_EXPR, res_type, res_var));
TREE_SIDE_EFFECTS (body) = 1;
!
! BLOCK_EXPR_BODY (block) = body;
! return block;
}
--- 2250,2278 ----
TREE_SIDE_EFFECTS (body) = 1;
! /* Finally, do the return. */
! res_type = void_type_node;
! if (res_var != NULL_TREE)
{
! tree drt;
! if (! DECL_RESULT (method))
! abort ();
! /* Make sure we copy the result variable to the actual
! result. We use the type of the DECL_RESULT because it
! might be different from the return type of the function:
! it might be promoted. */
! drt = TREE_TYPE (DECL_RESULT (method));
! if (drt != TREE_TYPE (res_var))
! res_var = build1 (CONVERT_EXPR, drt, res_var);
! res_var = build (MODIFY_EXPR, drt, DECL_RESULT (method), res_var);
! TREE_SIDE_EFFECTS (res_var) = 1;
}
+
body = build (COMPOUND_EXPR, void_type_node, body,
build1 (RETURN_EXPR, res_type, res_var));
TREE_SIDE_EFFECTS (body) = 1;
!
! bind = build (BIND_EXPR, void_type_node, BLOCK_VARS (block),
! body, block);
! return bind;
}
*************** expand_java_field_op (int is_static, int
*** 2354,2358 ****
}
}
! expand_assignment (field_ref, new_value, 0, 0);
}
else
--- 2348,2352 ----
}
}
! java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (field_ref), field_ref, new_value));
}
else
*************** java_expand_expr (tree exp, rtx target,
*** 2414,2417 ****
--- 2408,2413 ----
tree current;
+ abort ();
+
switch (TREE_CODE (exp))
{
*************** expand_byte_code (JCF *jcf, tree method)
*** 2782,2786 ****
return;
! /* Translate bytecodes to rtl instructions. */
linenumber_pointer = linenumber_table;
for (PC = 0; PC < length;)
--- 2778,2782 ----
return;
! /* Translate bytecodes. */
linenumber_pointer = linenumber_table;
for (PC = 0; PC < length;)
*************** expand_byte_code (JCF *jcf, tree method)
*** 2791,2795 ****
flush_quick_stack ();
if ((instruction_bits [PC] & BCODE_TARGET) != 0)
! expand_label (label);
if (LABEL_VERIFIED (label) || PC == 0)
load_type_state (label);
--- 2787,2791 ----
flush_quick_stack ();
if ((instruction_bits [PC] & BCODE_TARGET) != 0)
! java_add_stmt (build (LABEL_EXPR, void_type_node, label));
if (LABEL_VERIFIED (label) || PC == 0)
load_type_state (label);
*************** expand_byte_code (JCF *jcf, tree method)
*** 2838,2842 ****
{
input_line = GET_u2 (linenumber_pointer - 2);
- emit_line_note (input_filename, input_line);
if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
break;
--- 2834,2837 ----
*************** process_jvm_instruction (int PC, const u
*** 2886,2890 ****
{
tree type = pop_type (ptr_type_node);
! push_value (build (JAVA_EXC_OBJ_EXPR, type));
}
--- 2881,2885 ----
{
tree type = pop_type (ptr_type_node);
! push_value (build_exception_object_ref (type));
}
*************** process_jvm_instruction (int PC, const u
*** 3101,3105 ****
decl = find_local_variable (var, type, oldpc); \
set_local_type (var, type ); \
! expand_assignment (decl, value, 0, 0); \
}
--- 3096,3100 ----
decl = find_local_variable (var, type, oldpc); \
set_local_type (var, type ); \
! java_add_stmt (build (MODIFY_EXPR, type, decl, value)); \
}
*************** process_jvm_instruction (int PC, const u
*** 3124,3128 ****
c = build_java_monitor (call, o); \
TREE_SIDE_EFFECTS (c) = 1; \
! expand_expr_stmt (c); \
}
--- 3119,3123 ----
c = build_java_monitor (call, o); \
TREE_SIDE_EFFECTS (c) = 1; \
! java_add_stmt (c); \
}
Index: java-except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-except.h,v
retrieving revision 1.9.32.2
diff -c -2 -p -r1.9.32.2 java-except.h
*** java-except.h 3 Feb 2003 17:09:20 -0000 1.9.32.2
--- java-except.h 23 Jul 2003 15:14:17 -0000
*************** struct eh_range
*** 51,54 ****
--- 51,57 ----
/* True if this range has already been expanded. */
int expanded;
+
+ /* The TRY_CATCH_EXPR for this EH range. */
+ tree stmt;
};
Index: java-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/java-gimplify.c,v
retrieving revision 1.1.2.2
diff -c -2 -p -r1.1.2.2 java-gimplify.c
*** java-gimplify.c 28 Jun 2003 15:18:31 -0000 1.1.2.2
--- java-gimplify.c 23 Jul 2003 15:14:17 -0000
*************** java_gimplify_block (tree java_block)
*** 144,148 ****
/* Don't bother with empty blocks. */
! if (IS_EMPTY_STMT (body))
return body;
--- 144,148 ----
/* Don't bother with empty blocks. */
! if (! body || IS_EMPTY_STMT (body))
return body;
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.153.2.17
diff -c -2 -p -r1.153.2.17 java-tree.h
*** java-tree.h 21 Jun 2003 18:21:00 -0000 1.153.2.17
--- java-tree.h 23 Jul 2003 15:14:18 -0000
*************** extern void compile_resource_file (char
*** 1301,1304 ****
--- 1301,1308 ----
extern void init_resource_processing (void);
extern tree build_java_empty_stmt (void);
+ extern tree add_stmt_to_compound (tree, tree, tree);
+ extern tree java_add_stmt (tree);
+ extern tree java_add_local_var (tree decl);
+ extern tree *get_stmts (void);
#define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)
*************** enum
*** 1758,1763 ****
--- 1762,1769 ----
#define EXPR_WFL_EMIT_LINE_NOTE(NODE) \
(EXPR_WITH_FILE_LOCATION_CHECK (NODE)->common.public_flag)
+ #undef EXPR_WFL_NODE
#define EXPR_WFL_NODE(NODE) \
TREE_OPERAND (EXPR_WITH_FILE_LOCATION_CHECK (NODE), 0)
+ #undef EXPR_WFL_FILENAME_NODE
#define EXPR_WFL_FILENAME_NODE(NODE) \
TREE_OPERAND (EXPR_WITH_FILE_LOCATION_CHECK (NODE), 1)
Index: jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.118.2.13
diff -c -2 -p -r1.118.2.13 jcf-parse.c
*** jcf-parse.c 3 Jun 2003 16:52:07 -0000 1.118.2.13
--- jcf-parse.c 23 Jul 2003 15:14:18 -0000
*************** parse_class_file (void)
*** 748,752 ****
start_java_method (method);
give_name_to_locals (jcf);
! expand_expr_stmt (build_jni_stub (method));
end_java_method ();
continue;
--- 748,752 ----
start_java_method (method);
give_name_to_locals (jcf);
! *get_stmts () = build_jni_stub (method);
end_java_method ();
continue;
*************** parse_class_file (void)
*** 790,794 ****
give_name_to_locals (jcf);
! /* Actually generate code. */
expand_byte_code (jcf, method);
--- 790,794 ----
give_name_to_locals (jcf);
! /* Convert bytecode to trees. */
expand_byte_code (jcf, method);
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.387.2.24
diff -c -2 -p -r1.387.2.24 parse.y
*** parse.y 22 Jun 2003 20:25:50 -0000 1.387.2.24
--- parse.y 23 Jul 2003 15:14:23 -0000
*************** static int class_in_current_package (tre
*** 197,201 ****
static tree build_if_else_statement (int, tree, tree, tree);
static tree patch_if_else_statement (tree);
- static tree add_stmt_to_compound (tree, tree, tree);
static tree add_stmt_to_block (tree, tree, tree);
static tree patch_exit_expr (tree);
--- 197,200 ----
*************** add_stmt_to_block (tree b, tree type, tr
*** 7455,7474 ****
TREE_SIDE_EFFECTS (c) = 1;
return c;
- }
-
- /* Add STMT to EXISTING if possible, otherwise create a new
- COMPOUND_EXPR and add STMT to it. */
-
- static tree
- add_stmt_to_compound (tree existing, tree type, tree stmt)
- {
- /* Keep track of this for inlining. */
- if (current_function_decl)
- ++DECL_NUM_STMTS (current_function_decl);
-
- if (existing)
- return build (COMPOUND_EXPR, type, existing, stmt);
- else
- return stmt;
}
--- 7454,7457 ----