See ChangeLog..

Tue Dec  8 15:32:56 EST 1998  Andrew MacLeod  <amacleod@cygnus.com>
See ChangeLog.. These are the files that were changed:
	* eh-common.h (struct eh_context): Add table_index for rethrows.
	* rtl.h (enum reg_note): Add REG_EH_REGION and REG_EH_RETHROW reg notes.
	* rtl.c (reg_note_name): Add strings for new reg_note enums.
	* expr.h (rethrow_libfunc): New library decl.
	* optabs.c (rethrow_libfunc): Initialize.
	* except.h (struct eh_entry): Add new field 'rethrow_label'.
	* except.c (create_rethrow_ref): New function to create a single
	* flow.c (make_edges): Add different edges for rethrow calls,
	* integrate.c (save_for_inline_eh_labelmap): New callback routine to
	* libgcc2.c (find_exception_handler): Generalize to enable it to
        * cp/except.c
        * cp/exception.cc

From-SVN: r24194
This commit is contained in:
Andrew MacLeod 1998-12-08 14:04:03 +00:00 committed by Andrew Macleod
parent 2bfdc2d4e7
commit e6cfb550ab
14 changed files with 680 additions and 145 deletions

View File

@ -1,3 +1,71 @@
Tue Dec 8 15:32:56 EST 1998 Andrew MacLeod <amacleod@cygnus.com>
* eh-common.h (struct eh_context): Add table_index for rethrows.
* rtl.h (enum reg_note): Add REG_EH_REGION and REG_EH_RETHROW reg notes.
(SYMBOL_REF_NEED_ADJUST): New flag indicating symbol needs to be
processed when inlined or unrolled (ie duplicated in some way).
* rtl.c (reg_note_name): Add strings for new reg_note enums.
* expr.h (rethrow_libfunc): New library decl.
* optabs.c (rethrow_libfunc): Initialize.
* except.h (struct eh_entry): Add new field 'rethrow_label'.
(new_eh_region_entry): No longer exported from except.c.
(duplicate_handlers): Renamed to duplicate_eh_handlers and
different prototype.
(rethrow_symbol_map, rethrow_used): New exported functions.
(eh_region_from_symbol): New exported function.
* except.c (create_rethrow_ref): New function to create a single
SYMBOL_REF for a rethrow region.
(push_eh_entry): Initialize a rethrow ref.
(func_eh_entry): Add a rethrow_label field.
(new_eh_region_entry): Make static, and initialize the rethrow entry.
(duplicate_eh_handlers): Create a new region, and remap labels/symbols.
(eh_region_from_symbol): Find an EH region based on its rethrow symbol.
(rethrow_symbol_map): Given a label map, maps a rethrow symbol for
a region into an appropriate new symbol.
(rethrow_used): Indicate whether a rethrow symbol has been referenced.
(expand_eh_region_end): Don't issue jump around code for new-exceptions.
(end_catch_handler): Emit a barrier for new-exceptions since
control can never drop through the end of a catch block.
(expand_end_all_catch): new-exceptions never fall through a catch
block.
(expand_rethrow): use __rethrow routine for new exceptions.
(output_exception_table_entry): Generate rethrow labels, if needed.
(output_exception_table): Generate start and end rethrow labels.
(init_eh): Create rethrow symbols for beginning and end of table.
(scan_region): Don't eliminate EH regions which are the targets of
rethrows.
* flow.c (make_edges): Add different edges for rethrow calls,
identified by having the REG_EH_RETHROW reg label.
(delete_unreachable_blocks): Don't delete regions markers which are
the target of a rethrow.
* integrate.c (save_for_inline_eh_labelmap): New callback routine to
allow save_for_inline_copying to call duplicate_eh_handlers.
(save_for_inline_copying): Call duplicate_eh_handlers instead of
exposing internal details of exception regions.
(copy_for_inline): Check if SYMBOL_REFs need adjustment.
(expand_inline_function_eh_labelmap): New callback routine to
allow expand_inline_function to call duplicate_eh_handlers.
(expand_inline_function): Call duplicate_eh_handlers instead of
exposing internal details of exception regions.
(copy_rtx_and_substitute): Adjust SYMBOL_REFS if SYMBOL_REF_NEED_ADJUST
flag is set.
* libgcc2.c (find_exception_handler): Generalize to enable it to
pick up processing where it left off last time for a rethrow.
(__unwinding_cleanup): New function. debug hook which is called before
unwinding when __throw finds there is nothing but cleanups left.
(throw_helper): Common parts of __throw extracted out for reuse.
(__throw): Common parts moved to throw_helper.
(__rethrow): New function for performing rethrows.
Tue Dec 8 13:11:04 1998 Jeffrey A Law (law@cygnus.com)
* reload1.c (current_function_decl): Tweak declaration.

View File

