/* Implements exception handling.
- Copyright (C) 1989, 1992-1999 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
This file is part of GNU CC.
#include "toplev.h"
#include "intl.h"
#include "obstack.h"
+#include "ggc.h"
+#include "tm_p.h"
/* One to use setjmp/longjmp method of generating code for exception
handling. */
/* Prototypes for local functions. */
-static void push_eh_entry PROTO((struct eh_stack *));
-static struct eh_entry * pop_eh_entry PROTO((struct eh_stack *));
-static void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *));
-static struct eh_entry * dequeue_eh_entry PROTO((struct eh_queue *));
-static rtx call_get_eh_context PROTO((void));
-static void start_dynamic_cleanup PROTO((tree, tree));
-static void start_dynamic_handler PROTO((void));
-static void expand_rethrow PROTO((rtx));
-static void output_exception_table_entry PROTO((FILE *, int));
-static int can_throw PROTO((rtx));
-static rtx scan_region PROTO((rtx, int, int *));
-static void eh_regs PROTO((rtx *, rtx *, rtx *, int));
-static void set_insn_eh_region PROTO((rtx *, int));
+static void push_eh_entry PARAMS ((struct eh_stack *));
+static struct eh_entry * pop_eh_entry PARAMS ((struct eh_stack *));
+static void enqueue_eh_entry PARAMS ((struct eh_queue *, struct eh_entry *));
+static struct eh_entry * dequeue_eh_entry PARAMS ((struct eh_queue *));
+static rtx call_get_eh_context PARAMS ((void));
+static void start_dynamic_cleanup PARAMS ((tree, tree));
+static void start_dynamic_handler PARAMS ((void));
+static void expand_rethrow PARAMS ((rtx));
+static void output_exception_table_entry PARAMS ((FILE *, int));
+static rtx scan_region PARAMS ((rtx, int, int *));
+static void eh_regs PARAMS ((rtx *, rtx *, rtx *, int));
+static void set_insn_eh_region PARAMS ((rtx *, int));
#ifdef DONT_USE_BUILTIN_SETJMP
-static void jumpif_rtx PROTO((rtx, rtx));
+static void jumpif_rtx PARAMS ((rtx, rtx));
#endif
+static void find_exception_handler_labels_1 PARAMS ((rtx));
+static void mark_eh_node PARAMS ((struct eh_node *));
+static void mark_eh_stack PARAMS ((struct eh_stack *));
+static void mark_eh_queue PARAMS ((struct eh_queue *));
+static void mark_tree_label_node PARAMS ((struct label_node *));
+static void mark_func_eh_entry PARAMS ((void *));
+static rtx create_rethrow_ref PARAMS ((int));
+static void push_entry PARAMS ((struct eh_stack *, struct eh_entry*));
+static void receive_exception_label PARAMS ((rtx));
+static int new_eh_region_entry PARAMS ((int, rtx));
+static int find_func_region PARAMS ((int));
+static int find_func_region_from_symbol PARAMS ((rtx));
+static void clear_function_eh_region PARAMS ((void));
+static void process_nestinfo PARAMS ((int, eh_nesting_info *, int *));
+rtx expand_builtin_return_addr PARAMS ((enum built_in_function, int, rtx));
+static void emit_cleanup_handler PARAMS ((struct eh_entry *));
+static int eh_region_from_symbol PARAMS ((rtx));
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
\f
/* Various support routines to manipulate the various data structures
used by the exception handling code. */
extern struct obstack permanent_obstack;
/* Generate a SYMBOL_REF for rethrow to use */
+
static rtx
create_rethrow_ref (region_num)
int region_num;
{
rtx def;
- char *ptr;
+ const char *ptr;
char buf[60];
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num);
- ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf));
+ ptr = ggc_strdup (buf);
def = gen_rtx_SYMBOL_REF (Pmode, ptr);
SYMBOL_REF_NEED_ADJUST (def) = 1;
- pop_obstacks ();
return def;
}
return (*stack)->u.tlabel;
}
-/* get an exception label. These must be on the permanent obstack */
+/* Get an exception label. */
rtx
gen_exception_label ()
else
entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
entry->rethrow_label = entry->outer_context;
+ entry->goto_entry_p = 0;
node->entry = entry;
node->chain = stack->top;
stack->top = node;
}
-/* push an existing entry onto a stack. */
+/* Push an existing entry onto a stack. */
+
static void
push_entry (stack, entry)
struct eh_stack *stack;
node->chain = NULL;
if (queue->head == NULL)
- {
- queue->head = node;
- }
+ queue->head = node;
else
- {
- queue->tail->chain = node;
- }
+ queue->tail->chain = node;
queue->tail = node;
}
receive_exception_label (handler_label)
rtx handler_label;
{
+ rtx around_label = NULL_RTX;
+
+ if (! flag_new_exceptions || exceptions_via_longjmp)
+ {
+ around_label = gen_label_rtx ();
+ emit_jump (around_label);
+ emit_barrier ();
+ }
+
emit_label (handler_label);
-#ifdef HAVE_exception_receiver
if (! exceptions_via_longjmp)
- if (HAVE_exception_receiver)
- emit_insn (gen_exception_receiver ());
+ {
+#ifdef HAVE_exception_receiver
+ if (HAVE_exception_receiver)
+ emit_insn (gen_exception_receiver ());
+ else
#endif
-
#ifdef HAVE_nonlocal_goto_receiver
- if (! exceptions_via_longjmp)
- if (HAVE_nonlocal_goto_receiver)
- emit_insn (gen_nonlocal_goto_receiver ());
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+ else
+#endif
+ { /* Nothing */ }
+ }
+ else
+ {
+#ifndef DONT_USE_BUILTIN_SETJMP
+ expand_builtin_setjmp_receiver (handler_label);
#endif
+ }
+
+ if (around_label)
+ emit_label (around_label);
}
{
int range_number; /* EH region number from EH NOTE insn's. */
rtx rethrow_label; /* Label for rethrow. */
- int rethrow_ref; /* Is rethrow referenced? */
+ int rethrow_ref; /* Is rethrow_label referenced? */
+ int emitted; /* 1 if this entry has been emitted in assembly file. */
struct handler_info *handlers;
};
#define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X)
-/* Add a new eh_entry for this function, and base it off of the information
- in the EH_ENTRY parameter. A NULL parameter is invalid.
- OUTER_CONTEXT is a label which is used for rethrowing. The number
- returned is an number which uniquely identifies this exception range. */
+/* Add a new eh_entry for this function. The number returned is an
+ number which uniquely identifies this exception range. */
static int
new_eh_region_entry (note_eh_region, rethrow)
if (num_func_eh_entries == 0)
{
function_eh_regions =
- (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
+ (struct func_eh_entry *) xmalloc (SIZE_FUNC_EH (50));
num_func_eh_entries = 50;
}
else
{
num_func_eh_entries = num_func_eh_entries * 3 / 2;
function_eh_regions = (struct func_eh_entry *)
- realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
+ xrealloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
}
}
function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
else
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
function_eh_regions[current_func_eh_entry].handlers = NULL;
-
+ function_eh_regions[current_func_eh_entry].emitted = 0;
+
return current_func_eh_entry++;
}
{
struct handler_info *last;
+ /* If find_func_region returns -1, callers might attempt to pass us
+ this region number. If that happens, something has gone wrong;
+ -1 is never a valid region. */
+ if (region == -1)
+ abort ();
+
newhandler->next = NULL;
last = function_eh_regions[region].handlers;
if (last == NULL)
return 0;
max_ptr = 100;
- ptr = (void **)malloc (max_ptr * sizeof (void *));
-
- if (ptr == NULL)
- return 0;
+ ptr = (void **) xmalloc (max_ptr * sizeof (void *));
for (x = 0 ; x < current_func_eh_entry; x++)
{
if (n_ptr >= max_ptr)
{
max_ptr += max_ptr / 2;
- ptr = (void **)realloc (ptr, max_ptr * sizeof (void *));
- if (ptr == NULL)
- return 0;
+ ptr = (void **) xrealloc (ptr, max_ptr * sizeof (void *));
}
ptr[n_ptr] = val;
n_ptr++;
}
}
}
+
+ if (n_ptr == 0)
+ {
+ free (ptr);
+ ptr = NULL;
+ }
*array = ptr;
return n_ptr;
}
void *typeinfo;
{
struct handler_info* ptr;
- ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
+ ptr = (struct handler_info *) xmalloc (sizeof (struct handler_info));
ptr->handler_label = handler;
ptr->handler_number = CODE_LABEL_NUMBER (handler);
ptr->type_info = typeinfo;
/* Find the index in function_eh_regions associated with a NOTE region. If
- the region cannot be found, a -1 is returned. This should never happen! */
+ the region cannot be found, a -1 is returned. */
-int
+static int
find_func_region (insn_region)
int insn_region;
{
get_first_handler (region)
int region;
{
- return function_eh_regions[find_func_region (region)].handlers;
+ int r = find_func_region (region);
+ if (r == -1)
+ abort ();
+ return function_eh_regions[r].handlers;
}
/* Clean out the function_eh_region table and free all memory */
next = ptr->next;
free (ptr);
}
- free (function_eh_regions);
+ if (function_eh_regions)
+ free (function_eh_regions);
num_func_eh_entries = 0;
current_func_eh_entry = 0;
}
/* Given a rethrow symbol, find the EH region number this is for. */
-int
+
+static int
eh_region_from_symbol (sym)
rtx sym;
{
return -1;
}
+/* Like find_func_region, but using the rethrow symbol for the region
+ rather than the region number itself. */
+
+static int
+find_func_region_from_symbol (sym)
+ rtx sym;
+{
+ return find_func_region (eh_region_from_symbol (sym));
+}
/* When inlining/unrolling, we have to map the symbols passed to
__rethrow as well. This performs the remap. If a symbol isn't foiund,
the original one is returned. This is not an efficient routine,
so don't call it on everything!! */
+
rtx
rethrow_symbol_map (sym, map)
rtx sym;
rtx (*map) PARAMS ((rtx));
{
int x, y;
+
+ if (! flag_new_exceptions)
+ return sym;
+
for (x = 0; x < current_func_eh_entry; x++)
if (function_eh_regions[x].rethrow_label == sym)
{
return sym;
}
+/* Returns nonzero if the rethrow label for REGION is referenced
+ somewhere (i.e. we rethrow out of REGION or some other region
+ masquerading as REGION). */
+
int
rethrow_used (region)
int region;
{
expand_eh_region_start ();
- /* Make sure the entry is on the correct obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
/* Because this is a cleanup action, we may have to protect the handler
with __terminate. */
handler = protect_with_terminate (handler);
- protect_list = tree_cons (NULL_TREE, handler, protect_list);
- pop_obstacks ();
+ /* For backwards compatibility, we allow callers to omit calls to
+ begin_protect_partials for the outermost region. So, we must
+ explicitly do so here. */
+ if (!protect_list)
+ begin_protect_partials ();
+
+ /* Add this entry to the front of the list. */
+ TREE_VALUE (protect_list)
+ = tree_cons (NULL_TREE, handler, TREE_VALUE (protect_list));
}
/* Emit code to get EH context to current function. */
{
tree fntype;
fn = get_identifier ("__get_eh_context");
- push_obstacks_nochange ();
- end_temporary_allocation ();
fntype = build_pointer_type (build_pointer_type
(build_pointer_type (void_type_node)));
fntype = build_function_type (fntype, NULL_TREE);
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
TREE_READONLY (fn) = 1;
- make_decl_rtl (fn, NULL_PTR, 1);
+ make_decl_rtl (fn, NULL_PTR);
assemble_external (fn);
- pop_obstacks ();
+
+ ggc_add_tree_root (&fn, 1);
}
expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
start_dynamic_handler ()
{
rtx dhc, dcc;
- rtx x, arg, buf;
+ rtx arg, buf;
int size;
#ifndef DONT_USE_BUILTIN_SETJMP
/* The number of Pmode words for the setjmp buffer, when using the
- builtin setjmp/longjmp, see expand_builtin, case
- BUILT_IN_LONGJMP. */
- size = 5;
+ builtin setjmp/longjmp, see expand_builtin, case BUILT_IN_LONGJMP. */
+ /* We use 2 words here before calling expand_builtin_setjmp.
+ expand_builtin_setjmp uses 2 words, and then calls emit_stack_save.
+ emit_stack_save needs space of size STACK_SAVEAREA_MODE (SAVE_NONLOCAL).
+ Subtract one, because the assign_stack_local call below adds 1. */
+ size = (2 + 2 + (GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
+ / GET_MODE_SIZE (Pmode))
+ - 1);
#else
#ifdef JMP_BUF_SIZE
size = JMP_BUF_SIZE;
buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
#ifdef DONT_USE_BUILTIN_SETJMP
- x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
- buf, Pmode);
- /* If we come back here for a catch, transfer control to the handler. */
- jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
-#else
{
- /* A label to continue execution for the no exception case. */
- rtx noex = gen_label_rtx();
- x = expand_builtin_setjmp (buf, NULL_RTX, noex,
- ehstack.top->entry->exception_handler_label);
- emit_label (noex);
+ rtx x;
+ x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST,
+ TYPE_MODE (integer_type_node), 1,
+ buf, Pmode);
+ /* If we come back here for a catch, transfer control to the handler. */
+ jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
}
+#else
+ expand_builtin_setjmp_setup (buf,
+ ehstack.top->entry->exception_handler_label);
#endif
/* We are committed to this, so update the handler chain. */
/* is the second argument 2? */
&& TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
- && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
- && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
+ && compare_tree_int (TREE_VALUE (args), 2) == 0
/* Make sure there are no other arguments. */
&& TREE_CHAIN (args) == NULL_TREE)
/* We need a new block to record the start and end of the
dynamic handler chain. We also want to prevent jumping into
a try block. */
- expand_start_bindings (0);
+ expand_start_bindings (2);
/* But we don't need or want a new temporary level. */
pop_temp_slots ();
push_eh_entry (&ehstack);
note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
- NOTE_BLOCK_NUMBER (note)
+ NOTE_EH_HANDLER (note)
= CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
if (exceptions_via_longjmp)
start_dynamic_handler ();
tree handler;
{
struct eh_entry *entry;
+ struct eh_node *node;
rtx note;
int ret, r;
entry = pop_eh_entry (&ehstack);
note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
- ret = NOTE_BLOCK_NUMBER (note)
+ ret = NOTE_EH_HANDLER (note)
= CODE_LABEL_NUMBER (entry->exception_handler_label);
if (exceptions_via_longjmp == 0 && ! flag_new_exceptions
/* We share outer_context between regions; only emit it once. */
entry->finalization = handler;
/* create region entry in final exception table */
- r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
+ r = new_eh_region_entry (NOTE_EH_HANDLER (note), entry->rethrow_label);
- enqueue_eh_entry (&ehqueue, entry);
+ enqueue_eh_entry (ehqueue, entry);
/* If we have already started ending the bindings, don't recurse. */
if (is_eh_region ())
expand_end_bindings (NULL_TREE, 0, 0);
}
+
+ /* Go through the goto handlers in the queue, emitting their
+ handlers if we now have enough information to do so. */
+ for (node = ehqueue->head; node; node = node->chain)
+ if (node->entry->goto_entry_p
+ && node->entry->outer_context == entry->rethrow_label)
+ emit_cleanup_handler (node->entry);
+
+ /* We can't emit handlers for goto entries until their scopes are
+ complete because we don't know where they need to rethrow to,
+ yet. */
+ if (entry->finalization != integer_zero_node
+ && (!entry->goto_entry_p
+ || find_func_region_from_symbol (entry->outer_context) != -1))
+ emit_cleanup_handler (entry);
}
/* End the EH region for a goto fixup. We only need them in the region-based
return;
expand_eh_region_start ();
+ /* Mark this entry as the entry for a goto. */
+ ehstack.top->entry->goto_entry_p = 1;
}
/* End the EH region for a goto fixup. CLEANUP is the cleanup we just
for (node = ehstack.top; node && node->entry->finalization != cleanup; )
node = node->chain;
if (node == 0)
- for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+ for (node = ehqueue->head; node && node->entry->finalization != cleanup; )
node = node->chain;
if (node == 0)
abort ();
and we could get an infinte loop when it tried to rethrow, or just
generally incorrect execution following a throw. */
- dont_issue = ((INSN_UID (node->entry->outer_context) == 0)
- && (ehstack.top->entry != node->entry));
+ if (flag_new_exceptions)
+ dont_issue = 0;
+ else
+ dont_issue = ((INSN_UID (node->entry->outer_context) == 0)
+ && (ehstack.top->entry != node->entry));
ehstack.top->entry->outer_context = node->entry->outer_context;
}
/* If we are using the setjmp/longjmp EH codegen method, we emit a
- call to __sjthrow.
-
- Otherwise, we emit a call to __throw and note that we threw
- something, so we know we need to generate the necessary code for
- __throw.
-
- Before invoking throw, the __eh_pc variable must have been set up
- to contain the PC being thrown from. This address is used by
- __throw to determine which exception region (if any) is
- responsible for handling the exception. */
+ call to __sjthrow. Otherwise, we emit a call to __throw. */
void
emit_throw ()
{
struct eh_entry *entry;
- while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
+ for (entry = dequeue_eh_entry (ehqueue);
+ entry;
+ entry = dequeue_eh_entry (ehqueue))
{
- rtx prev;
-
- /* A leftover try block. Shouldn't be one here. */
+ /* A leftover try block. Shouldn't be one here. */
if (entry->finalization == integer_zero_node)
abort ();
- /* Output the label for the start of the exception handler. */
-
- receive_exception_label (entry->exception_handler_label);
-
- /* register a handler for this cleanup region */
- add_new_handler (
- find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
- get_new_handler (entry->exception_handler_label, NULL));
-
- /* And now generate the insns for the handler. */
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- prev = get_last_insn ();
- if (prev == NULL || GET_CODE (prev) != BARRIER)
- /* 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);
}
}
rtx call_rtx, rtime_address;
if (catchstack.top->entry->false_label != NULL_RTX)
- fatal ("Compiler Bug: Never issued previous false_label");
+ {
+ error ("Never issued previous false_label");
+ abort ();
+ }
catchstack.top->entry->false_label = gen_exception_label ();
rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
/* Now issue the call, and branch around handler if needed */
call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX,
- 0, SImode, 1, rtime_address, Pmode);
+ LCT_NORMAL,
+ TYPE_MODE (integer_type_node),
+ 1, rtime_address, Pmode);
/* Did the function return true? */
emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX,
catchstack.top->entry->false_label = NULL_RTX;
}
+/* Save away the current ehqueue. */
+
+void
+push_ehqueue ()
+{
+ struct eh_queue *q;
+ q = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue));
+ q->next = ehqueue;
+ ehqueue = q;
+}
+
+/* Restore a previously pushed ehqueue. */
+
+void
+pop_ehqueue ()
+{
+ struct eh_queue *q;
+ expand_leftover_cleanups ();
+ q = ehqueue->next;
+ free (ehqueue);
+ ehqueue = q;
+}
+
+/* Emit the handler specified by ENTRY. */
+
+static void
+emit_cleanup_handler (entry)
+ struct eh_entry *entry;
+{
+ rtx prev;
+ rtx handler_insns;
+
+ /* Since the cleanup could itself contain try-catch blocks, we
+ squirrel away the current queue and replace it when we are done
+ with this function. */
+ push_ehqueue ();
+
+ /* Put these handler instructions in a sequence. */
+ do_pending_stack_adjust ();
+ start_sequence ();
+
+ /* Emit the label for the cleanup handler for this region, and
+ expand the code for the handler.
+
+ Note that a catch region is handled as a side-effect here; for a
+ try block, entry->finalization will contain integer_zero_node, so
+ no code will be generated in the expand_expr call below. But, the
+ label for the handler will still be emitted, so any code emitted
+ after this point will end up being the handler. */
+
+ receive_exception_label (entry->exception_handler_label);
+
+ /* register a handler for this cleanup region */
+ add_new_handler (find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
+ get_new_handler (entry->exception_handler_label, NULL));
+
+ /* And now generate the insns for the cleanup handler. */
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+
+ prev = get_last_insn ();
+ if (prev == NULL || GET_CODE (prev) != BARRIER)
+ /* 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);
+
+ /* Finish this sequence. */
+ do_pending_stack_adjust ();
+ handler_insns = get_insns ();
+ end_sequence ();
+
+ /* And add it to the CATCH_CLAUSES. */
+ push_to_full_sequence (catch_clauses, catch_clauses_last);
+ emit_insns (handler_insns);
+ end_full_sequence (&catch_clauses, &catch_clauses_last);
+
+ /* Now we've left the handler. */
+ pop_ehqueue ();
+}
+
/* Generate RTL for the start of a group of catch clauses.
It is responsible for starting a new instruction sequence for the
the handlers in this handler-seq. */
start_sequence ();
- entry = dequeue_eh_entry (&ehqueue);
- for ( ; entry->finalization != integer_zero_node;
- entry = dequeue_eh_entry (&ehqueue))
- {
- rtx prev;
-
- /* Emit the label for the cleanup handler for this region, and
- expand the code for the handler.
-
- Note that a catch region is handled as a side-effect here;
- for a try block, entry->finalization will contain
- integer_zero_node, so no code will be generated in the
- expand_expr call below. But, the label for the handler will
- still be emitted, so any code emitted after this point will
- end up being the handler. */
-
- receive_exception_label (entry->exception_handler_label);
-
- /* register a handler for this cleanup region */
- add_new_handler (
- find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
- get_new_handler (entry->exception_handler_label, NULL));
-
- /* And now generate the insns for the cleanup handler. */
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- prev = get_last_insn ();
- if (prev == NULL || GET_CODE (prev) != BARRIER)
- /* 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);
-
- do_pending_stack_adjust ();
- free (entry);
- }
+ /* Throw away entries in the queue that we won't need anymore. We
+ need entries for regions that have ended but to which there might
+ still be gotos pending. */
+ for (entry = dequeue_eh_entry (ehqueue);
+ entry->finalization != integer_zero_node;
+ entry = dequeue_eh_entry (ehqueue))
+ free (entry);
/* At this point, all the cleanups are done, and the ehqueue now has
the current exception region at its head. We dequeue it, and put it
on the catch stack. */
-
- push_entry (&catchstack, entry);
+ push_entry (&catchstack, 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
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);
+ push_to_full_sequence (catch_clauses, catch_clauses_last);
emit_insns (new_catch_clause);
- catch_clauses = get_insns ();
- end_sequence ();
+ end_full_sequence (&catch_clauses, &catch_clauses_last);
/* Here we fall through into the continuation code. */
}
else
if (flag_new_exceptions)
{
- rtx insn, val;
+ rtx insn;
int region;
if (label == NULL_RTX)
label = last_rethrow_symbol;
emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
region = find_func_region (eh_region_from_symbol (label));
+ /* If the region is -1, it doesn't exist yet. We shouldn't be
+ trying to rethrow there yet. */
+ if (region == -1)
+ abort ();
function_eh_regions[region].rethrow_ref = 1;
/* Search backwards for the actual call insn. */
emit_jump (label);
}
+/* Begin a region that will contain entries created with
+ add_partial_entry. */
+
+void
+begin_protect_partials ()
+{
+ /* Push room for a new list. */
+ protect_list = tree_cons (NULL_TREE, NULL_TREE, protect_list);
+}
+
/* End all the pending exception regions on protect_list. The handlers
will be emitted when expand_leftover_cleanups is invoked. */
void
end_protect_partials ()
{
- while (protect_list)
- {
- expand_eh_region_end (TREE_VALUE (protect_list));
- protect_list = TREE_CHAIN (protect_list);
- }
+ tree t;
+
+ /* For backwards compatibility, we allow callers to omit the call to
+ begin_protect_partials for the outermost region. So,
+ PROTECT_LIST may be NULL. */
+ if (!protect_list)
+ return;
+
+ /* End all the exception regions. */
+ for (t = TREE_VALUE (protect_list); t; t = TREE_CHAIN (t))
+ expand_eh_region_end (TREE_VALUE (t));
+
+ /* Pop the topmost entry. */
+ protect_list = TREE_CHAIN (protect_list);
+
}
/* Arrange for __terminate to be called if there is an unhandled throw
{
tree handler, result;
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
handler = make_node (RTL_EXPR);
TREE_TYPE (handler) = void_type_node;
RTL_EXPR_RTL (handler) = const0_rtx;
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
TREE_READONLY (result) = TREE_READONLY (e);
- pop_obstacks ();
-
e = result;
}
Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
(Or NOTE_INSN_EH_REGION_END sometimes)
- N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
+ N is the NOTE_EH_HANDLER of the note, which comes from the code
label number of the exception handler for the region. */
void
}
}
eh_table[eh_table_size++] = n;
+
+ if (flag_new_exceptions)
+ {
+ /* We will output the exception table late in the compilation. That
+ references type_info objects which should have already been output
+ by that time. We explicitly mark those objects as being
+ referenced now so we know to emit them. */
+ struct handler_info *handler = get_first_handler (n);
+
+ for (; handler; handler = handler->next)
+ if (handler->type_info && handler->type_info != CATCH_ALL_TYPE)
+ {
+ tree tinfo = (tree)handler->type_info;
+
+ tinfo = TREE_OPERAND (tinfo, 0);
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
+ }
+ }
#endif
}
int index = find_func_region (n);
rtx rethrow;
- /* form and emit the rethrow label, if needed */
- rethrow = function_eh_regions[index].rethrow_label;
- if (rethrow != NULL_RTX && !flag_new_exceptions)
- rethrow = NULL_RTX;
- if (rethrow != NULL_RTX && handler == NULL)
- if (! function_eh_regions[index].rethrow_ref)
- rethrow = NULL_RTX;
+ /* Form and emit the rethrow label, if needed */
+ if (flag_new_exceptions
+ && (handler || function_eh_regions[index].rethrow_ref))
+ rethrow = function_eh_regions[index].rethrow_label;
+ else
+ rethrow = NULL_RTX;
+ if (function_eh_regions[index].emitted)
+ return;
+ function_eh_regions[index].emitted = 1;
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
{
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
- assemble_label(buf);
+ assemble_eh_label(buf);
rethrow = NULL_RTX;
}
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
if (handler == NULL)
- assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
else
{
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
- assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
}
if (flag_new_exceptions)
{
if (handler == NULL || handler->type_info == NULL)
- assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
else
if (handler->type_info == CATCH_ALL_TYPE)
- assemble_integer (GEN_INT (CATCH_ALL_TYPE),
+ assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE),
POINTER_SIZE / BITS_PER_UNIT, 1);
else
output_constant ((tree)(handler->type_info),
version_code = code;
}
-
+/* Free the EH table structures. */
void
-output_exception_table ()
+free_exception_table ()
+{
+ if (eh_table)
+ free (eh_table);
+ clear_function_eh_region ();
+}
+
+/* Output the common content of an exception table. */
+void
+output_exception_table_data ()
{
int i;
char buf[256];
extern FILE *asm_out_file;
- if (! doing_eh (0) || ! eh_table)
- return;
-
- exception_section ();
-
- /* Beginning marker for table. */
- assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
- assemble_label ("__EXCEPTION_TABLE__");
-
if (flag_new_exceptions)
{
- assemble_integer (GEN_INT (NEW_EH_RUNTIME),
+ assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME),
POINTER_SIZE / BITS_PER_UNIT, 1);
- assemble_integer (GEN_INT (language_code), 2 , 1);
- assemble_integer (GEN_INT (version_code), 2 , 1);
+ assemble_eh_integer (GEN_INT (language_code), 2 , 1);
+ assemble_eh_integer (GEN_INT (version_code), 2 , 1);
/* Add enough padding to make sure table aligns on a pointer boundry. */
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
;
if (i != 0)
- assemble_integer (const0_rtx, i , 1);
+ assemble_eh_integer (const0_rtx, i , 1);
- /* Generate the label for offset calculations on rethrows */
+ /* Generate the label for offset calculations on rethrows. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
- assemble_label(buf);
+ assemble_eh_label(buf);
}
for (i = 0; i < eh_table_size; ++i)
output_exception_table_entry (asm_out_file, eh_table[i]);
- free (eh_table);
- clear_function_eh_region ();
+}
+
+/* Output an exception table for the entire compilation unit. */
+void
+output_exception_table ()
+{
+ char buf[256];
+ extern FILE *asm_out_file;
+
+ if (! doing_eh (0) || ! eh_table)
+ return;
+
+ exception_section ();
+
+ /* Beginning marker for table. */
+ assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+ assemble_eh_label ("__EXCEPTION_TABLE__");
+
+ output_exception_table_data ();
/* Ending marker for table. */
/* Generate the label for end of table. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
- assemble_label(buf);
- assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_label(buf);
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
- /* for binary compatability, the old __throw checked the second
+ /* For binary compatibility, the old __throw checked the second
position for a -1, so we should output at least 2 -1's */
if (! flag_new_exceptions)
- assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
putc ('\n', asm_out_file); /* blank line */
}
+
+/* Used by the ia64 unwind format to output data for an individual
+ function. */
+void
+output_function_exception_table ()
+{
+ extern FILE *asm_out_file;
+
+ if (! doing_eh (0) || ! eh_table)
+ return;
+
+#ifdef HANDLER_SECTION
+ HANDLER_SECTION;
+#endif
+
+ output_exception_table_data ();
+
+ /* Ending marker for table. */
+ assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ putc ('\n', asm_out_file); /* blank line */
+}
+
\f
/* Emit code to get EH context.
end_sequence ();
emit_insns_before (insns, insn);
-
- /* At -O0, we must make the context register stay alive so
- that the stupid.c register allocator doesn't get confused. */
- if (obey_regdecls != 0)
- {
- insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0));
- emit_insn_before (insns, get_last_insn ());
- }
}
}
}
-/* Scan the current insns and build a list of handler labels. The
- resulting list is placed in the global variable exception_handler_labels.
-
- It is called after the last exception handling region is added to
- the current function (when the rtl is almost all built for the
- current function) and before the jump optimization pass. */
+/* Scan the insn chain F and build a list of handler labels. The
+ resulting list is placed in the global variable exception_handler_labels. */
-void
-find_exception_handler_labels ()
+static void
+find_exception_handler_labels_1 (f)
+ rtx f;
{
rtx insn;
- exception_handler_labels = NULL_RTX;
-
- /* If we aren't doing exception handling, there isn't much to check. */
- if (! doing_eh (0))
- return;
-
/* For each start of a region, add its label to the list. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ for (insn = f; insn; insn = NEXT_INSN (insn))
{
struct handler_info* ptr;
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
{
- ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
+ ptr = get_first_handler (NOTE_EH_HANDLER (insn));
for ( ; ptr; ptr = ptr->next)
{
/* make sure label isn't in the list already */
ptr->handler_label, exception_handler_labels);
}
}
+ else if (GET_CODE (insn) == CALL_INSN
+ && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+ {
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 0));
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 1));
+ find_exception_handler_labels_1 (XEXP (PATTERN (insn), 2));
+ }
}
}
+/* Scan the current insns and build a list of handler labels. The
+ resulting list is placed in the global variable exception_handler_labels.
+
+ It is called after the last exception handling region is added to
+ the current function (when the rtl is almost all built for the
+ current function) and before the jump optimization pass. */
+void
+find_exception_handler_labels ()
+{
+ exception_handler_labels = NULL_RTX;
+
+ /* If we aren't doing exception handling, there isn't much to check. */
+ if (! doing_eh (0))
+ return;
+
+ find_exception_handler_labels_1 (get_insns ());
+}
+
/* Return a value of 1 if the parameter label number is an exception handler
label. Return 0 otherwise. */
}
}
-\f
+
+/* Mark the children of NODE for GC. */
+
+static void
+mark_eh_node (node)
+ struct eh_node *node;
+{
+ while (node)
+ {
+ if (node->entry)
+ {
+ ggc_mark_rtx (node->entry->outer_context);
+ ggc_mark_rtx (node->entry->exception_handler_label);
+ ggc_mark_tree (node->entry->finalization);
+ ggc_mark_rtx (node->entry->false_label);
+ ggc_mark_rtx (node->entry->rethrow_label);
+ }
+ node = node ->chain;
+ }
+}
+
+/* Mark S for GC. */
+
+static void
+mark_eh_stack (s)
+ struct eh_stack *s;
+{
+ if (s)
+ mark_eh_node (s->top);
+}
+
+/* Mark Q for GC. */
+
+static void
+mark_eh_queue (q)
+ struct eh_queue *q;
+{
+ while (q)
+ {
+ mark_eh_node (q->head);
+ q = q->next;
+ }
+}
+
+/* Mark NODE for GC. A label_node contains a union containing either
+ a tree or an rtx. This label_node will contain a tree. */
+
+static void
+mark_tree_label_node (node)
+ struct label_node *node;
+{
+ while (node)
+ {
+ ggc_mark_tree (node->u.tlabel);
+ node = node->chain;
+ }
+}
+
+/* Mark EH for GC. */
+
+void
+mark_eh_status (eh)
+ struct eh_status *eh;
+{
+ if (eh == 0)
+ return;
+
+ mark_eh_stack (&eh->x_ehstack);
+ mark_eh_stack (&eh->x_catchstack);
+ mark_eh_queue (eh->x_ehqueue);
+ ggc_mark_rtx (eh->x_catch_clauses);
+
+ if (lang_mark_false_label_stack)
+ (*lang_mark_false_label_stack) (eh->x_false_label_stack);
+ mark_tree_label_node (eh->x_caught_return_label_stack);
+
+ ggc_mark_tree (eh->x_protect_list);
+ ggc_mark_rtx (eh->ehc);
+ ggc_mark_rtx (eh->x_eh_return_stub_label);
+}
+
+/* Mark ARG (which is really a struct func_eh_entry**) for GC. */
+
+static void
+mark_func_eh_entry (arg)
+ void *arg;
+{
+ struct func_eh_entry *fee;
+ struct handler_info *h;
+ int i;
+
+ fee = *((struct func_eh_entry **) arg);
+
+ for (i = 0; i < current_func_eh_entry; ++i)
+ {
+ ggc_mark_rtx (fee->rethrow_label);
+ for (h = fee->handlers; h; h = h->next)
+ {
+ ggc_mark_rtx (h->handler_label);
+ if (h->type_info != CATCH_ALL_TYPE)
+ ggc_mark_tree ((tree) h->type_info);
+ }
+
+ /* Skip to the next entry in the array. */
+ ++fee;
+ }
+}
+
/* This group of functions initializes the exception handling data
structures at the start of the compilation, initializes the data
structures at the start of a function, and saves and restores the
first_rethrow_symbol = create_rethrow_ref (0);
final_rethrow = gen_exception_label ();
last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
-}
+ ggc_add_rtx_root (&exception_handler_labels, 1);
+ ggc_add_rtx_root (&eh_return_context, 1);
+ ggc_add_rtx_root (&eh_return_stack_adjust, 1);
+ ggc_add_rtx_root (&eh_return_handler, 1);
+ ggc_add_rtx_root (&first_rethrow_symbol, 1);
+ ggc_add_rtx_root (&final_rethrow, 1);
+ ggc_add_rtx_root (&last_rethrow_symbol, 1);
+ ggc_add_root (&function_eh_regions, 1, sizeof (function_eh_regions),
+ mark_func_eh_entry);
+}
+
/* Initialize the per-function EH information. */
void
init_eh_for_function ()
{
- current_function->eh = (struct eh_status *) xmalloc (sizeof (struct eh_status));
-
- ehstack.top = 0;
- catchstack.top = 0;
- ehqueue.head = ehqueue.tail = 0;
- catch_clauses = NULL_RTX;
- false_label_stack = 0;
- caught_return_label_stack = 0;
- protect_list = NULL_TREE;
- current_function_ehc = NULL_RTX;
+ cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status));
+ ehqueue = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue));
eh_return_context = NULL_RTX;
eh_return_stack_adjust = NULL_RTX;
eh_return_handler = NULL_RTX;
- eh_return_stub_label = NULL_RTX;
+}
+
+void
+free_eh_status (f)
+ struct function *f;
+{
+ free (f->eh->x_ehqueue);
+ free (f->eh);
+ f->eh = NULL;
}
\f
/* This section is for the exception handling specific optimization
- pass. First are the internal routines, and then the main
- optimization pass. */
+ pass. */
/* Determine if the given INSN can throw an exception. */
-static int
+int
can_throw (insn)
rtx insn;
{
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ insn = XVECEXP (PATTERN (insn), 0, 0);
+
/* Calls can always potentially throw exceptions, unless they have
a REG_EH_REGION note with a value of 0 or less. */
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
- if (!note || XINT (XEXP (note, 0), 0) > 0)
+ if (!note || INTVAL (XEXP (note, 0)) > 0)
return 1;
}
return 0;
}
+/* Return nonzero if nothing in this function can throw. */
+
+int
+nothrow_function_p ()
+{
+ rtx insn;
+
+ if (! flag_exceptions)
+ return 1;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (can_throw (insn))
+ return 0;
+ for (insn = current_function_epilogue_delay_list; insn;
+ insn = XEXP (insn, 1))
+ if (can_throw (insn))
+ return 0;
+
+ return 1;
+}
+
/* Scan a exception region looking for the matching end and then
remove it if possible. INSN is the start of the region, N is the
region number, and DELETE_OUTER is to note if anything in this
/* Assume we can delete the region. */
int delete = 1;
- /* Can't delete something which is rethrown to. */
+ /* Can't delete something which is rethrown from. */
if (rethrow_used (n))
delete = 0;
if (insn == NULL_RTX
|| GET_CODE (insn) != NOTE
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
- || NOTE_BLOCK_NUMBER (insn) != n
+ || NOTE_EH_HANDLER (insn) != n
|| delete_outer == NULL)
abort ();
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
{
- insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
+ insn = scan_region (insn, NOTE_EH_HANDLER (insn), &delete);
}
insn = NEXT_INSN (insn);
}
/* The _BEG/_END NOTEs must match and nest. */
- if (NOTE_BLOCK_NUMBER (insn) != n)
+ if (NOTE_EH_HANDLER (insn) != n)
abort ();
/* If anything in this exception region can throw, we can throw. */
inbetween. We are also guaranteed that the value of insn
returned will be valid, as otherwise scan_region won't
return. */
- insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
+ insn = scan_region (insn, NOTE_EH_HANDLER (insn), &n);
}
}
}
-/* This function determines whether any of the exception regions in the
- current function are targets of a rethrow or not, and set the
- reference flag according. */
+/* This function determines whether the rethrow labels for any of the
+ exception regions in the current function are used or not, and set
+ the reference flag according. */
+
void
update_rethrow_references ()
{
if (!flag_new_exceptions)
return;
- saw_region = (int *) alloca (current_func_eh_entry * sizeof (int));
- saw_rethrow = (int *) alloca (current_func_eh_entry * sizeof (int));
- bzero ((char *) saw_region, (current_func_eh_entry * sizeof (int)));
- bzero ((char *) saw_rethrow, (current_func_eh_entry * sizeof (int)));
+ saw_region = (int *) xcalloc (current_func_eh_entry, sizeof (int));
+ saw_rethrow = (int *) xcalloc (current_func_eh_entry, sizeof (int));
/* Determine what regions exist, and whether there are any rethrows
- to those regions or not. */
+ from those regions or not. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
{
- region = find_func_region (NOTE_BLOCK_NUMBER (insn));
+ region = find_func_region (NOTE_EH_HANDLER (insn));
saw_region[region] = 1;
}
}
for (x = 0; x < current_func_eh_entry; x++)
if (saw_region[x])
function_eh_regions[x].rethrow_ref = saw_rethrow[x];
+
+ /* Clean up. */
+ free (saw_region);
+ free (saw_rethrow);
}
\f
/* Various hooks for the DWARF 2 __throw routine. */
The first passes the exception context to the handler. For this
we use the return value register for a void*.
- The second holds the stack pointer value to be restored. For
- this we use the static chain register if it exists and is different
- from the previous, otherwise some arbitrary call-clobbered register.
+ The second holds the stack pointer value to be restored. For this
+ we use the static chain register if it exists, is different from
+ the previous, and is call-clobbered; otherwise some arbitrary
+ call-clobbered register.
The third holds the address of the handler itself. Here we use
some arbitrary call-clobbered register. */
static void
eh_regs (pcontext, psp, pra, outgoing)
rtx *pcontext, *psp, *pra;
- int outgoing;
+ int outgoing ATTRIBUTE_UNUSED;
{
rtx rcontext, rsp, rra;
- int i;
+ unsigned int i;
#ifdef FUNCTION_OUTGOING_VALUE
if (outgoing)
rsp = static_chain_incoming_rtx;
else
rsp = static_chain_rtx;
- if (REGNO (rsp) == REGNO (rcontext))
+ if (REGNO (rsp) == REGNO (rcontext)
+ || ! call_used_regs [REGNO (rsp)])
#endif /* STATIC_CHAIN_REGNUM */
rsp = NULL_RTX;
/* Retrieve the register which contains the pointer to the eh_context
structure set the __throw. */
+#if 0
rtx
get_reg_for_handler ()
{
current_function_decl);
return reg1;
}
+#endif
/* Set up the epilogue with the magic bits we'll need to return to the
exception handler. */
for (insn = *first; insn; insn = NEXT_INSN (insn))
{
- if ((GET_CODE (insn) == NOTE) &&
- (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
+ if ((GET_CODE (insn) == NOTE)
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
{
- rnum = NOTE_BLOCK_NUMBER (insn);
+ rnum = NOTE_EH_HANDLER (insn);
insn_eh_region[INSN_UID (insn)] = rnum;
insn = NEXT_INSN (insn);
set_insn_eh_region (&insn, rnum);
max_uid = INSN_UID (insn);
maximum_uid = max_uid;
- insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
+ insn_eh_region = (int *) xmalloc ((max_uid + 1) * sizeof (int));
insn = first;
set_insn_eh_region (&insn, 0);
}
yet. At some point in the future we can trim out handlers which we
know cannot be called. (ie, if a block has an INT type handler,
control will never be passed to an outer INT type handler). */
+
static void
process_nestinfo (block, info, nested_eh_region)
int block;
handler_info *ptr, *last_ptr = NULL;
int x, y, count = 0;
int extra = 0;
- handler_info **extra_handlers;
+ handler_info **extra_handlers = 0;
int index = info->region_index[block];
/* If we've already processed this block, simply return. */
extra = 0;
info->num_handlers[index] = count + extra;
- info->handlers[index] = (handler_info **) malloc ((count + extra)
+ info->handlers[index] = (handler_info **) xmalloc ((count + extra)
* sizeof (handler_info **));
/* First put all our handlers into the list. */
/* This function will allocate and initialize an eh_nesting_info structure.
It returns a pointer to the completed data structure. If there are
no exception regions, a NULL value is returned. */
+
eh_nesting_info *
init_eh_nesting_info ()
{
rtx insn;
int x;
- info = (eh_nesting_info *) malloc (sizeof (eh_nesting_info));
- info->region_index = (int *) malloc ((max_label_num () + 1) * sizeof (int));
- bzero ((char *) info->region_index, (max_label_num () + 1) * sizeof (int));
+ if (! flag_exceptions)
+ return 0;
- nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
- bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
+ info = (eh_nesting_info *) xmalloc (sizeof (eh_nesting_info));
+ info->region_index = (int *) xcalloc ((max_label_num () + 1), sizeof (int));
+ nested_eh_region = (int *) xcalloc (max_label_num () + 1, sizeof (int));
/* Create the nested_eh_region list. If indexed with a block number, it
returns the block number of the next outermost region, if any.
{
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
{
- int block = NOTE_BLOCK_NUMBER (insn);
+ int block = NOTE_EH_HANDLER (insn);
region_count++;
info->region_index[block] = region_count;
if (eh_note)
nested_eh_region [block] =
- NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
+ NOTE_EH_HANDLER (XEXP (eh_note, 0));
else
nested_eh_region [block] = 0;
eh_note = gen_rtx_EXPR_LIST (VOIDmode, insn, eh_note);
{
free (info->region_index);
free (info);
+ free (nested_eh_region);
return NULL;
}
region_count++;
- info->handlers = (handler_info ***) malloc (region_count
- * sizeof (handler_info ***));
- info->num_handlers = (int *) malloc (region_count * sizeof (int));
- info->outer_index = (int *) malloc (region_count * sizeof (int));
-
- bzero ((char *) info->handlers, region_count * sizeof (rtx *));
- bzero ((char *) info->num_handlers, region_count * sizeof (int));
- bzero ((char *) info->outer_index, region_count * sizeof (int));
+ info->handlers = (handler_info ***) xcalloc (region_count,
+ sizeof (handler_info ***));
+ info->num_handlers = (int *) xcalloc (region_count, sizeof (int));
+ info->outer_index = (int *) xcalloc (region_count, sizeof (int));
/* Now initialize the handler lists for all exception blocks. */
for (x = 0; x <= max_label_num (); x++)
process_nestinfo (x, info, nested_eh_region);
}
info->region_count = region_count;
+
+ /* Clean up. */
+ free (nested_eh_region);
+
return info;
}
HANDLERS is the address of a pointer to a vector of handler_info pointers.
Upon return, this will have the handlers which can be reached by block.
This function returns the number of elements in the handlers vector. */
+
int
reachable_handlers (block, info, insn, handlers)
int block;
if (insn && GET_CODE (insn) == CALL_INSN)
{
/* RETHROWs specify a region number from which we are going to rethrow.
- This means we wont pass control to handlers in the specified
+ This means we won't pass control to handlers in the specified
region, but rather any region OUTSIDE the specified region.
We accomplish this by setting block to the outer_index of the
specified region. */
note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (note)
{
- int b = XINT (XEXP (note, 0), 0);
+ int b = INTVAL (XEXP (note, 0));
if (b <= 0)
index = 0;
else
free (info->handlers[x]);
free (info->handlers);
}
+ free (info);
}
}