mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-24 07:20:29 +08:00
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:
parent
2bfdc2d4e7
commit
e6cfb550ab
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
228
gcc/except.c
228
gcc/except.c
@ -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
|
||||
|
21
gcc/except.h
21
gcc/except.h
@ -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. */
|
||||
|
||||
|
@ -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;
|
||||
|
58
gcc/flow.c
58
gcc/flow.c
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
304
gcc/libgcc2.c
304
gcc/libgcc2.c
@ -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! */
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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 *));
|
||||
|
15
gcc/rtl.h
15
gcc/rtl.h
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user