@ -1,3 +1,19 @@
1998-12-08 Andrew MacLeod <amacleod@cygnus.com>
* cp/except.c (call_eh_info): use __start_cp_handler instead of
__cp_eh_info for getting the eh info pointer. Add table_index to
field list.
(push_eh_cleanup): Don't increment 'handlers' data field.
(process_start_catch_block): Don't set the 'caught' field.
* cp/exception.cc (CP_EH_INFO): New macro for getting the
exception info pointer within library routines.
(__cp_eh_info): Use CP_EH_INFO.
(__start_cp_handler): Get exception info pointer, set caught field,
and increment the handlers field. Avoids this being done by handlers.
(__uncatch_exception, __check_eh_spec): Use CP_EH_INFO macro.
(uncaught_exception): Use CP_EH_INFO macro.
Tue Dec 8 10:48:21 1998 Jeffrey A Law (law@cygnus.com)
* Make-lang.in (cxxmain.o): Depend on $(DEMANGLE_H), not demangle.h

View File

@ -249,14 +249,14 @@ call_eh_info ()
{
tree fn;
fn = get_identifier ("__cp_eh_info");
fn = get_identifier ("__start_cp_handler");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
tree t1, t, fields[7];
/* Declare cp_eh_info * __cp_eh_info (void),
/* Declare cp_eh_info * __start_cp_handler (void),
as defined in exception.cc. */
push_obstacks_nochange ();
end_temporary_allocation ();
@ -270,9 +270,11 @@ call_eh_info ()
get_identifier ("dynamic_handler_chain"), ptr_type_node);
fields[2] = build_lang_field_decl (FIELD_DECL,
get_identifier ("info"), ptr_type_node);
fields[3] = build_lang_field_decl (FIELD_DECL,
get_identifier ("table_index"), ptr_type_node);
/* N.B.: The fourth field LEN is expected to be
the number of fields - 1, not the total number of fields. */
finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node);
finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
t1 = build_pointer_type (t1);
t1= make_lang_type (RECORD_TYPE);
@ -547,9 +549,6 @@ push_eh_cleanup ()
{
int yes;
expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
const0_rtx, VOIDmode, EXPAND_NORMAL);
yes = suspend_momentary ();
/* All cleanups must last longer than normal. */
expand_decl_cleanup (NULL_TREE, do_pop_exception ());
@ -701,9 +700,6 @@ process_start_catch_block (declspecs, declarator)
/* Fall into the catch all section. */
}
init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
emit_line_note (input_filename, lineno);
}

View File

@ -117,13 +117,29 @@ __cp_exception_info (void)
return &((*__get_eh_info ())->value);
}
/* Compiler hook to return a pointer to the info for the current exception.
#define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ())
/* Old Compiler hook to return a pointer to the info for the current exception.
Used by get_eh_info (). */
extern "C" cp_eh_info *
__cp_eh_info (void)
{
return *__get_eh_info ();
cp_eh_info *p = CP_EH_INFO;
return p;
}
/* Compiler hook to return a pointer to the info for the current exception,
Set the caught bit, and increment the number of handlers that are
looking at this exception. This makes handlers smaller. */
extern "C" cp_eh_info *
__start_cp_handler (void)
{
cp_eh_info *p = CP_EH_INFO;
p->caught = 1;
p->handlers++;
return p;
}
/* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
@ -242,7 +258,7 @@ __cp_pop_exception (cp_eh_info *p)
extern "C" void
__uncatch_exception (void)
{
cp_eh_info *p = __cp_eh_info ();
cp_eh_info *p = CP_EH_INFO;
if (p == 0)
terminate ();
p->caught = false;
@ -263,7 +279,7 @@ __uncatch_exception (void)
extern "C" void
__check_eh_spec (int n, const void **spec)
{
cp_eh_info *p = __cp_eh_info ();
cp_eh_info *p = CP_EH_INFO;
for (int i = 0; i < n; ++i)
{
@ -316,7 +332,7 @@ __throw_bad_typeid (void)
bool
std::uncaught_exception ()
{
cp_eh_info *p = __cp_eh_info ();
cp_eh_info *p = CP_EH_INFO;
return p && ! p->caught;
}

View File

@ -29,6 +29,8 @@ struct eh_context
void **dynamic_handler_chain;
/* This is language dependent part of the eh context. */
void *info;
/* This is used to remember where we threw for re-throws */
void *table_index; /* address of exception table entry to rethrow from */
};
#ifndef EH_TABLE_LOOKUP

View File

