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]
Other format: [Raw text]

Java: rewrite exception handling logic for bytecode compiler


I found a bytecode file that made gcj fail.  It turns out that the
contorted logic (mine, mostly) that tried to handle exception ranges
was just plain wrong, and could never be made to work reliably.

I've rewritten it.  Now, all exception ranges are associated with a
binding level, so that when we pop a level we wrap the code we've
generated inside that level with one or more TRY_CATCH_EXPRs.  We no
longer have to call maybe_end_try(), and everything is much simpler.

On the downside, it does mean we sometimes have to generate binding
levels with no variables just in order to hold an exception range.  I
don't think that matters much, because we no longer have to check for
end of exception range as well as end of binding level.

The wacko bytecode file is part of an old release of mx4j, and I guess
because it's free software I can could it in as a testcase.  I don't
know about that, though.  I can't find the original source code for
that file, anyway.

Andrew.


2004-06-29  Andrew Haley  <aph@redhat.com>

	* except.c (expand_start_java_handler): Push a new binding level.
	Don't build a TRY_CATCH_EXPR now, we'll do it later.  Call
	register_exception_range() to register where we'll do it.
	(expand_end_java_handler): Remove old bogus code.  Replace with
	new logic that simply builds TRY_CATCH_EXPRs and inserts them at
	the top of the expression we're curently building.
	(maybe_end_try): Delete.
	* decl.c (binding_level.exception_range): New field.
	(clear_binding_level): Add field exception_range.  Reformat.
	(poplevel): Call expand_end_java_handler().
	(poplevel): Call java_add_stmt only if functionbody is false.
	(maybe_poplevels): Don't call maybe_end_try() from here.
	(register_exception_range): New function.
	* java-tree.h (register_exception_range, struct eh_range): Declare.

	* decl.c (end_java_method): Clear no longer used trees in
          function decl.

Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.184
diff -p -2 -c -w -r1.184 decl.c
*** decl.c	27 Jun 2004 18:16:48 -0000	1.184
--- decl.c	29 Jun 2004 15:51:02 -0000
*************** struct binding_level GTY(())
*** 315,318 ****
--- 315,321 ----
      tree stmts;
  
+     /* An exception range associated with this binding level.  */
+     struct eh_range * GTY((skip (""))) exception_range;
+ 
      /* Binding depth at which this level began.  Used only for debugging.  */
      unsigned binding_depth;
*************** static GTY(()) struct binding_level *glo
*** 342,347 ****
  
  static const struct binding_level clear_binding_level
!   = {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
!      NULL_BINDING_LEVEL, LARGEST_PC, 0, NULL_TREE, 0};
  
  #if 0
--- 345,360 ----
  
  static const struct binding_level clear_binding_level
! = {
!     NULL_TREE, /* names */
!     NULL_TREE, /* shadowed */
!     NULL_TREE, /* blocks */
!     NULL_TREE, /* this_lock */
!     NULL_BINDING_LEVEL, /* level_chain */
!     LARGEST_PC, /* end_pc */
!     0, /* start_pc */
!     NULL, /* stmts */
!     NULL, /* exception_range */
!     0, /* binding_depth */
!   };
  
  #if 0
*************** poplevel (int keep, int reverse, int fun
*** 1317,1320 ****
--- 1330,1336 ----
      }
  
+   if (current_binding_level->exception_range)
+     expand_end_java_handler (current_binding_level->exception_range);
+ 
    if (block != 0)
      {
*************** poplevel (int keep, int reverse, int fun
*** 1342,1346 ****
  	  bind =  build (BIND_EXPR, TREE_TYPE (block), BLOCK_VARS (block), 
  			 BLOCK_EXPR_BODY (block), block);
- 
  	  BIND_EXPR_BODY (bind) = current_binding_level->stmts;
  	  
--- 1358,1361 ----
*************** poplevel (int keep, int reverse, int fun
*** 1449,1453 ****
        DECL_SAVED_TREE (current_function_decl) = bind;
      }
!   else if (block)
      {
        if (!block_previously_created)
--- 1464,1470 ----
        DECL_SAVED_TREE (current_function_decl) = bind;
      }
!   else 
!     {
!       if (block)
  	{
  	  if (!block_previously_created)
*************** poplevel (int keep, int reverse, int fun
*** 1466,1469 ****
--- 1483,1487 ----
        if (bind)
  	java_add_stmt (bind);
+     }
  
    if (block)
*************** maybe_poplevels (int pc)
*** 1522,1531 ****
  
    while (current_binding_level->end_pc <= pc)
-     {
-       maybe_end_try (current_binding_level->start_pc, pc);
        poplevel (1, 0, 0);
      }
-   maybe_end_try (0, pc);
- }
  
  /* Terminate any binding which began during the range beginning at
--- 1540,1545 ----
*************** end_java_method (void)
*** 1782,1785 ****
--- 1796,1807 ----
    finish_method (fndecl);
  
+   if (! flag_unit_at_a_time)
+     {
+       /* Nulling these fields when we no longer need them saves
+ 	 memory.  */
+       DECL_SAVED_TREE (fndecl) = NULL;
+       DECL_STRUCT_FUNCTION (fndecl) = NULL;
+       DECL_INITIAL (fndecl) = NULL_TREE;
+     }
    current_function_decl = NULL_TREE;
  }
*************** get_stmts (void)
*** 1930,1933 ****
--- 1952,1969 ----
  }
  
