========================================================================= */
+#ifndef DWARF2_UNWIND_INFO
/* Holds the pc for doing "throw" */
static tree saved_pc;
extern int throw_used;
+#endif
+
extern rtx catch_clauses;
extern tree const_ptr_type_node;
pop_lang_context ();
+#ifndef DWARF2_UNWIND_INFO
d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node);
TREE_PUBLIC (d) = 1;
DECL_EXTERNAL (d) = 1;
DECL_ARTIFICIAL (d) = 1;
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
saved_pc = d;
+#endif
/* If we use setjmp/longjmp EH, arrange for all cleanup actions to
be protected with __terminate. */
if (! doing_eh (1))
return;
- /* If we are not doing setjmp/longjmp EH, because we are reordered
- out of line, we arrange to rethrow in the outer context so as to
- skip through the terminate region we are nested in, should we
- encounter an exception in the catch handler. We also need to do
- this because we are not physically within the try block, if any,
- that contains this catch block.
-
- Matches the end in expand_end_catch_block. */
- if (! exceptions_via_longjmp)
- expand_eh_region_start ();
-
/* Create a binding level for the eh_info and the exception object
cleanup. */
pushlevel (0);
expand_end_bindings (getdecls (), kept_level_p (), 0);
poplevel (kept_level_p (), 1, 0);
- if (! exceptions_via_longjmp)
- {
- /* If we are not doing setjmp/longjmp EH, we need an extra
- region around the whole catch block to skip through the
- terminate region we are nested in. */
-
- tree t = make_node (RTL_EXPR);
- TREE_TYPE (t) = void_type_node;
- RTL_EXPR_RTL (t) = const0_rtx;
- TREE_SIDE_EFFECTS (t) = 1;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (t);
-
- expand_internal_throw (outer_context_label_stack->u.rlabel);
-
- do_pending_stack_adjust ();
- RTL_EXPR_SEQUENCE (t) = get_insns ();
- end_sequence ();
-
- /* For the rethrow region. */
- expand_eh_region_end (t);
- }
-
/* Fall to outside the try statement when done executing handler and
we fall off end of handler. This is jump Lresume in the
documentation. */
expand_goto (top_label_entry (&caught_return_label_stack));
- expand_leftover_cleanups ();
-
/* label we emit to jump to if this catch block didn't match. */
/* This the closing } in the `if (eq) {' of the documentation. */
emit_label (pop_label_entry (&false_label_stack));
expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
- if (exceptions_via_longjmp)
- emit_throw ();
- else
- {
- /* This is the label that represents where in the code we were, when
- we got an exception. This needs to be updated when we rethrow an
- exception, so that the matching routine knows to search out. */
- label = gen_label_rtx ();
- emit_label (label);
-
- expand_internal_throw (label);
- }
+ expand_internal_throw ();
}
/* Build a throw expression. */
/* One to protect cleanup actions with a handler that calls
__terminate, zero otherwise. */
-int protect_cleanup_actions_with_terminate = 0;
+int protect_cleanup_actions_with_terminate;
/* A list of labels used for exception handlers. Created by
find_exception_handler_labels for the optimization passes. */
struct label_node *caught_return_label_stack = NULL;
-/* Keeps track of the label used as the context of a throw to rethrow an
- exception to the outer exception region. */
-
-struct label_node *outer_context_label_stack = NULL;
-
/* A random data area for the front end's own use. */
struct label_node *false_label_stack = NULL;
+#ifndef DWARF2_UNWIND_INFO
/* The rtx and the tree for the saved PC value. */
rtx eh_saved_pc_rtx;
tree eh_saved_pc;
+#endif
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
+static void expand_rethrow PROTO((rtx));
+
\f
/* Various support routines to manipulate the various data structures
used by the exception handling code. */
note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
NOTE_BLOCK_NUMBER (note)
= CODE_LABEL_NUMBER (entry->exception_handler_label);
- if (exceptions_via_longjmp == 0)
+ if (exceptions_via_longjmp == 0
+ /* We share outer_context between regions; only emit it once. */
+ && INSN_UID (entry->outer_context) == 0)
{
rtx label;
/* Emit a label marking the end of this exception region that
is used for rethrowing into the outer context. */
emit_label (entry->outer_context);
+ expand_internal_throw ();
- /* Put in something that takes up space, as otherwise the end
- address for this EH region could have the exact same address as
- its outer region. This would cause us to miss the fact that
- resuming exception handling with this PC value would be inside
- the outer region. */
- emit_insn (gen_nop ());
- emit_barrier ();
emit_label (label);
}
expand_fixup_region_end (cleanup)
tree cleanup;
{
- tree t;
struct eh_node *node;
- int yes;
if (! doing_eh (0) || exceptions_via_longjmp)
return;
if (node == 0)
abort ();
- yes = suspend_momentary ();
-
- t = build (RTL_EXPR, void_type_node, NULL_RTX, const0_rtx);
- TREE_SIDE_EFFECTS (t) = 1;
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (t);
- expand_internal_throw (node->entry->outer_context);
- do_pending_stack_adjust ();
- RTL_EXPR_SEQUENCE (t) = get_insns ();
- end_sequence ();
+ ehstack.top->entry->outer_context = node->entry->outer_context;
- resume_momentary (yes);
-
- expand_eh_region_end (t);
+ /* Just rethrow. size_zero_node is just a NOP. */
+ expand_eh_region_end (size_zero_node);
}
/* If we are using the setjmp/longjmp EH codegen method, we emit a
emit_barrier ();
}
-/* An internal throw with an indirect CONTEXT we want to throw from.
- CONTEXT evaluates to the context of the throw. */
-
-static void
-expand_internal_throw_indirect (context)
- rtx context;
-{
- assemble_external (eh_saved_pc);
- emit_move_insn (eh_saved_pc_rtx, context);
- emit_throw ();
-}
-
-/* An internal throw with a direct CONTEXT we want to throw from.
- CONTEXT must be a label; its address will be used as the context of
- the throw. */
+/* Throw the current exception. If appropriate, this is done by jumping
+ to the next handler. */
void
-expand_internal_throw (context)
- rtx context;
+expand_internal_throw ()
{
- expand_internal_throw_indirect (gen_rtx (LABEL_REF, Pmode, context));
+#ifndef DWARF2_UNWIND_INFO
+ if (! exceptions_via_longjmp)
+ {
+ rtx label = gen_label_rtx ();
+ emit_label (label);
+ label = gen_rtx (LABEL_REF, Pmode, label);
+ assemble_external (eh_saved_pc);
+ emit_move_insn (eh_saved_pc_rtx, label);
+ }
+#endif
+ emit_throw ();
}
/* Called from expand_exception_blocks and expand_end_catch_block to
prev = get_last_insn ();
if (prev == NULL || GET_CODE (prev) != BARRIER)
- {
- if (exceptions_via_longjmp)
- emit_throw ();
- else
- {
- /* The below can be optimized away, and we could just
- fall into the next EH handler, if we are certain they
- are nested. */
- /* Emit code to throw to the outer context if we fall off
- the end of the handler. */
- expand_internal_throw (entry->outer_context);
- }
- }
+ /* Emit code to throw to the outer context if we fall off
+ the end of the handler. */
+ expand_rethrow (entry->outer_context);
do_pending_stack_adjust ();
free (entry);
{
struct eh_entry *entry;
tree label;
+ rtx outer_context;
if (! doing_eh (1))
return;
- push_label_entry (&outer_context_label_stack,
- ehstack.top->entry->outer_context, NULL_TREE);
+ outer_context = ehstack.top->entry->outer_context;
/* End the try block. */
expand_eh_region_end (integer_zero_node);
This is Lresume in the documention. */
expand_label (label);
- if (exceptions_via_longjmp == 0)
- {
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
- }
-
/* Push the label that points to where normal flow is resumed onto
the top of the label stack. */
push_label_entry (&caught_return_label_stack, NULL_RTX, label);
prev = get_last_insn ();
if (prev == NULL || GET_CODE (prev) != BARRIER)
- {
- if (exceptions_via_longjmp)
- emit_throw ();
- else
- {
- /* Code to throw out to outer context when we fall off end
- of the handler. We can't do this here for catch blocks,
- so it's done in expand_end_all_catch instead.
-
- The below can be optimized away (and we could just fall
- into the next EH handler) if we are certain they are
- nested. */
+ /* Code to throw out to outer context when we fall off end
+ of the handler. We can't do this here for catch blocks,
+ so it's done in expand_end_all_catch instead. */
+ expand_rethrow (entry->outer_context);
- expand_internal_throw (entry->outer_context);
- }
- }
do_pending_stack_adjust ();
free (entry);
}
+
+ /* If we are not doing setjmp/longjmp EH, because we are reordered
+ out of line, we arrange to rethrow in the outer context. We need to
+ do this because we are not physically within the region, if any, that
+ logically contains this catch block. */
+ if (! exceptions_via_longjmp)
+ {
+ expand_eh_region_start ();
+ ehstack.top->entry->outer_context = outer_context;
+ }
}
/* Finish up the catch block. At this point all the insns for the
void
expand_end_all_catch ()
{
- rtx new_catch_clause;
+ rtx new_catch_clause, outer_context;
if (! doing_eh (1))
return;
- if (exceptions_via_longjmp)
- emit_throw ();
- else
- {
- /* Code to throw out to outer context, if we fall off end of catch
- handlers. This is rethrow (Lresume, same id, same obj) in the
- documentation. We use Lresume because we know that it will throw
- to the correct context.
-
- In other words, if the catch handler doesn't exit or return, we
- do a "throw" (using the address of Lresume as the point being
- thrown from) so that the outer EH region can then try to process
- the exception. */
+ outer_context = ehstack.top->entry->outer_context;
+ if (! exceptions_via_longjmp)
+ /* Finish the rethrow region. size_zero_node is just a NOP. */
+ expand_eh_region_end (size_zero_node);
+
+ /* Code to throw out to outer context, if we fall off end of catch
+ handlers. This is rethrow (Lresume, same id, same obj) in the
+ documentation. We use Lresume because we know that it will throw
+ to the correct context.
- expand_internal_throw (outer_context_label_stack->u.rlabel);
- }
+ In other words, if the catch handler doesn't exit or return, we
+ do a "throw" (using the address of Lresume as the point being
+ thrown from) so that the outer EH region can then try to process
+ the exception. */
+ expand_rethrow (outer_context);
/* Now we have the complete catch sequence. */
new_catch_clause = get_insns ();
/* This level of catch blocks is done, so set up the successful
catch jump label for the next layer of catch blocks. */
pop_label_entry (&caught_return_label_stack);
- pop_label_entry (&outer_context_label_stack);
/* Add the new sequence of catches to the main one for this function. */
push_to_sequence (catch_clauses);
/* Here we fall through into the continuation code. */
}
+/* Rethrow from the outer context LABEL. */
+
+static void
+expand_rethrow (label)
+ rtx label;
+{
+ if (exceptions_via_longjmp)
+ emit_throw ();
+ else
+ emit_jump (label);
+}
+
/* End all the pending exception regions on protect_list. The handlers
will be emitted when expand_leftover_cleanups is invoked. */
current context is saved. */
tree type = build_pointer_type (make_node (VOID_TYPE));
+#ifndef DWARF2_UNWIND_INFO
eh_saved_pc = build_decl (VAR_DECL, get_identifier ("__eh_pc"), type);
DECL_EXTERNAL (eh_saved_pc) = 1;
TREE_PUBLIC (eh_saved_pc) = 1;
make_decl_rtl (eh_saved_pc, NULL_PTR, 1);
eh_saved_pc_rtx = DECL_RTL (eh_saved_pc);
+#endif
}
/* Initialize the per-function EH information. */