@ -406,6 +406,7 @@ Boston, MA 02111-1307, USA. */
#include "recog.h"
#include "output.h"
#include "toplev.h"
#include "obstack.h"
/* One to use setjmp/longjmp method of generating code for exception
handling. */
@ -502,6 +503,15 @@ static rtx eh_return_handler;
rtx eh_return_stub_label;
/* This is used for targets which can call rethrow with an offset instead
of an address. This is subtracted from the rethrow label we are
interested in. */
static rtx first_rethrow_symbol = NULL_RTX;
static rtx final_rethrow = NULL_RTX;
static rtx last_rethrow_symbol = NULL_RTX;
/* Prototypes for local functions. */
static void push_eh_entry PROTO((struct eh_stack *));
@ -526,6 +536,29 @@ rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
/* 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;
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));
def = gen_rtx_SYMBOL_REF (Pmode, ptr);
SYMBOL_REF_NEED_ADJUST (def) = 1;
pop_obstacks ();
return def;
}
/* Push a label entry onto the given STACK. */
void
@ -600,11 +633,16 @@ push_eh_entry (stack)
struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
entry->outer_context = gen_label_rtx ();
rtx rlab = gen_exception_label ();
entry->finalization = NULL_TREE;
entry->label_used = 0;
entry->exception_handler_label = gen_exception_label ();
entry->exception_handler_label = rlab;
entry->false_label = NULL_RTX;
if (! flag_new_exceptions)
entry->outer_context = gen_label_rtx ();
else
entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
entry->rethrow_label = entry->outer_context;
node->entry = entry;
node->chain = stack->top;
@ -707,6 +745,7 @@ receive_exception_label (handler_label)
struct func_eh_entry
{
int range_number; /* EH region number from EH NOTE insn's */
rtx rethrow_label; /* Label for rethrow */
struct handler_info *handlers;
};
@ -719,12 +758,14 @@ static int current_func_eh_entry = 0;
#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. The number
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. */
int
new_eh_region_entry (note_eh_region)
static int
new_eh_region_entry (note_eh_region, rethrow)
int note_eh_region;
rtx rethrow;
{
if (current_func_eh_entry == num_func_eh_entries)
{
@ -742,6 +783,11 @@ new_eh_region_entry (note_eh_region)
}
}
function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
if (rethrow == NULL_RTX)
function_eh_regions[current_func_eh_entry].rethrow_label =
create_rethrow_ref (note_eh_region);
else
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
function_eh_regions[current_func_eh_entry].handlers = NULL;
return current_func_eh_entry++;
@ -929,34 +975,98 @@ clear_function_eh_region ()
}
/* Make a duplicate of an exception region by copying all the handlers
for an exception region. Return the new handler index. */
for an exception region. Return the new handler index. The final
parameter is a routine which maps old labels to new ones. */
int
duplicate_handlers (old_note_eh_region, new_note_eh_region)
duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
int old_note_eh_region, new_note_eh_region;
rtx (*map)(rtx);
{
struct handler_info *ptr, *new_ptr;
int new_region, region;
rtx tmp;
region = find_func_region (old_note_eh_region);
if (region == -1)
error ("Cannot duplicate non-existant exception region.");
fatal ("Cannot duplicate non-existant exception region.");
if (find_func_region (new_note_eh_region) != -1)
error ("Cannot duplicate EH region because new note region already exists");
/* duplicate_eh_handlers may have been called during a symbol remap. */
new_region = find_func_region (new_note_eh_region);
if (new_region != -1)
return (new_region);
new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
new_region = new_eh_region_entry (new_note_eh_region);
ptr = function_eh_regions[region].handlers;
for ( ; ptr; ptr = ptr->next)
{
new_ptr = get_new_handler (ptr->handler_label, ptr->type_info);
new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info);
add_new_handler (new_region, new_ptr);
}
return new_region;
}
/* Given a rethrow symbol, find the EH region number this is for. */
int
eh_region_from_symbol (sym)
rtx sym;
{
int x;
if (sym == last_rethrow_symbol)
return 1;
for (x = 0; x < current_func_eh_entry; x++)
if (function_eh_regions[x].rethrow_label == sym)
return function_eh_regions[x].range_number;
return -1;
}
/* 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)(rtx);
{
int x, y;
for (x = 0; x < current_func_eh_entry; x++)
if (function_eh_regions[x].rethrow_label == sym)
{
/* We've found the original region, now lets determine which region
this now maps to. */
rtx l1 = function_eh_regions[x].handlers->handler_label;
rtx l2 = map (l1);
y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
x = find_func_region (y); /* Get the new permanent region */
if (x == -1) /* Hmm, Doesn't exist yet */
{
x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
/* Since we're mapping it, it must be used. */
SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
}
return function_eh_regions[x].rethrow_label;
}
return sym;
}
int
rethrow_used (region)
int region;
{
if (flag_new_exceptions)
{
rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
return (SYMBOL_REF_USED (lab));
}
return 0;
}
/* Routine to see if exception handling is turned on.
DO_WARN is non-zero if we want to inform the user that exception
@ -1410,6 +1520,7 @@ expand_eh_region_end (handler)
{
struct eh_entry *entry;
rtx note;
int ret, r;
if (! doing_eh (0))
return;
@ -1417,9 +1528,9 @@ expand_eh_region_end (handler)
entry = pop_eh_entry (&ehstack);
note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
NOTE_BLOCK_NUMBER (note)
ret = NOTE_BLOCK_NUMBER (note)
= CODE_LABEL_NUMBER (entry->exception_handler_label);
if (exceptions_via_longjmp == 0
if (exceptions_via_longjmp == 0 && ! flag_new_exceptions
/* We share outer_context between regions; only emit it once. */
&& INSN_UID (entry->outer_context) == 0)
{
@ -1439,7 +1550,7 @@ expand_eh_region_end (handler)
entry->finalization = handler;
/* create region entry in final exception table */
new_eh_region_entry (NOTE_BLOCK_NUMBER (note));
r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
enqueue_eh_entry (&ehqueue, entry);
@ -1673,8 +1784,14 @@ start_catch_handler (rtime)
void
end_catch_handler ()
{
if (! doing_eh (1) || (flag_new_exceptions && ! exceptions_via_longjmp))
if (! doing_eh (1))
return;
if (flag_new_exceptions && ! exceptions_via_longjmp)
{
emit_barrier ();
return;
}
/* A NULL label implies the catch clause was a catch all or cleanup */
if (catchstack.top->entry->false_label == NULL_RTX)
@ -1786,7 +1903,7 @@ expand_start_all_catch ()
void
expand_end_all_catch ()
{
rtx new_catch_clause, outer_context = NULL_RTX;
rtx new_catch_clause;
struct eh_entry *entry;
if (! doing_eh (1))
@ -1798,11 +1915,17 @@ expand_end_all_catch ()
if (! exceptions_via_longjmp)
{
outer_context = ehstack.top->entry->outer_context;
rtx outer_context = ehstack.top->entry->outer_context;
/* Finish the rethrow region. size_zero_node is just a NOP. */
expand_eh_region_end (size_zero_node);
/* New exceptions handling models will never have a fall through
of a catch clause */
if (!flag_new_exceptions)
expand_rethrow (outer_context);
}
else
expand_rethrow (NULL_RTX);
/* 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
@ -1813,7 +1936,6 @@ expand_end_all_catch ()
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 ();
@ -1842,7 +1964,22 @@ expand_rethrow (label)
if (exceptions_via_longjmp)
emit_throw ();
else
emit_jump (label);
if (flag_new_exceptions)
{
rtx insn, val;
if (label == NULL_RTX)
label = last_rethrow_symbol;
emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
SYMBOL_REF_USED (label) = 1;
insn = get_last_insn ();
val = GEN_INT (eh_region_from_symbol (label));
/* Mark the label/symbol on the call. */
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
REG_NOTES (insn));
emit_barrier ();
}
else
emit_jump (label);
}
/* End all the pending exception regions on protect_list. The handlers
@ -1976,12 +2113,29 @@ output_exception_table_entry (file, n)
{
char buf[256];
rtx sym;
struct handler_info *handler;
struct handler_info *handler = get_first_handler (n);
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 (! SYMBOL_REF_USED (rethrow))
rethrow = NULL_RTX;
handler = get_first_handler (n);
for ( ; handler != NULL; handler = handler->next)
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
{
/* rethrow label should indicate the LAST entry for a region */
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
assemble_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);
@ -1990,12 +2144,15 @@ output_exception_table_entry (file, n)
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_integer (handler->handler_label,
POINTER_SIZE / BITS_PER_UNIT, 1);
if (handler == NULL)
assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
else
assemble_integer (handler->handler_label,
POINTER_SIZE / BITS_PER_UNIT, 1);
if (flag_new_exceptions)
{
if (handler->type_info == NULL)
if (handler == NULL || handler->type_info == NULL)
assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
else
if (handler->type_info == CATCH_ALL_TYPE)
@ -2007,7 +2164,7 @@ output_exception_table_entry (file, n)
}
putc ('\n', file); /* blank line */
/* We only output the first label under the old scheme */
if (! flag_new_exceptions)
if (! flag_new_exceptions || handler == NULL)
break;
}
}
@ -2038,6 +2195,7 @@ void
output_exception_table ()
{
int i;
char buf[256];
extern FILE *asm_out_file;
if (! doing_eh (0) || ! eh_table)
@ -2062,6 +2220,10 @@ output_exception_table ()
;
if (i != 0)
assemble_integer (const0_rtx, i , 1);
/* Generate the label for offset calculations on rethrows */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
assemble_label(buf);
}
for (i = 0; i < eh_table_size; ++i)
@ -2071,6 +2233,9 @@ output_exception_table ()
clear_function_eh_region ();
/* 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);
/* for binary compatability, the old __throw checked the second
@ -2229,6 +2394,10 @@ check_exception_handler_labels ()
void
init_eh ()
{
first_rethrow_symbol = create_rethrow_ref (0);
final_rethrow = gen_exception_label ();
last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
}
/* Initialize the per-function EH information. */
@ -2348,6 +2517,11 @@ scan_region (insn, n, delete_outer)
/* Assume we can delete the region. */
int delete = 1;
int r = find_func_region (n);
/* Can't delete something which is rethrown to. */
if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label)))
delete = 0;
if (insn == NULL_RTX
|| GET_CODE (insn) != NOTE
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG

View File

@ -65,6 +65,7 @@ struct eh_entry {
tree finalization;
int label_used;
rtx false_label;
rtx rethrow_label;
};
/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
@ -177,13 +178,6 @@ typedef struct handler_info
} handler_info;
/* Add a new eh_entry for this function, The parameter specifies what
exception region number NOTE insns use to delimit this range.
The integer returned is uniquely identifies this exception range
within an internal table. */
int new_eh_region_entry PROTO((int));
/* Add new handler information to an exception range. The first parameter
specifies the range number (returned from new_eh_entry()). The second
parameter specifies the handler. By default the handler is inserted at
@ -208,8 +202,19 @@ struct handler_info *get_new_handler PROTO((rtx, void *));
/* Make a duplicate of an exception region by copying all the handlers
for an exception region. Return the new handler index. */
int duplicate_handlers PROTO((int, int));
int duplicate_eh_handlers PROTO((int, int, rtx (*)(rtx)));
/* map symbol refs for rethrow */
rtx rethrow_symbol_map PROTO((rtx, rtx (*)(rtx)));
/* Is the rethrow label for a region used? */
int rethrow_used PROTO((int));
/* Return the region number a this is the rethrow label for. */
int eh_region_from_symbol PROTO((rtx));
/* Get a pointer to the first handler in an exception region's list. */