+ /* Register an exception range as belonging to the current binding
+    level.  There may only be one: if there are more, we'll create more
+    binding levels.  However, each range can have multiple handlers,
+    and these are expanded when we call expand_end_java_handler().  */
+ 
+ void
+ register_exception_range (struct eh_range *range, int pc, int end_pc)
+ {
+   if (current_binding_level->exception_range)
+     abort ();
+   current_binding_level->exception_range = range;
+   current_binding_level->end_pc = end_pc;
+   current_binding_level->start_pc = pc;      
+ }
  
  #include "gt-java-decl.h"
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/except.c,v
retrieving revision 1.43
diff -p -2 -c -w -r1.43 except.c
*** except.c	13 May 2004 06:40:34 -0000	1.43
--- except.c	29 Jun 2004 15:51:02 -0000
*************** The Free Software Foundation is independ
*** 41,45 ****
  
  static void expand_start_java_handler (struct eh_range *);
- static void expand_end_java_handler (struct eh_range *);
  static struct eh_range *find_handler_in_range (int, struct eh_range *,
  					       struct eh_range *);
--- 41,44 ----
*************** expand_start_java_handler (struct eh_ran
*** 306,316 ****
  	   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;
  }
--- 305,310 ----
  	   current_pc, range->end_pc);
  #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */
!   pushlevel (0);
!   register_exception_range (range,  range->start_pc, range->end_pc);
    range->expanded = 1;
  }
*************** build_exception_object_ref (tree type)
*** 429,439 ****
  /* If there are any handlers for this range, isssue end of range,
     and then all handler blocks */
! static void
  expand_end_java_handler (struct eh_range *range)
  {  
    tree handler = range->handlers;
-   tree compound = NULL;
  
-   force_poplevels (range->start_pc);  
    for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
      {
--- 423,431 ----
  /* If there are any handlers for this range, isssue end of range,
     and then all handler blocks */
! void
  expand_end_java_handler (struct eh_range *range)
  {  
    tree handler = range->handlers;
  
    for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
      {
*************** expand_end_java_handler (struct eh_range
*** 445,496 ****
  	 gcc-style finally clause.  */
        tree type = TREE_PURPOSE (handler);
- 
        if (type == NULL)
  	type = throwable_type_node;
- 
        type = prepare_eh_table_type (type);
  
-       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 ();
! 	  tree outer;
! 	  tree try_expr;
! 	  compound = range->stmt;
! 	  outer = TREE_OPERAND (compound, 0);
! 	  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;
  	}
      }
--- 437,451 ----
  	 gcc-style finally clause.  */
        tree type = TREE_PURPOSE (handler);
        if (type == NULL)
  	type = throwable_type_node;
        type = prepare_eh_table_type (type);
  
        {
  	tree catch_expr 
  	  = build (CATCH_EXPR, void_type_node, type,
  		   build (GOTO_EXPR, void_type_node, TREE_VALUE (handler)));
! 	tree try_catch_expr = build (TRY_CATCH_EXPR, void_type_node,
! 				     *get_stmts (), catch_expr);	
! 	*get_stmts () = try_catch_expr;
        }
      }
*************** maybe_start_try (int start_pc, int end_p
*** 537,554 ****
  }
  
- /* Emit any end-of-try-range ending at end_pc and starting before
-    start_pc. */
- 
- void
- maybe_end_try (int start_pc, int end_pc)
- {
-   if (! doing_eh (1))
-     return;
- 
-   while (current_range != NULL_EH_RANGE && current_range->end_pc <= end_pc
- 	 && current_range->start_pc >= start_pc)
-     {
-       expand_end_java_handler (current_range);
-       current_range = current_range->outer;
-     }
- }
--- 492,493 ----
Index: java-except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-except.h,v
retrieving revision 1.13
diff -p -2 -c -w -r1.13 java-except.h
*** java-except.h	13 May 2004 06:40:34 -0000	1.13
--- java-except.h	29 Jun 2004 15:51:02 -0000
*************** extern void add_handler (int, int, tree,
*** 69,70 ****
--- 69,71 ----
  extern void handle_nested_ranges (void);
  extern void expand_resume_after_catch (void);
+ extern void expand_end_java_handler (struct eh_range *);
Index: java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.201
diff -p -2 -c -w -r1.201 java-tree.h
*** java-tree.h	29 May 2004 05:11:41 -0000	1.201
--- java-tree.h	29 Jun 2004 15:51:04 -0000
*************** struct lang_type GTY(())
*** 1118,1121 ****
--- 1118,1124 ----
  #define SEARCH_VISIBLE        4
  
+ /* Defined in java-except.h  */
+ struct eh_range;
+ 
  extern void java_parse_file (int);
  extern bool java_mark_addressable (tree);
*************** extern tree java_add_stmt (tree);
*** 1346,1349 ****
--- 1349,1353 ----
  extern tree java_add_local_var (tree decl);
  extern tree *get_stmts (void);
+ extern void register_exception_range(struct eh_range *, int, int);
  
  extern void finish_method (tree);


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