PATCH: new TRY_FINALLY_EXPR tree node

Per Bothner bothner@cygnus.com
Mon Feb 8 14:24:00 GMT 1999


[Note - this is not in just the Java front-end!]
I've been wanting to simplify Java's handling of the try-finally
statement.  I think a better way is a new TRY_FINALLY_EXPR tree-node,
which allows us to separate out the try-finally handling from
the try-catch handling (which catches specified exception).
Since there is no longer anything Java-specific in try-finally,
and since it provides useful functionality (I believe RMS
has been wanting to add something like this to the C front-end),
I think the new tree-node(s) should be in Gcc proper.

Then main way TRY_FINALLY_EXPR is different from a CLEANUP_POINT_EXPR
/WITH_CLEANUP_EXPR combination is that the latter "inlines" the
finalization.  I don't want that - I want a single copy of
the finalization, since in Java's case it is real user code,
and users expect to be able to set breakpoints in it.

This is actually two patches:  The changes to the gcc generic front-end,
plus patches to the java sub-directory.  The latter is mainly FYI,
since I have the authority to check that in on my own.  What I need
is a response on the changes to tree.def and expr.c.  It would be
good if back-/middle-end experts could take a look at the code for
expand_expr and see if they see anything that looks wrong.

	--Per Bothner
Cygnus Solutions     bothner@cygnus.com     http://www.cygnus.com/~bothner

Wed Feb  3 12:37:31 1999  Per Bothner  <bothner@cygnus.com>

	* tree.def (TRY_FINALLY_EXPR, GOTO_SUBROUTINE_EXPR):  New tree nodes,
	* expr.c (expand_expr):  Support new tree nodes.

Index: tree.def
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/tree.def,v
retrieving revision 1.52
diff -u -p -r1.52 tree.def
--- tree.def	1998/10/09 23:03:07	1.52
+++ tree.def	1999/02/03 20:57:42
@@ -702,6 +702,19 @@ DEFTREECODE (POSTINCREMENT_EXPR, "postin
    evaluated unless an exception is throw.  */
 DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2)
 
+/* Evaluate the first operand.
+   The second operand is a a cleanup expression whihc is evaluated
+   before an exit (normal, exception, or jump out) from this expression.
+   Like a CLEANUP_POINT_EXPR/WITH_CLEANUP_EXPR combination, except
+   the cleanup is only emitted once (so debuggers can set breakpoints
+   in it). */
+DEFTREECODE (TRY_FINALLY_EXPR, "try-finally", 'e', 2)
+
+/* Used internally for cleanups in the implementation of TRY_FINALLY_EXPR.
+   Operand 0 is the rtx for the start of the subroutine we need to call.
+   Operand 1 is the rtx for a variable where the subrotine should return to. */
+DEFTREECODE (GOTO_SUBROUTINE_EXPR, "goto-subroutine", 'e', 2)
+
 /* Pop the top element off the dynamic handler chain.  Used in
    conjunction with setjmp/longjmp based exception handling, see
    except.c for more details.  This is meant to be used only by the
Index: expr.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/expr.c,v
retrieving revision 1.368
diff -u -p -r1.368 expr.c
--- expr.c	1998/10/09 23:02:31	1.368
+++ expr.c	1999/02/03 20:57:42
@@ -8102,6 +8102,48 @@ expand_expr (exp, target, tmode, modifie
 	return op0;
       }
 
+    case TRY_FINALLY_EXPR:
+      {
+	tree try_block = TREE_OPERAND (exp, 0);
+	tree finally_block = TREE_OPERAND (exp, 1);
+	rtx finally_label = gen_label_rtx ();
+	rtx done_label = gen_label_rtx ();
+	rtx return_link = gen_reg_rtx (Pmode);
+	extern int temp_slot_level;
+	tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
+			      (tree) finally_label, (tree) return_link);
+	TREE_SIDE_EFFECTS (cleanup) = 1;
+
+	/* Start a new binding layer that will keep track of all cleanup
+	   actions to be performed.  */
+	expand_start_bindings (0);
+
+	target_temp_slot_level = temp_slot_level;
+
+	expand_decl_cleanup (NULL_TREE, cleanup);
+	op0 = expand_expr (try_block, target, tmode, modifier);
+
+	preserve_temp_slots (op0);
+	expand_end_bindings (NULL_TREE, 0, 0);
+	emit_jump (done_label);
+	emit_label (finally_label);
+	expand_expr (finally_block, const0_rtx, VOIDmode, 0);
+	emit_indirect_jump (return_link);
+	emit_label (done_label);
+	return op0;
+      }
+
+      case GOTO_SUBROUTINE_EXPR:
+      {
+	rtx subr = (rtx) TREE_OPERAND (exp, 0);
+	rtx return_link = *(rtx *) &TREE_OPERAND (exp, 1);
+	rtx return_address = gen_label_rtx ();
+	emit_move_insn (return_link, gen_rtx_LABEL_REF (Pmode, return_address));
+	emit_jump (subr);
+	emit_label (return_address);
+	return const0_rtx;
+      }
+
     case POPDCC_EXPR:
       {
 	rtx dcc = get_dynamic_cleanup_chain ();

In gcc/java:

Wed Feb  3 12:38:43 1999  Per Bothner  <bothner@cygnus.com>

	* java-tree.def (FINALLY_EXPR):  Removed.  (Now uses TRY_FINALLY_EXPR.)
	(TRY_EXPR):  Simplify - it no longer has a finally clause.
	* check-init.c (check_init):  Handle TRY_FINALLY_EXPR.
	Simpler handling of TRY_EXPR, which no longer has a finally clause.
	* expr.c (java_lang_expand_expr):  Likewise.
	* java-tree.h (CATCH_EXPR_GET_EXPR):  Removed - no longer needed.
	* parse.h (java_get_catch_block), parse.y:  Removed - no longer needed.
	* parse.y (java_complete_lhs):  Add support for TRY_FIANLLY_EXPR.
	(build_try_statement):  Remove finally parameter and handling.
	(build_try_finally_statement):  New function.
	(patch_try_statement):   No longer need to support finally clause.
	(try_statement):  Update grammar action rules.
	* jcf-write.c (generate_bytecode_insns):  Handle TRY_FINALLY_EXPR.
	Simpler handling of TRY_EXPR, which no longer has a finally clause.

Index: java/java-tree.def
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/java-tree.def,v
retrieving revision 1.11.2.4
diff -u -p -r1.11.2.4 java-tree.def
--- java-tree.def	1998/12/09 23:51:49	1.11.2.4
+++ java-tree.def	1999/02/03 20:57:42
@@ -42,19 +42,13 @@ DEFTREECODE (DEFAULT_EXPR, "default", 'x
 
 /* 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,
Index: java/check-init.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/check-init.c,v
retrieving revision 1.1.2.4
diff -u -p -r1.1.2.4 check-init.c
--- check-init.c	1999/02/02 20:40:43	1.1.2.4
+++ check-init.c	1999/02/03 20:57:42
@@ -543,7 +543,6 @@ check_init (exp, before)
       {
 	tree try_clause = TREE_OPERAND (exp, 0);
 	tree clause = TREE_OPERAND (exp, 1);
-        tree finally = TREE_OPERAND (exp, 2);
 	words save = ALLOC_WORDS (num_current_words);
 	words tmp = ALLOC_WORDS (num_current_words);
 	struct alternatives alt;
@@ -559,16 +558,21 @@ check_init (exp, before)
 	    check_init (catch_clause, tmp);
 	    done_alternative (tmp, &alt);
 	  }
-	if (finally != NULL_TREE)
-	  {
-	    check_init (finally, save);
-	    UNION (alt.combined, alt.combined, save);
-	  }
 	FREE_WORDS (tmp);
 	FREE_WORDS (save);
 	END_ALTERNATIVES (before, alt);
       }
     return;
+
+    case TRY_FINALLY_EXPR:
+      {
+	words tmp = ALLOC_WORDS (num_current_words);
+	COPY (tmp, before);
+	check_init (TREE_OPERAND (exp, 0), tmp);
+	check_init (TREE_OPERAND (exp, 1), before);
+	FREE_WORDS (tmp);
+      }
+      return;
 
     case RETURN_EXPR:
     case THROW_EXPR:
Index: java/expr.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/expr.c,v
retrieving revision 1.82.2.18
diff -u -p -r1.82.2.18 expr.c
--- expr.c	1999/01/25 21:04:28	1.82.2.18
+++ expr.c	1999/02/03 20:57:43
@@ -1746,6 +1746,7 @@ java_lang_expand_expr (exp, target, tmod
 {
   tree current;
   int has_finally_p;
+  rtx op0;
 
   switch (TREE_CODE (exp))
     {
@@ -1869,13 +1870,12 @@ java_lang_expand_expr (exp, target, tmod
       return const0_rtx;
 
     case TRY_EXPR:
-      /* We expand a try[-catch][-finally] block */
+      /* We expand a try[-catch] block */
 
       /* Expand the try block */
       expand_eh_region_start ();
       expand_expr_stmt (TREE_OPERAND (exp, 0));
       expand_start_all_catch ();
-      has_finally_p = (TREE_OPERAND (exp, 2) ? 1 : 0);
 
       /* Expand all catch clauses (EH handlers) */
       for (current = TREE_OPERAND (exp, 1); current; 
@@ -1883,30 +1883,14 @@ java_lang_expand_expr (exp, target, tmod
 	{
 	  extern rtx return_label;
 	  tree type;
-	  /* If we have a finally, the last exception handler is the
-	     one that is supposed to catch everything. */
-	  if (has_finally_p && !TREE_CHAIN (current))
-	    type = NULL_TREE;
-	  else
-	    {
-	      tree catch = java_get_catch_block (current, has_finally_p);
-	      tree decl = BLOCK_EXPR_DECLS (catch);
-	      type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
-	    }
+	  tree catch = TREE_OPERAND (current, 0);
+	  tree decl = BLOCK_EXPR_DECLS (catch);
+	  type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
 	  start_catch_handler (prepare_eh_table_type (type));
 	  expand_expr_stmt (TREE_OPERAND (current, 0));
 
 	  expand_resume_after_catch ();
 	  end_catch_handler ();
-	}
-
-      /* Expand the finally block, if any */
-      if (has_finally_p)
-	{
-	  tree finally = TREE_OPERAND (exp, 2);
-	  if (FINALLY_EXPR_LABEL (finally))
-	    emit_label (label_rtx (FINALLY_EXPR_LABEL (finally)));
-	  expand_expr_stmt (FINALLY_EXPR_BLOCK (finally));
 	}
       expand_end_all_catch ();
       break;
Index: java/java-tree.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/java-tree.h,v
retrieving revision 1.58.2.22
diff -u -p -r1.58.2.22 java-tree.h
--- java-tree.h	1999/01/25 22:07:03	1.58.2.22
+++ java-tree.h	1999/02/03 20:57:43
@@ -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)	\
Index: java/parse.y
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/parse.y,v
retrieving revision 1.43.2.44
diff -u -p -r1.43.2.44 parse.y
--- parse.y	1999/02/02 20:09:17	1.43.2.44
+++ parse.y	1999/02/03 20:57:43
@@ -201,7 +201,8 @@ static tree build_string_concatenation P
 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));
@@ -1613,11 +1614,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);}
 ;