View File

@ -443,6 +443,7 @@ extern rtx memset_libfunc;
extern rtx bzero_libfunc;
extern rtx throw_libfunc;
extern rtx rethrow_libfunc;
extern rtx sjthrow_libfunc;
extern rtx sjpopnthrow_libfunc;
extern rtx terminate_libfunc;

View File

@ -721,6 +721,7 @@ make_edges (i)
int i;
{
rtx insn, x;
rtx pending_eh_region = NULL_RTX;
/* See if control drops into the next block. */
if (i + 1 < n_basic_blocks)
@ -801,6 +802,40 @@ make_edges (i)
}
}
/* If this is a call with an EH_RETHROW note, then we
know its a rethrow call, and we know exactly where
this call can end up going. */
else if (GET_CODE (insn) == CALL_INSN
&& (note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX)))
{
int region = XINT (XEXP (note, 0), 0);
/* if nested region is not 0, we know for sure it has been
processed. If it is zero, we dont know whether its an
outer region, or hasn't been seen yet, so defer it */
if (nested_eh_region[region] != 0)
{
/* start with the first region OUTSIDE the one specified
in the rethrow parameter. (since a rethrow behaves
as if a handler in the region didn't handle the
exception, so the handlers for the next outer region
are going to get a shot at it.*/
for ( region = nested_eh_region[region]; region;
region = nested_eh_region[region])
{
handler_info *ptr = get_first_handler (region);
for ( ; ptr ; ptr = ptr->next)
add_edge_to_label (i, ptr->handler_label);
}
}
else
{
/* Push this region onto a list, and after we've done the
whole procedure, we'll process everything on the list */
pending_eh_region = gen_rtx_EXPR_LIST (VOIDmode, insn,
pending_eh_region);
}
}
/* If this is a CALL_INSN, then mark it as reaching the active EH
handler for this CALL_INSN. If we're handling asynchronous
exceptions mark every insn as reaching the active EH handler.
@ -837,6 +872,24 @@ make_edges (i)
}
}
}
while (pending_eh_region != NULL_RTX)
{
rtx insn = XEXP (pending_eh_region, 0);
rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
int region = XINT (XEXP (note, 0), 0);
/* start with the first region OUTSIDE the one specified
in the rethrow parameter */
for ( region = nested_eh_region[region]; region;
region = nested_eh_region[region])
{
handler_info *ptr = get_first_handler (region);
for ( ; ptr ; ptr = ptr->next)
add_edge_to_label (BLOCK_NUM (insn), ptr->handler_label);
}
pending_eh_region = XEXP (pending_eh_region, 1);
}
/* We know something about the structure of the function __throw in
libgcc2.c. It is the only function that ever contains eh_stub labels.
It modifies its return address so that the last block returns to one of
@ -918,8 +971,9 @@ delete_unreachable_blocks ()
NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
{
int num = CODE_LABEL_NUMBER (insn);
/* A NULL handler indicates a region is no longer needed */
if (get_first_handler (num) == NULL)
/* A NULL handler indicates a region is no longer needed,
unless its the target of a rethrow. */
if (get_first_handler (num) == NULL && !rethrow_used (num))
{
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;

View File

@ -265,6 +265,16 @@ static rtvec copy_asm_constraints_vector;
/* In save_for_inline, nonzero if past the parm-initialization insns. */
static int in_nonparm_insns;
/* subroutines passed to duplicate_eh_handlers to map exception labels */
static rtx
save_for_inline_eh_labelmap (label)
rtx label;
{
int index = CODE_LABEL_NUMBER (label);
return label_map[index];
}
/* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization
needed to save FNDECL's insns and info for future inline expansion. */
@ -667,19 +677,8 @@ save_for_inline_copying (fndecl)
/* we have to duplicate the handlers for the original */
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
{
handler_info *ptr, *temp;
int nr;
nr = new_eh_region_entry (new_region);
ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
for ( ; ptr; ptr = ptr->next)
{
temp = get_new_handler (
label_map[CODE_LABEL_NUMBER (ptr->handler_label)],
ptr->type_info);
add_new_handler (nr, temp);
}
}
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
save_for_inline_eh_labelmap);
/* We have to forward these both to match the new exception
region. */
@ -1075,11 +1074,15 @@ copy_for_inline (orig)
{
case QUEUED:
case CONST_INT:
case SYMBOL_REF:
case PC:
case CC0:
return x;
case SYMBOL_REF:
if (! SYMBOL_REF_NEED_ADJUST (x))
return x;
return rethrow_symbol_map (x, save_for_inline_eh_labelmap);
case CONST_DOUBLE:
/* We have to make a new CONST_DOUBLE to ensure that we account for
it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */
@ -1338,6 +1341,18 @@ process_reg_param (map, loc, copy)
}
map->reg_map[REGNO (loc)] = copy;
}
/* Used by duplicate_eh_handlers to map labels for the exception table */
static struct inline_remap *eif_eh_map;
static rtx
expand_inline_function_eh_labelmap (label)
rtx label;
{
int index = CODE_LABEL_NUMBER (label);
return get_label_from_map (eif_eh_map, index);
}
/* Integrate the procedure defined by FNDECL. Note that this function
may wind up calling itself. Since the static variables are not
reentrant, we do not assign them until after the possibility
@ -2055,17 +2070,12 @@ expand_inline_function (fndecl, parms, target, ignore, type,
/* we have to duplicate the handlers for the original */
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
{
handler_info *ptr, *temp;
int nr;
nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
for ( ; ptr; ptr = ptr->next)
{
temp = get_new_handler ( get_label_from_map (map,
CODE_LABEL_NUMBER (ptr->handler_label)),
ptr->type_info);
add_new_handler (nr, temp);
}
/* We need to duplicate the handlers for the EH region
and we need to indicate where the label map is */
eif_eh_map = map;
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy),
CODE_LABEL_NUMBER (label),
expand_inline_function_eh_labelmap);
}
/* We have to forward these both to match the new exception
@ -2533,6 +2543,13 @@ copy_rtx_and_substitute (orig, map)
map)),
0);
}
else
if (SYMBOL_REF_NEED_ADJUST (orig))
{
eif_eh_map = map;
return rethrow_symbol_map (orig,
expand_inline_function_eh_labelmap);
}
return orig;

View File

@ -3468,45 +3468,82 @@ old_find_exception_handler (void *pc, old_exception_table *table)
return (void *) 0;
}
/* find_exception_handler finds the correct handler, if there is one, to
handle an exception.
returns a pointer to the handler which controlled should be transferred
to, or NULL if there is nothing left.
Parameters:
PC - pc where the exception originates. If this is a rethrow,
then this starts out as a pointer to the exception table
entry we wish to rethrow out of.
TABLE - exception table for the current module.
EH_INFO - eh info pointer for this exception.
RETHROW - 1 if this is a rethrow. (see incoming value of PC).
CLEANUP - returned flag indicating whether this is a cleanup handler.
*/
static void *
find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
find_exception_handler (void *pc, exception_descriptor *table,
__eh_info *eh_info, int rethrow, int *cleanup)
{
void *retval = NULL;
*cleanup = 1;
if (table)
{
int pos = 0;
/* The new model assumed the table is sorted inner-most out so the
first region we find which matches is the correct one */
int pos;
void *ret;
exception_table *tab = &(table->table[0]);
/* Subtract 1 from the PC to avoid hitting the next region */
pc--;
if (rethrow)
{
/* pc is actually the region table entry to rethrow out of */
pos = ((exception_table *) pc) - tab;
pc = ((exception_table *) pc)->end_region - 1;
/* The label is always on the LAST handler entry for a region,
so we know the next entry is a different region, even if the
addresses are the same. Make sure its not end of table tho. */
if (tab[pos].start_region != (void *) -1)
pos++;
}
else
pc--;
/* We can't do a binary search because the table is in inner-most
to outermost address ranges within functions */
for (pos = 0; tab[pos].start_region != (void *) -1; pos++)
for ( ; tab[pos].start_region != (void *) -1; pos++)
{
if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
{
if (tab[pos].match_info)
{
__eh_matcher matcher = ((__eh_info *)eh_info)->match_function;
__eh_matcher matcher = eh_info->match_function;
/* match info but no matcher is NOT a match */
if (matcher)
{
ret = (*matcher)(eh_info, tab[pos].match_info, table);
if (ret)
return tab[pos].exception_handler;
void *ret = (*matcher)((void *) eh_info,
tab[pos].match_info, table);
if (ret)
{
if (retval == NULL)
retval = tab[pos].exception_handler;
*cleanup = 0;
break;
}
}
}
else
return tab[pos].exception_handler;
{
if (retval == NULL)
retval = tab[pos].exception_handler;
}
}
}
}
return (void *) 0;
return retval;
}
#endif /* DWARF2_UNWIND_INFO */
#endif /* EH_TABLE_LOOKUP */
@ -3643,54 +3680,47 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
return caller_udata;
}
/* We first search for an exception handler, and if we don't find
it, we call __terminate on the current stack frame so that we may
use the debugger to walk the stack and understand why no handler
was found.
If we find one, then we unwind the frames down to the one that
has the handler and transfer control into the handler. */
/*extern void __throw(void) __attribute__ ((__noreturn__));*/
void
__throw ()
/* Hook to call before __terminate if only cleanup handlers remain. */
void
__unwinding_cleanup ()
{
struct eh_context *eh = (*get_eh_context) ();
void *saved_pc, *pc, *handler;
frame_state ustruct, ustruct2;
frame_state *udata = &ustruct;
frame_state *sub_udata = &ustruct2;
frame_state my_ustruct, *my_udata = &my_ustruct;
long args_size;
int new_exception_model;
}
/* This is required for C++ semantics. We must call terminate if we
try and rethrow an exception, when there is no exception currently
active. */
if (! eh->info)
__terminate ();
/* Start at our stack frame. */
label:
udata = __frame_state_for (&&label, udata);
if (! udata)
__terminate ();
/* throw_helper performs some of the common grunt work for a throw. This
routine is called by throw and rethrows. This is pretty much split
out from the old __throw routine. An addition has been added which allows
for a dummy call to a routine __unwinding_cleanup() when there are nothing
but cleanups remaining. This allows a debugger to examine the state
at which the throw was executed, before any cleanups, rather than
at the terminate point after the stack has been unwound. */
/* We need to get the value from the CFA register. */
udata->cfa = __builtin_dwarf_cfa ();
static void *
throw_helper (eh, pc, my_udata, udata_p)
struct eh_context *eh;
void *pc;
frame_state *my_udata;
frame_state **udata_p;
{
frame_state *udata = *udata_p;
frame_state ustruct;
frame_state *sub_udata = &ustruct;
void *saved_pc = pc;
void *handler;
void *handler_p;
void *pc_p;
frame_state saved_ustruct;
int new_eh_model;
int cleanup = 0;
int only_cleanup = 0;
int rethrow = 0;
int saved_state = 0;
__eh_info *eh_info = (__eh_info *)eh->info;
memcpy (my_udata, udata, sizeof (*udata));
/* Do we find a handler based on a re-throw PC? */
if (eh->table_index != (void *) 0)
rethrow = 1;
/* Do any necessary initialization to access arbitrary stack frames.
On the SPARC, this means flushing the register windows. */
__builtin_unwind_init ();
/* Now reset pc to the right throw point. */
pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
saved_pc = pc;
handler = 0;
handler = (void *) 0;
for (;;)
{
frame_state *p = udata;
@ -3702,32 +3732,64 @@ label:
break;
if (udata->eh_ptr == NULL)
new_exception_model = 0;
new_eh_model = 0;
else
new_exception_model = (((exception_descriptor *)(udata->eh_ptr))->
new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
runtime_id_field == NEW_EH_RUNTIME);
if (new_exception_model)
handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
if (rethrow)
{
rethrow = 0;
handler = find_exception_handler (eh->table_index, udata->eh_ptr,
eh_info, 1, &cleanup);
eh->table_index = (void *)0;
}
else
handler = old_find_exception_handler (pc, udata->eh_ptr);
if (new_eh_model)
handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
0, &cleanup);
else
handler = old_find_exception_handler (pc, udata->eh_ptr);
/* If we found one, we can stop searching. */
/* If we found one, we can stop searching, if its not a cleanup.
for cleanups, we save the state, and keep looking. This allows
us to call a debug hook if there are nothing but cleanups left. */
if (handler)
{
args_size = udata->args_size;
break;
}
if (cleanup)
{
if (!saved_state)
{
saved_ustruct = *udata;
handler_p = handler;
pc_p = pc;
saved_state = 1;
only_cleanup = 1;
}
}
else
{
only_cleanup = 0;
break;
}
/* Otherwise, we continue searching. We subtract 1 from PC to avoid
hitting the beginning of the next region. */
pc = get_return_addr (udata, sub_udata) - 1;
}
if (saved_state)
{
udata = &saved_ustruct;
handler = handler_p;
pc = pc_p;
if (only_cleanup)
__unwinding_cleanup ();
}
/* If we haven't found a handler by now, this is an unhandled
exception. */
if (! handler)
__terminate ();
if (! handler)
__terminate();
eh->handler_label = handler;
@ -3781,6 +3843,114 @@ label:
copy_reg (i, udata, my_udata);
}
}
/* udata now refers to the frame called by the handler frame. */
*udata_p = udata;
return handler;
}
/* We first search for an exception handler, and if we don't find
it, we call __terminate on the current stack frame so that we may
use the debugger to walk the stack and understand why no handler
was found.
If we find one, then we unwind the frames down to the one that
has the handler and transfer control into the handler. */
/*extern void __throw(void) __attribute__ ((__noreturn__));*/
void
__throw ()
{
struct eh_context *eh = (*get_eh_context) ();
void *pc, *handler;
frame_state ustruct;
frame_state *udata = &ustruct;
frame_state my_ustruct, *my_udata = &my_ustruct;
/* This is required for C++ semantics. We must call terminate if we
try and rethrow an exception, when there is no exception currently
active. */
if (! eh->info)
__terminate ();
/* Start at our stack frame. */
label:
udata = __frame_state_for (&&label, udata);
if (! udata)
__terminate ();
/* We need to get the value from the CFA register. */
udata->cfa = __builtin_dwarf_cfa ();
memcpy (my_udata, udata, sizeof (*udata));
/* Do any necessary initialization to access arbitrary stack frames.
On the SPARC, this means flushing the register windows. */
__builtin_unwind_init ();
/* Now reset pc to the right throw point. */
pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
handler = throw_helper (eh, pc, my_udata, &udata);
/* Now go! */
__builtin_eh_return ((void *)eh,
#ifdef STACK_GROWS_DOWNWARD
udata->cfa - my_udata->cfa,
#else
my_udata->cfa - udata->cfa,
#endif
handler);
/* Epilogue: restore the handler frame's register values and return
to the stub. */
}
/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
void
__rethrow (index)
void *index;
{
struct eh_context *eh = (*get_eh_context) ();
void *pc, *handler;
frame_state ustruct;
frame_state *udata = &ustruct;
frame_state my_ustruct, *my_udata = &my_ustruct;
/* This is required for C++ semantics. We must call terminate if we
try and rethrow an exception, when there is no exception currently
active. */
if (! eh->info)
__terminate ();
/* This is the table index we want to rethrow from. The value of
the END_REGION label is used for the PC of the throw, and the
search begins with the next table entry. */
eh->table_index = index;
/* Start at our stack frame. */
label:
udata = __frame_state_for (&&label, udata);
if (! udata)
__terminate ();
/* We need to get the value from the CFA register. */
udata->cfa = __builtin_dwarf_cfa ();
memcpy (my_udata, udata, sizeof (*udata));
/* Do any necessary initialization to access arbitrary stack frames.
On the SPARC, this means flushing the register windows. */
__builtin_unwind_init ();
/* Now reset pc to the right throw point. */
pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
handler = throw_helper (eh, pc, my_udata, &udata);
/* Now go! */

View File

@ -119,6 +119,7 @@ rtx memset_libfunc;
rtx bzero_libfunc;
rtx throw_libfunc;
rtx rethrow_libfunc;
rtx sjthrow_libfunc;
rtx sjpopnthrow_libfunc;
rtx terminate_libfunc;
@ -4294,6 +4295,7 @@ init_optabs ()
bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");

View File

@ -193,7 +193,8 @@ char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
"REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
"REG_BR_PRED", "REG_EH_CONTEXT",
"REG_FRAME_RELATED_EXPR" };
"REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
"REG_EH_RETHROW" };
static void dump_and_abort PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
static void read_name PROTO((char *, FILE *));

