For PR java/4766:
authorTom Tromey <tromey@redhat.com>
Fri, 21 Dec 2001 05:13:43 +0000 (05:13 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Fri, 21 Dec 2001 05:13:43 +0000 (05:13 +0000)
* jcf-write.c (generate_bytecode_insns) [TRY_FINALLY_EXPR]: Handle
case where `finally' clause can't complete normally.

From-SVN: r48232

gcc/java/ChangeLog
gcc/java/jcf-write.c

index 666c441fcbcfae90adeded28709f46cc6e090495..110454603964c7d8435cc073b889f8248860c1d5 100644 (file)
@@ -1,3 +1,9 @@
+2001-12-20  Tom Tromey  <tromey@redhat.com>
+
+       For PR java/4766:
+       * jcf-write.c (generate_bytecode_insns) [TRY_FINALLY_EXPR]: Handle
+       case where `finally' clause can't complete normally.
+
 2001-12-20  Tom Tromey  <tromey@redhat.com>
 
        Fixes PR java/5057:
index c6de1fe9b47e1a80ae485239c18bd1fce8f88cc2..f6c0bfa71de2cf6e16b19d09294e723283eb96a8 100644 (file)
@@ -1348,7 +1348,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
     abort ();
 }
 
-/* Call pending cleanups i.e. those for surrounding TRY_FINAL_EXPRs.
+/* Call pending cleanups i.e. those for surrounding TRY_FINALLY_EXPRs.
    but only as far out as LIMIT (since we are about to jump to the
    emit label that is LIMIT). */
 
@@ -1683,8 +1683,8 @@ generate_bytecode_insns (exp, target, state)
           1.  the switch_expression (the value used to select the correct case);
           2.  the switch_body;
           3.  the switch_instruction (the tableswitch/loopupswitch instruction.).
-          After code generation, we will re-order then in the order 1, 3, 2.
-          This is to avoid an extra GOTOs. */
+          After code generation, we will re-order them in the order 1, 3, 2.
+          This is to avoid any extra GOTOs. */
        struct jcf_switch_state sw_state;
        struct jcf_block *expression_last; /* Last block of the switch_expression. */
        struct jcf_block *body_last; /* Last block of the switch_body. */
@@ -2298,7 +2298,8 @@ generate_bytecode_insns (exp, target, state)
          {
            tree catch_clause = TREE_OPERAND (clause, 0);
            tree exception_decl = BLOCK_EXPR_DECLS (catch_clause);
-           struct jcf_handler *handler = alloc_handler (start_label, end_label, state);
+           struct jcf_handler *handler = alloc_handler (start_label,
+                                                        end_label, state);
            if (exception_decl == NULL_TREE)
              handler->type = NULL_TREE;
            else
@@ -2314,8 +2315,8 @@ generate_bytecode_insns (exp, target, state)
 
     case TRY_FINALLY_EXPR:
       {
-       struct jcf_block *finished_label,
-         *finally_label, *start_label, *end_label;
+       struct jcf_block *finished_label = NULL;
+       struct jcf_block *finally_label, *start_label, *end_label;
        struct jcf_handler *handler;
        tree try_block = TREE_OPERAND (exp, 0);
        tree finally = TREE_OPERAND (exp, 1);
@@ -2325,15 +2326,26 @@ generate_bytecode_insns (exp, 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++;
+       /* If the `finally' clause can complete normally, we emit it
+          as a subroutine and let the other clauses call it via
+          `jsr'.  If it can't complete normally, then we simply emit
+          `goto's directly to it.  */
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           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;
+
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           if (state->labeled_blocks != finally_label)
+             abort();
+           state->labeled_blocks = finally_label->next;
+         }
        end_label = get_jcf_label_here (state);
 
        if (end_label == start_label)
@@ -2344,43 +2356,75 @@ generate_bytecode_insns (exp, target, state)
            break;
          }
 
-       return_link = build_decl (VAR_DECL, NULL_TREE,
-                                 return_address_type_node);
-       finished_label = gen_jcf_label (state);
-
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           return_link = build_decl (VAR_DECL, NULL_TREE,
+                                     return_address_type_node);
+           finished_label = gen_jcf_label (state);
+         }
 
        if (CAN_COMPLETE_NORMALLY (try_block))
          {
-           emit_jsr (finally_label, state);
-           emit_goto (finished_label, state);
+           if (CAN_COMPLETE_NORMALLY (finally))
+             {
+               emit_jsr (finally_label, state);
+               emit_goto (finished_label, state);
+             }
+           else
+             emit_goto (finally_label, state);
          }
 
-       /* Handle exceptions. */
+       /* Handle exceptions.  */
 
        exception_type = build_pointer_type (throwable_type_node);
-       exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
-       localvar_alloc (return_link, state);
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           /* We're going to generate a subroutine, so we'll need to
+              save and restore the exception around the `jsr'.  */ 
+           exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type);
+           localvar_alloc (return_link, state);
+         }
        handler = alloc_handler (start_label, end_label, state);
        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);
-
-       /* The finally block.  First save return PC into return_link. */
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           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);
+         }
+       else
+         {
+           /* We're not generating a subroutine.  In this case we can
+              simply have the exception handler pop the exception and
+              then fall through to the `finally' block.  */
+           NOTE_PUSH (1);
+           emit_pop (1, state);
+           NOTE_POP (1);
+         }
+
+       /* The finally block.  If we're generating a subroutine, first
+          save return PC into return_link.  Otherwise, just generate
+          the code for the `finally' block.  */
        define_jcf_label (finally_label, state);
-       NOTE_PUSH (1);
-       emit_store (return_link, state);
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           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 (exception_decl, state);
-       localvar_free (return_link, state);
-       define_jcf_label (finished_label, state);
+       if (CAN_COMPLETE_NORMALLY (finally))
+         {
+           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);
+         }
       }
       break;
     case THROW_EXPR: