Use new TRY_FINALLY_EXPR tree node.

�
Use new TRY_FINALLY_EXPR tree node.  See ChangeLog.

From-SVN: r25314
This commit is contained in:
Per Bothner 1999-02-19 04:32:50 -08:00
parent 10b3fbc515
commit a7d8d81f7c
6 changed files with 546 additions and 719 deletions

View File

@ -42,20 +42,14 @@ DEFTREECODE (DEFAULT_EXPR, "default", 'x', 0)
/* Try expression
Operand 0 is the tried block,
Operand 1 contains chained catch nodes
Operand 2 contains the finally clause. */
DEFTREECODE (TRY_EXPR, "try-catch-finally", 'e', 3)
Operand 1 contains chained catch nodes. */
DEFTREECODE (TRY_EXPR, "try-catch-finally", 'e', 2)
/* Catch clause.
Operand 0 is the catch clause block, which contains the declaration of
the catch clause parameter. */
DEFTREECODE (CATCH_EXPR, "catch", '1', 1)
/* Finally clause.
Operand 0 is the finally label.
Operand 1 is the finally block. */
DEFTREECODE (FINALLY_EXPR, "finally", 'e', 2)
/* Synchronized statement.
Operand 0 is the expression on which we whish to synchronize,
Operand 1 is the synchronized expression block. */

View File