@@ -1666,10 +1670,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; }
 ;
@@ -7587,6 +7588,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;
@@ -10662,92 +10672,23 @@ build_jump_to_finally (block, decl, fina
 }
 
 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
@@ -10758,8 +10699,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
@@ -10772,29 +10711,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));
 
@@ -10828,7 +10752,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))))
@@ -10868,24 +10792,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;
 }
Index: java/parse.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/parse.h,v
retrieving revision 1.33.2.13
diff -u -p -r1.33.2.13 parse.h
--- parse.h	1999/01/29 23:20:37	1.33.2.13
+++ parse.h	1999/02/03 20:57:43
@@ -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
 
Index: java/jcf-write.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/java/jcf-write.c,v
retrieving revision 1.13.2.18
diff -u -p -r1.13.2.18 jcf-write.c
--- jcf-write.c	1999/02/02 20:25:07	1.13.2.18
+++ jcf-write.c	1999/02/03 20:57:43
@@ -2184,24 +2184,17 @@ generate_bytecode_insns (exp, target, st
     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);
@@ -2211,43 +2204,63 @@ generate_bytecode_insns (exp, target, st
 	    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);
+	define_jcf_label (finished_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;
 
-	    /* 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);
-	  }
+	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);
-	if (finally)
-	  emit_jsr (finally_label, state);
       }
       break;
     case THROW_EXPR:


More information about the Gcc-patches mailing list