View File

@ -340,6 +340,14 @@ typedef struct rtvec_def{
REG_FRAME_RELATED_EXPR is attached to insns that are RTX_FRAME_RELATED_P,
but are too complex for DWARF to interpret what they imply. The attached
rtx is used instead of intuition. */
/* REG_EH_REGION is used to indicate what exception region an INSN
belongs in. This can be used to indicate what region a call may throw
to. a REGION of 0 indicates that a call cannot throw at all.
REG_EH_RETHROW is used to indicate what that a call is actually a
call to rethrow, and specifies which region the rethrow is targetting.
This provides a way to generate the non standard flow edges required
for a rethrow. */
#define REG_NOTES(INSN) ((INSN)->fld[6].rtx)
@ -353,7 +361,8 @@ enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
REG_BR_PRED = 20, REG_EH_CONTEXT = 21,
REG_FRAME_RELATED_EXPR = 22 };
REG_FRAME_RELATED_EXPR = 22, REG_EH_REGION = 23,
REG_EH_RETHROW = 24 };
/* The base value for branch probability notes. */
#define REG_BR_PROB_BASE 10000
@ -617,6 +626,10 @@ extern char *note_insn_name[];
/* Flag in a SYMBOL_REF for machine-specific purposes. */
#define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
/* 1 in a SYMBOL_REF if it represents a symbol which might have to change
if its inlined or unrolled. */
#define SYMBOL_REF_NEED_ADJUST(RTX) ((RTX)->in_struct)
/* 1 means a SYMBOL_REF has been the library function in emit_library_call. */
#define SYMBOL_REF_USED(RTX) ((RTX)->used)