@ -860,9 +860,6 @@ extern tree *type_map;
#define BLOCK_EXPR_DECLS(NODE) BLOCK_VARS(NODE)
#define BLOCK_EXPR_BODY(NODE) BLOCK_SUBBLOCKS(NODE)
/* Using a CATCH_EXPR node */
#define CATCH_EXPR_GET_EXPR(NODE, V) (V ? LABELED_BLOCK_BODY (NODE) : (NODE))
/* Non zero if TYPE is an unchecked exception */
#define IS_UNCHECKED_EXCEPTION_P(TYPE) \
(inherits_from_p ((TYPE), runtime_exception_type_node) \

View File

@ -2182,24 +2182,17 @@ generate_bytecode_insns (exp, target, state)
case TRY_EXPR:
{
tree try_clause = TREE_OPERAND (exp, 0);
tree finally = TREE_OPERAND (exp, 2);
struct jcf_block *start_label = get_jcf_label_here (state);
struct jcf_block *end_label; /* End of try clause. */
struct jcf_block *finally_label; /* Finally subroutine. */
struct jcf_block *finished_label = gen_jcf_label (state);
tree clause = TREE_OPERAND (exp, 1);
if (finally)
{
finally = FINALLY_EXPR_BLOCK (finally);
finally_label = gen_jcf_label (state);
}
if (target != IGNORE_TARGET)
abort ();
generate_bytecode_insns (try_clause, IGNORE_TARGET, state);
end_label = get_jcf_label_here (state);
if (CAN_COMPLETE_NORMALLY (try_clause))
emit_goto (finished_label, state);
for ( ; clause != NULL_TREE; clause = TREE_CHAIN (clause))
while (clause != NULL_TREE)
{
tree catch_clause = TREE_OPERAND (clause, 0);
tree exception_decl = BLOCK_EXPR_DECLS (catch_clause);
@ -2209,43 +2202,63 @@ generate_bytecode_insns (exp, target, state)
else
handler->type = TREE_TYPE (TREE_TYPE (exception_decl));
generate_bytecode_insns (catch_clause, IGNORE_TARGET, state);
if (CAN_COMPLETE_NORMALLY (catch_clause))
clause = TREE_CHAIN (clause);
if (CAN_COMPLETE_NORMALLY (catch_clause) && clause != NULL_TREE)
emit_goto (finished_label, state);
}
if (finally)
{
tree return_link;
tree exception_type = build_pointer_type (throwable_type_node);
tree exception_decl = build_decl (VAR_DECL, NULL_TREE,
exception_type);
struct jcf_handler *handler
= alloc_handler (start_label, NULL_TREE, state);
handler->end_label = handler->handler_label;
handler->type = NULL_TREE;
localvar_alloc (exception_decl, state);
NOTE_PUSH (1);
emit_store (exception_decl, state);
emit_jsr (finally_label, state);
emit_load (exception_decl, state);
RESERVE (1);
OP1 (OPCODE_athrow);
NOTE_POP (1);
localvar_free (exception_decl, state);
/* The finally block. */
return_link = build_decl (VAR_DECL, NULL_TREE,
return_address_type_node);
define_jcf_label (finally_label, state);
NOTE_PUSH (1);
localvar_alloc (return_link, state);
emit_store (return_link, state);
generate_bytecode_insns (finally, IGNORE_TARGET, state);
maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
localvar_free (return_link, state);
}
define_jcf_label (finished_label, state);
if (finally)
emit_jsr (finally_label, state);
}
break;
case TRY_FINALLY_EXPR:
{
tree try_block = TREE_OPERAND (exp, 0);
tree finally = TREE_OPERAND (exp, 1);
struct jcf_block *finished_label = gen_jcf_label (state);
struct jcf_block *finally_label = gen_jcf_label (state);
struct jcf_block *start_label = get_jcf_label_here (state);
tree return_link = build_decl (VAR_DECL, NULL_TREE,
return_address_type_node);
tree exception_type = build_pointer_type (throwable_type_node);
tree exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
struct jcf_handler *handler;
finally_label->pc = PENDING_CLEANUP_PC;
finally_label->next = state->labeled_blocks;
state->labeled_blocks = finally_label;
state->num_finalizers++;
generate_bytecode_insns (try_block, target, state);
if (state->labeled_blocks != finally_label)
abort();
state->labeled_blocks = finally_label->next;
emit_jsr (finally_label, state);
if (CAN_COMPLETE_NORMALLY (try_block))
emit_goto (finished_label, state);
/* Handle exceptions. */
localvar_alloc (return_link, state);
handler = alloc_handler (start_label, NULL_TREE, state);
handler->end_label = handler->handler_label;
handler->type = NULL_TREE;
localvar_alloc (exception_decl, state);
NOTE_PUSH (1);
emit_store (exception_decl, state);
emit_jsr (finally_label, state);
emit_load (exception_decl, state);
RESERVE (1);
OP1 (OPCODE_athrow);
NOTE_POP (1);
localvar_free (exception_decl, state);
/* The finally block. First save return PC into return_link. */
define_jcf_label (finally_label, state);
NOTE_PUSH (1);
emit_store (return_link, state);
generate_bytecode_insns (finally, IGNORE_TARGET, state);
maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
localvar_free (return_link, state);
define_jcf_label (finished_label, state);
}
break;
case THROW_EXPR:

File diff suppressed because it is too large Load Diff

View File

@ -666,7 +666,6 @@ void java_layout_classes PROTO ((void));
tree java_method_add_stmt PROTO ((tree, tree));
char *java_get_line_col PROTO ((char *, int, int));
void java_expand_switch PROTO ((tree));
tree java_get_catch_block PROTO ((tree, int));
int java_report_errors PROTO (());
#endif

View File

@ -201,7 +201,8 @@ static tree build_string_concatenation PROTO ((tree, tree));
static tree patch_string_cst PROTO ((tree));
static tree patch_string PROTO ((tree));
static tree build_jump_to_finally PROTO ((tree, tree, tree, tree));
static tree build_try_statement PROTO ((int, tree, tree, tree));
static tree build_try_statement PROTO ((int, tree, tree));
static tree build_try_finally_statement PROTO ((int, tree, tree));
static tree patch_try_statement PROTO ((tree));
static tree patch_synchronized_statement PROTO ((tree, tree));
static tree patch_throw_statement PROTO ((tree, tree));
@ -1616,11 +1617,14 @@ synchronized:
try_statement:
TRY_TK block catches
{ $$ = build_try_statement ($1.location, $2, $3, NULL_TREE); }
{ $$ = build_try_statement ($1.location, $2, $3); }
| TRY_TK block finally
{ $$ = build_try_statement ($1.location, $2, NULL_TREE, $3); }
{ $$ = build_try_finally_statement ($1.location, $2, $3); }
| TRY_TK block catches finally
{ $$ = build_try_statement ($1.location, $2, $3, $4); }
{ $$ = build_try_finally_statement ($1.location,
build_try_statement ($1.location,
$2, $3),
$4); }
| TRY_TK error
{yyerror ("'{' expected"); DRECOVER (try_statement);}
;
@ -1669,10 +1673,7 @@ catch_clause_parameter:
finally:
FINALLY_TK block
{
$$ = build (FINALLY_EXPR, NULL_TREE,
create_label_decl (generate_name ()), $2);
}
{ $$ = $2; }
| FINALLY_TK error
{yyerror ("'{' expected"); RECOVER; }
;
@ -7584,6 +7585,15 @@ java_complete_lhs (node)
case TRY_EXPR:
return patch_try_statement (node);
case TRY_FINALLY_EXPR:
COMPLETE_CHECK_OP_0 (node);
COMPLETE_CHECK_OP_1 (node);
CAN_COMPLETE_NORMALLY (node)
= (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0))
&& CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1)));
TREE_TYPE (node) = TREE_TYPE (TREE_OPERAND (node, 0));
return node;
case CLEANUP_POINT_EXPR:
COMPLETE_CHECK_OP_0 (node);
TREE_TYPE (node) = void_type_node;
@ -10671,92 +10681,23 @@ build_jump_to_finally (block, decl, finally_label, type)
}
static tree
build_try_statement (location, try_block, catches, finally)
build_try_statement (location, try_block, catches)
int location;
tree try_block, catches, finally;
tree try_block, catches;
{
tree node, rff;
if (finally && ! flag_emit_class_files)
{
/* This block defines a scope for the entire try[-catch]-finally
sequence. It hold a local variable used to return from the
finally using a computed goto. We call it
return_from_finally (RFF). */
rff = build_decl (VAR_DECL, generate_name (), return_address_type_node);
/* Modification of the try block. */
try_block = build_jump_to_finally (try_block, rff,
FINALLY_EXPR_LABEL (finally),
NULL_TREE);
/* To the finally block: add the computed goto */
add_stmt_to_block (FINALLY_EXPR_BLOCK (finally), NULL_TREE,
build (GOTO_EXPR, void_type_node, rff));
/* Modification of each catch blocks, if any */
if (catches)
{
tree catch, catch_decl, catch_block, stmt;
for (catch = catches; catch; catch = TREE_CHAIN (catch))
TREE_OPERAND (catch, 0) =
build_jump_to_finally (TREE_OPERAND (catch, 0), rff,
FINALLY_EXPR_LABEL (finally),
NULL_TREE);
/* Plus, at the end of the list, we add the catch clause that
will catch an uncaught exception, call finally and rethrow it:
BLOCK
void *exception_parameter; (catch_decl)
LABELED_BLOCK
BLOCK
exception_parameter = _Jv_exception_info ();
RFF = &LABEL_DECL;
goto finally;
LABEL_DECL;
CALL_EXPR
Jv_ReThrow
exception_parameter */
catch_decl = build_decl (VAR_DECL, generate_name (), ptr_type_node);
BUILD_ASSIGN_EXCEPTION_INFO (stmt, catch_decl);
catch_block = build_expr_block (stmt, NULL_TREE);
catch_block = build_jump_to_finally (catch_block, rff,
FINALLY_EXPR_LABEL (finally),
void_type_node);
BUILD_THROW (stmt, catch_decl);
catch_block = build_expr_block (catch_block, catch_decl);
add_stmt_to_block (catch_block, void_type_node, stmt);
/* Link the new handler to the existing list as the first
entry. It will be the last one to be generated. */
catch = build1 (CATCH_EXPR, void_type_node, catch_block);
TREE_CHAIN (catch) = catches;
catches = catch;
}
}
node = build (TRY_EXPR, NULL_TREE, try_block, catches, finally);
tree node = build (TRY_EXPR, NULL_TREE, try_block, catches);
EXPR_WFL_LINECOL (node) = location;
/* If we have a finally, surround this whole thing by a block where
the RFF local variable is defined. */
return (finally && ! flag_emit_class_files ? build_expr_block (node, rff)
: node);
return node;
}
/* Get the catch clause block from an element of the catch clause
list. If depends on whether a finally clause exists or node (in
which case the original catch clause was surrounded by a
LABELED_BLOCK_EXPR. */
tree
java_get_catch_block (node, finally_present_p)
tree node;
int finally_present_p;
static tree
build_try_finally_statement (location, try_block, finally)
int location;
tree try_block, finally;
{
return (CATCH_EXPR_GET_EXPR (TREE_OPERAND (node, 0), finally_present_p));
tree node = build (TRY_FINALLY_EXPR, NULL_TREE, try_block, finally);
EXPR_WFL_LINECOL (node) = location;
return node;
}
static tree
@ -10767,8 +10708,6 @@ patch_try_statement (node)
tree try = TREE_OPERAND (node, 0);
/* Exception handlers are considered in left to right order */
tree catch = nreverse (TREE_OPERAND (node, 1));
tree finally = TREE_OPERAND (node, 2);
int finally_p = (finally ? 1 : 0);
tree current, caught_type_list = NULL_TREE;
/* Check catch clauses, if any. Every time we find an error, we try
@ -10781,29 +10720,14 @@ patch_try_statement (node)
tree sub_current, catch_block, catch_clause;
int unreachable;
/* Always detect the last catch clause if a finally is
present. This is the catch-all handler and it just needs to
be walked. */
if (!TREE_CHAIN (current) && finally)
{
TREE_OPERAND (current, 0) =
java_complete_tree (TREE_OPERAND (current, 0));
continue;
}
/* At this point, the structure of the catch clause is
LABELED_BLOCK_EXPR (if we have a finally)
CATCH_EXPR (catch node)
BLOCK (with the decl of the parameter)
COMPOUND_EXPR
MODIFY_EXPR (assignment of the catch parameter)
BLOCK (catch clause block)
LABEL_DECL (where to return after finally (if any))
Since the structure of the catch clause depends on the
presence of a finally, we use a function call to get to the
cath clause */
catch_clause = java_get_catch_block (current, finally_p);
*/
catch_clause = TREE_OPERAND (current, 0);
carg_decl = BLOCK_EXPR_DECLS (catch_clause);
carg_type = TREE_TYPE (TREE_TYPE (carg_decl));
@ -10837,7 +10761,7 @@ patch_try_statement (node)
sub_current != current; sub_current = TREE_CHAIN (sub_current))
{
tree sub_catch_clause, decl;
sub_catch_clause = java_get_catch_block (sub_current, finally_p);
sub_catch_clause = TREE_OPERAND (sub_current, 0);
decl = BLOCK_EXPR_DECLS (sub_catch_clause);
if (inherits_from_p (carg_type, TREE_TYPE (TREE_TYPE (decl))))
@ -10877,24 +10801,12 @@ patch_try_statement (node)
CAN_COMPLETE_NORMALLY (node) = 1;
POP_EXCEPTIONS ();
/* Process finally */
if (finally)
{
current = java_complete_tree (FINALLY_EXPR_BLOCK (finally));
FINALLY_EXPR_BLOCK (finally) = current;
if (current == error_mark_node)
error_found = 1;
if (! CAN_COMPLETE_NORMALLY (current))
CAN_COMPLETE_NORMALLY (node) = 0;
}
/* Verification ends here */
if (error_found)
return error_mark_node;
TREE_OPERAND (node, 0) = try;
TREE_OPERAND (node, 1) = catch;
TREE_OPERAND (node, 2) = finally;
TREE_TYPE (node) = void_type_node;
return node;
}