This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

patch for PR java/1208, plus other try-finally cleanups


There has been some discussion on the java list over PR 1208 and
related issues with generating bytecode for TRY_FINALLY_EXPR;
this is my candidate fix.  I'll give people a chance to critique it
before I check it in.  Otherwise, I'll probably check it in tomorrow.

The verify_jvm_instructions patch is semi-related; it improves the error
message on compiling the incorrect bytecode.

The java_complete_lhs is also only semi-related; if we have the optimization
there (where I think it belongs), we can get rid of some of the special-case
code (including the "worthwhile_finally" stuff) in jcf-write.c.

Leaving that aside, there are a couple of different problems with the
compilation of TRY_FINALLY_EXPR.  The immediate fix for PR 1208 is to
defer free the local variable for the exception_decl until after the
finalizer, to prevent the latter from re-allocating (and hence
clobbering) it.

There is also an optimization to avoid emiting a jsr to teh finalizer
in the try-block after a return or other expression that fails
CAN_COMPLETE_NORMALLY.  (In the case of a return, the handling of
cleanups will generate a call to the finalizer before the return.)
(Tom Tromey independently found a similar patch.)

Finally, this reverts an invalid optimization from last year which would
suppress the goto after a try-block if the latter was empty.

2001-03-20  Per Bothner  <per@bothner.com>

	* verify.c (verify_jvm_instructions):  Replace 3 pop_type by POP_TYPE
	macro for better error pin-pointing.

	* jcf-write.c (generate_bytecode_insns):  Changes to TRY_FINALLY_EXPR.
	Don't bothner optimizing empty try-/finally-clause here.
	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.

Index: verify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/verify.c,v
retrieving revision 1.39.2.1
diff -u -p -r1.39.2.1 verify.c
--- verify.c	2001/03/17 21:53:12	1.39.2.1
+++ verify.c	2001/03/21 02:59:51
@@ -1137,7 +1137,7 @@ verify_jvm_instructions (jcf, byte_ops, 
 
 	case OPCODE_athrow:
 	  /* FIXME: athrow also empties the stack. */
-	  pop_type (throwable_type_node);
+	  POP_TYPE (throwable_type_node, "missing throwable at athrow" );
 	  INVALIDATE_PC;
 	  break;
 
@@ -1156,7 +1156,7 @@ verify_jvm_instructions (jcf, byte_ops, 
 	  {
 	    jint low, high;
 
-	    pop_type (int_type_node);
+	    POP_TYPE (int_type_node, "missing int for tableswitch");
 	    while (PC%4)
 	      {
 	        if (byte_ops[PC++])
@@ -1179,7 +1179,7 @@ verify_jvm_instructions (jcf, byte_ops, 
 	  {
 	    jint npairs, last = 0, not_registered = 1;
 
-	    pop_type (int_type_node);
+	    POP_TYPE (int_type_node, "missing int for lookupswitch");
 	    while (PC%4)
 	      {
 	        if (byte_ops[PC++])
Index: jcf-write.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-write.c,v
retrieving revision 1.72.2.1
diff -u -p -r1.72.2.1 jcf-write.c
--- jcf-write.c	2001/03/17 21:53:11	1.72.2.1
+++ jcf-write.c	2001/03/21 02:59:53
@@ -111,7 +111,7 @@ struct chunk
 struct jcf_block
 {
   /* 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),
      this is the next (outer) such end label, in a stack headed by
      labeled_blocks in jcf_partial. */
@@ -131,8 +131,8 @@ struct jcf_block
 
   int linenumber;
 
-  /* After finish_jcf_block is called, The actual instructions
-     contained in this block.  Before than NULL, and the instructions
+  /* After finish_jcf_block is called, the actual instructions
+     contained in this block.  Before that NULL, and the instructions
      are in state->bytecode. */
   union {
     struct chunk *chunk;
@@ -349,7 +349,7 @@ static void append_innerclasses_attribut
 
 /* Utility macros for appending (big-endian) data to a buffer.
    We assume a local variable 'ptr' points into where we want to
-   write next, and we assume enoygh space has been allocated. */
+   write next, and we assume enough space has been allocated. */
 
 #ifdef ENABLE_JC1_CHECKING
 static int CHECK_PUT PARAMS ((void *, struct jcf_partial *, int));
@@ -2331,58 +2331,42 @@ generate_bytecode_insns (exp, target, st
       break;
     case TRY_FINALLY_EXPR:
       {
-	struct jcf_block *finished_label, *finally_label, *start_label;
+	struct jcf_block *finished_label,
+	  *finally_label = NULL, *start_label = NULL;
 	struct jcf_handler *handler;
-	int worthwhile_finally = 1;
 	tree try_block = TREE_OPERAND (exp, 0);
 	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;
-	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
-           remember to just skip it. */
-	if (BLOCK_EXPR_BODY (finally) == empty_stmt_node)
-	  worthwhile_finally = 0;
+	tree exception_type;
+	return_link = build_decl (VAR_DECL, NULL_TREE,
+				  return_address_type_node);
+	exception_type = build_pointer_type (throwable_type_node);
+	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++;
 
-	if (worthwhile_finally)
-	  {
-	    tree exception_type;
-	    return_link = build_decl (VAR_DECL, NULL_TREE,
-				      return_address_type_node);
-	    exception_type = build_pointer_type (throwable_type_node);
-	    exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
+	generate_bytecode_insns (try_block, target, state);
 
-	    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++;
-	  }
+	finished_label = gen_jcf_label (state);
 
-	generate_bytecode_insns (try_block, target, state);
+	if (state->labeled_blocks != finally_label)
+	  abort();
+	state->labeled_blocks = finally_label->next;
 
-	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_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. */
 
-	if (!worthwhile_finally)
-	  break;
-
 	localvar_alloc (return_link, state);
 	handler = alloc_handler (start_label, NULL_PTR, state);
 	handler->end_label = handler->handler_label;
@@ -2395,7 +2379,6 @@ generate_bytecode_insns (exp, target, st
 	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);
@@ -2404,6 +2387,7 @@ generate_bytecode_insns (exp, target, st
 
 	generate_bytecode_insns (finally, IGNORE_TARGET, state);
 	maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state);
+	localvar_free (exception_decl, state);
 	localvar_free (return_link, state);
 	define_jcf_label (finished_label, state);
       }
Index: parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/parse.y,v
retrieving revision 1.251.2.8
diff -u -r1.251.2.8 parse.y
--- parse.y	2001/03/19 17:20:00	1.251.2.8
+++ parse.y	2001/03/21 03:02:04
@@ -11194,6 +11194,10 @@
     case TRY_FINALLY_EXPR:
       COMPLETE_CHECK_OP_0 (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 (TREE_OPERAND (node, 0))
 	   && CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 1)));

-- 
	--Per Bothner
per@bothner.com   http://www.bothner.com/~per/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]