Commit fa029f45 by Per Bothner Committed by Per Bothner

re PR java/1208 (Gcj can't compile a class file it generates.)

e
	* verify.c (verify_jvm_instructions):  Replace 3 pop_type by POP_TYPE
	macro for better error pin-pointing.
	* java-tree.h:  Fix typo in comment.

	* jcf-write.c (generate_bytecode_insns):  Changes to TRY_FINALLY_EXPR.
	Don't include jsr/goto in exception range.
	Check if start and end of exception range are the same (also TRY_EXPR).
	Don't emit jsr after try_block if CAN_COMPLETE_NORMALLY is false.
	However, do emit the following goto even if try_block is empty.
	Defer freeing exception_decl until after the finalizer, to make
	sure the local isn't reused in the finalizer.  Fixes PR java/1208.

	* parse.y (java_complete_lhs):  If the try-clause is empty, just
	return the finally-clause and vice versa.

From-SVN: r40801
parent 3c45ffa5
2001-03-23 Per Bothner <per@bothner.com>
* verify.c (verify_jvm_instructions): Replace 3 pop_type by POP_TYPE
macro for better error pin-pointing.
* java-tree.h: Fix typo in comment.
* jcf-write.c (generate_bytecode_insns): Changes to TRY_FINALLY_EXPR.
Don't include jsr/goto in exception range.
Check if start and end of exception range are the same (also TRY_EXPR).
Don't emit jsr after try_block if CAN_COMPLETE_NORMALLY is false.
However, do emit the following goto even if try_block is empty.
Defer freeing exception_decl until after the finalizer, to make
sure the local isn't reused in the finalizer. Fixes PR java/1208.
* parse.y (java_complete_lhs): If the try-clause is empty, just
return the finally-clause and vice versa.
2001-03-23 Alexandre Petit-Bianco <apbianco@redhat.com> 2001-03-23 Alexandre Petit-Bianco <apbianco@redhat.com>
* gcj.texi (Input Options): documented the check for attribute * gcj.texi (Input Options): documented the check for attribute
......
...@@ -743,7 +743,7 @@ struct lang_identifier ...@@ -743,7 +743,7 @@ struct lang_identifier
#define LABEL_RETURN_TYPE_STATE(NODE) LABEL_TYPE_STATE (LABEL_RETURN_LABEL (NODE)) #define LABEL_RETURN_TYPE_STATE(NODE) LABEL_TYPE_STATE (LABEL_RETURN_LABEL (NODE))
/* In a TREE_VEC for a LABEL_RETURN_TYPE_STATE, notes that /* In a TREE_VEC for a LABEL_RETURN_TYPE_STATE, notes that
TREE_VEC_LENGTH has been adjust to the correct stack size. */ TREE_VEC_LENGTH has been adjusted to the correct stack size. */
#define RETURN_MAP_ADJUSTED(NODE) TREE_LANG_FLAG_2(NODE) #define RETURN_MAP_ADJUSTED(NODE) TREE_LANG_FLAG_2(NODE)
/* In the label of a sub-routine, a chain of the return location labels. */ /* In the label of a sub-routine, a chain of the return location labels. */
......
...@@ -111,7 +111,7 @@ struct chunk ...@@ -111,7 +111,7 @@ struct chunk
struct jcf_block struct jcf_block
{ {
/* For blocks that that are defined, the next block (in pc order). /* For blocks that that are defined, the next block (in pc order).
For blocks that are the not-yet-defined end label of a LABELED_BLOCK_EXPR For blocks that are not-yet-defined the end label of a LABELED_BLOCK_EXPR
or a cleanup expression (from a WITH_CLEANUP_EXPR), or a cleanup expression (from a WITH_CLEANUP_EXPR),
this is the next (outer) such end label, in a stack headed by this is the next (outer) such end label, in a stack headed by
labeled_blocks in jcf_partial. */ labeled_blocks in jcf_partial. */
...@@ -131,8 +131,8 @@ struct jcf_block ...@@ -131,8 +131,8 @@ struct jcf_block
int linenumber; int linenumber;
/* After finish_jcf_block is called, The actual instructions /* After finish_jcf_block is called, the actual instructions
contained in this block. Before than NULL, and the instructions contained in this block. Before that NULL, and the instructions
are in state->bytecode. */ are in state->bytecode. */
union { union {
struct chunk *chunk; struct chunk *chunk;
...@@ -2311,6 +2311,8 @@ generate_bytecode_insns (exp, target, state) ...@@ -2311,6 +2311,8 @@ generate_bytecode_insns (exp, target, state)
abort (); abort ();
generate_bytecode_insns (try_clause, IGNORE_TARGET, state); generate_bytecode_insns (try_clause, IGNORE_TARGET, state);
end_label = get_jcf_label_here (state); end_label = get_jcf_label_here (state);
if (end_label == start_label)
break;
if (CAN_COMPLETE_NORMALLY (try_clause)) if (CAN_COMPLETE_NORMALLY (try_clause))
emit_goto (finished_label, state); emit_goto (finished_label, state);
while (clause != NULL_TREE) while (clause != NULL_TREE)
...@@ -2332,61 +2334,53 @@ generate_bytecode_insns (exp, target, state) ...@@ -2332,61 +2334,53 @@ generate_bytecode_insns (exp, target, state)
break; break;
case TRY_FINALLY_EXPR: case TRY_FINALLY_EXPR:
{ {
struct jcf_block *finished_label, *finally_label, *start_label; struct jcf_block *finished_label,
*finally_label, *start_label, *end_label;
struct jcf_handler *handler; struct jcf_handler *handler;
int worthwhile_finally = 1;
tree try_block = TREE_OPERAND (exp, 0); tree try_block = TREE_OPERAND (exp, 0);
tree finally = TREE_OPERAND (exp, 1); tree finally = TREE_OPERAND (exp, 1);
tree return_link, exception_decl; tree return_link = NULL_TREE, exception_decl = NULL_TREE;
finally_label = start_label = NULL; tree exception_type;
return_link = exception_decl = NULL_TREE;
finished_label = gen_jcf_label (state);
/* If the finally clause happens to be empty, set a flag so we finally_label = gen_jcf_label (state);
remember to just skip it. */ start_label = get_jcf_label_here (state);
if (BLOCK_EXPR_BODY (finally) == empty_stmt_node) finally_label->pc = PENDING_CLEANUP_PC;
worthwhile_finally = 0; 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;
end_label = get_jcf_label_here (state);
if (worthwhile_finally) if (end_label == start_label)
{ {
tree exception_type; state->num_finalizers--;
return_link = build_decl (VAR_DECL, NULL_TREE, define_jcf_label (finally_label, state);
return_address_type_node); generate_bytecode_insns (finally, IGNORE_TARGET, state);
exception_type = build_pointer_type (throwable_type_node); break;
exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
finally_label = gen_jcf_label (state);
start_label = get_jcf_label_here (state);
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); return_link = build_decl (VAR_DECL, NULL_TREE,
return_address_type_node);
finished_label = gen_jcf_label (state);
if (worthwhile_finally)
if (CAN_COMPLETE_NORMALLY (try_block))
{ {
if (state->labeled_blocks != finally_label)
abort();
state->labeled_blocks = finally_label->next;
emit_jsr (finally_label, state); emit_jsr (finally_label, state);
emit_goto (finished_label, state);
} }
if (CAN_COMPLETE_NORMALLY (try_block)
&& TREE_CODE (try_block) == BLOCK
&& BLOCK_EXPR_BODY (try_block) != empty_stmt_node)
emit_goto (finished_label, state);
/* Handle exceptions. */ /* Handle exceptions. */
if (!worthwhile_finally) exception_type = build_pointer_type (throwable_type_node);
break; exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
localvar_alloc (return_link, state); localvar_alloc (return_link, state);
handler = alloc_handler (start_label, NULL_PTR, state); handler = alloc_handler (start_label, end_label, state);
handler->end_label = handler->handler_label;
handler->type = NULL_TREE; handler->type = NULL_TREE;
localvar_alloc (exception_decl, state); localvar_alloc (exception_decl, state);
NOTE_PUSH (1); NOTE_PUSH (1);
...@@ -2396,7 +2390,6 @@ generate_bytecode_insns (exp, target, state) ...@@ -2396,7 +2390,6 @@ generate_bytecode_insns (exp, target, state)
RESERVE (1); RESERVE (1);
OP1 (OPCODE_athrow); OP1 (OPCODE_athrow);
NOTE_POP (1); NOTE_POP (1);
localvar_free (exception_decl, state);
/* The finally block. First save return PC into return_link. */ /* The finally block. First save return PC into return_link. */
define_jcf_label (finally_label, state); define_jcf_label (finally_label, state);
...@@ -2405,6 +2398,7 @@ generate_bytecode_insns (exp, target, state) ...@@ -2405,6 +2398,7 @@ generate_bytecode_insns (exp, target, state)
generate_bytecode_insns (finally, IGNORE_TARGET, state); generate_bytecode_insns (finally, IGNORE_TARGET, state);
maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state); maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
localvar_free (exception_decl, state);
localvar_free (return_link, state); localvar_free (return_link, state);
define_jcf_label (finished_label, state); define_jcf_label (finished_label, state);
} }
......
...@@ -11185,6 +11185,10 @@ java_complete_lhs (node) ...@@ -11185,6 +11185,10 @@ java_complete_lhs (node)
case TRY_FINALLY_EXPR: case TRY_FINALLY_EXPR:
COMPLETE_CHECK_OP_0 (node); COMPLETE_CHECK_OP_0 (node);
COMPLETE_CHECK_OP_1 (node); COMPLETE_CHECK_OP_1 (node);
if (TREE_OPERAND (node, 0) == empty_stmt_node)
return TREE_OPERAND (node, 1);
if (TREE_OPERAND (node, 1) == empty_stmt_node)
return TREE_OPERAND (node, 0);
CAN_COMPLETE_NORMALLY (node) CAN_COMPLETE_NORMALLY (node)
= (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0)) = (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0))
&& CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1))); && CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1)));
......
...@@ -1137,7 +1137,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1137,7 +1137,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
case OPCODE_athrow: case OPCODE_athrow:
/* FIXME: athrow also empties the stack. */ /* FIXME: athrow also empties the stack. */
pop_type (throwable_type_node); POP_TYPE (throwable_type_node, "missing throwable at athrow" );
INVALIDATE_PC; INVALIDATE_PC;
break; break;
...@@ -1156,7 +1156,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1156,7 +1156,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
{ {
jint low, high; jint low, high;
pop_type (int_type_node); POP_TYPE (int_type_node, "missing int for tableswitch");
while (PC%4) while (PC%4)
{ {
if (byte_ops[PC++]) if (byte_ops[PC++])
...@@ -1179,7 +1179,7 @@ verify_jvm_instructions (jcf, byte_ops, length) ...@@ -1179,7 +1179,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
{ {
jint npairs, last = 0, not_registered = 1; jint npairs, last = 0, not_registered = 1;
pop_type (int_type_node); POP_TYPE (int_type_node, "missing int for lookupswitch");
while (PC%4) while (PC%4)
{ {
if (byte_ops[PC++]) if (byte_ops[PC++])
......
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