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)
|
Tue Dec 8 13:11:04 1998 Jeffrey A Law (law@cygnus.com)
|
||||||
|
|
||||||
* reload1.c (current_function_decl): Tweak declaration.
|
* 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)
|
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
|
* Make-lang.in (cxxmain.o): Depend on $(DEMANGLE_H), not demangle.h
|
||||||
|
|
|
@ -249,14 +249,14 @@ call_eh_info ()
|
||||||
{
|
{
|
||||||
tree fn;
|
tree fn;
|
||||||
|
|
||||||
fn = get_identifier ("__cp_eh_info");
|
fn = get_identifier ("__start_cp_handler");
|
||||||
if (IDENTIFIER_GLOBAL_VALUE (fn))
|
if (IDENTIFIER_GLOBAL_VALUE (fn))
|
||||||
fn = IDENTIFIER_GLOBAL_VALUE (fn);
|
fn = IDENTIFIER_GLOBAL_VALUE (fn);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tree t1, t, fields[7];
|
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. */
|
as defined in exception.cc. */
|
||||||
push_obstacks_nochange ();
|
push_obstacks_nochange ();
|
||||||
end_temporary_allocation ();
|
end_temporary_allocation ();
|
||||||
|
@ -270,9 +270,11 @@ call_eh_info ()
|
||||||
get_identifier ("dynamic_handler_chain"), ptr_type_node);
|
get_identifier ("dynamic_handler_chain"), ptr_type_node);
|
||||||
fields[2] = build_lang_field_decl (FIELD_DECL,
|
fields[2] = build_lang_field_decl (FIELD_DECL,
|
||||||
get_identifier ("info"), ptr_type_node);
|
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
|
/* N.B.: The fourth field LEN is expected to be
|
||||||
the number of fields - 1, not the total number of fields. */
|
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 = build_pointer_type (t1);
|
||||||
|
|
||||||
t1= make_lang_type (RECORD_TYPE);
|
t1= make_lang_type (RECORD_TYPE);
|
||||||
|
@ -547,9 +549,6 @@ push_eh_cleanup ()
|
||||||
{
|
{
|
||||||
int yes;
|
int yes;
|
||||||
|
|
||||||
expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
|
|
||||||
const0_rtx, VOIDmode, EXPAND_NORMAL);
|
|
||||||
|
|
||||||
yes = suspend_momentary ();
|
yes = suspend_momentary ();
|
||||||
/* All cleanups must last longer than normal. */
|
/* All cleanups must last longer than normal. */
|
||||||
expand_decl_cleanup (NULL_TREE, do_pop_exception ());
|
expand_decl_cleanup (NULL_TREE, do_pop_exception ());
|
||||||
|
@ -701,9 +700,6 @@ process_start_catch_block (declspecs, declarator)
|
||||||
/* Fall into the catch all section. */
|
/* 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);
|
emit_line_note (input_filename, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,13 +117,29 @@ __cp_exception_info (void)
|
||||||
return &((*__get_eh_info ())->value);
|
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 (). */
|
Used by get_eh_info (). */
|
||||||
|
|
||||||
extern "C" cp_eh_info *
|
extern "C" cp_eh_info *
|
||||||
__cp_eh_info (void)
|
__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,
|
/* 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
|
extern "C" void
|
||||||
__uncatch_exception (void)
|
__uncatch_exception (void)
|
||||||
{
|
{
|
||||||
cp_eh_info *p = __cp_eh_info ();
|
cp_eh_info *p = CP_EH_INFO;
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
terminate ();
|
terminate ();
|
||||||
p->caught = false;
|
p->caught = false;
|
||||||
|
@ -263,7 +279,7 @@ __uncatch_exception (void)
|
||||||
extern "C" void
|
extern "C" void
|
||||||
__check_eh_spec (int n, const void **spec)
|
__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)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
|
@ -316,7 +332,7 @@ __throw_bad_typeid (void)
|
||||||
bool
|
bool
|
||||||
std::uncaught_exception ()
|
std::uncaught_exception ()
|
||||||
{
|
{
|
||||||
cp_eh_info *p = __cp_eh_info ();
|
cp_eh_info *p = CP_EH_INFO;
|
||||||
return p && ! p->caught;
|
return p && ! p->caught;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ struct eh_context
|
||||||
void **dynamic_handler_chain;
|
void **dynamic_handler_chain;
|
||||||
/* This is language dependent part of the eh context. */
|
/* This is language dependent part of the eh context. */
|
||||||
void *info;
|
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
|
#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 "recog.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "toplev.h"
|
#include "toplev.h"
|
||||||
|
#include "obstack.h"
|
||||||
|
|
||||||
/* One to use setjmp/longjmp method of generating code for exception
|
/* One to use setjmp/longjmp method of generating code for exception
|
||||||
handling. */
|
handling. */
|
||||||
|
@ -502,6 +503,15 @@ static rtx eh_return_handler;
|
||||||
|
|
||||||
rtx eh_return_stub_label;
|
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. */
|
/* Prototypes for local functions. */
|
||||||
|
|
||||||
static void push_eh_entry PROTO((struct eh_stack *));
|
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
|
/* Various support routines to manipulate the various data structures
|
||||||
used by the exception handling code. */
|
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. */
|
/* Push a label entry onto the given STACK. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -600,11 +633,16 @@ push_eh_entry (stack)
|
||||||
struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
|
struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
|
||||||
struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
|
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->finalization = NULL_TREE;
|
||||||
entry->label_used = 0;
|
entry->label_used = 0;
|
||||||
entry->exception_handler_label = gen_exception_label ();
|
entry->exception_handler_label = rlab;
|
||||||
entry->false_label = NULL_RTX;
|
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->entry = entry;
|
||||||
node->chain = stack->top;
|
node->chain = stack->top;
|
||||||
|
@ -707,6 +745,7 @@ receive_exception_label (handler_label)
|
||||||
struct func_eh_entry
|
struct func_eh_entry
|
||||||
{
|
{
|
||||||
int range_number; /* EH region number from EH NOTE insn's */
|
int range_number; /* EH region number from EH NOTE insn's */
|
||||||
|
rtx rethrow_label; /* Label for rethrow */
|
||||||
struct handler_info *handlers;
|
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)
|
#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
|
/* 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. */
|
returned is an number which uniquely identifies this exception range. */
|
||||||
|
|
||||||
int
|
static int
|
||||||
new_eh_region_entry (note_eh_region)
|
new_eh_region_entry (note_eh_region, rethrow)
|
||||||
int note_eh_region;
|
int note_eh_region;
|
||||||
|
rtx rethrow;
|
||||||
{
|
{
|
||||||
if (current_func_eh_entry == num_func_eh_entries)
|
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;
|
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;
|
function_eh_regions[current_func_eh_entry].handlers = NULL;
|
||||||
|
|
||||||
return current_func_eh_entry++;
|
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
|
/* 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
|
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;
|
int old_note_eh_region, new_note_eh_region;
|
||||||
|
rtx (*map)(rtx);
|
||||||
{
|
{
|
||||||
struct handler_info *ptr, *new_ptr;
|
struct handler_info *ptr, *new_ptr;
|
||||||
int new_region, region;
|
int new_region, region;
|
||||||
|
rtx tmp;
|
||||||
|
|
||||||
region = find_func_region (old_note_eh_region);
|
region = find_func_region (old_note_eh_region);
|
||||||
if (region == -1)
|
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)
|
/* duplicate_eh_handlers may have been called during a symbol remap. */
|
||||||
error ("Cannot duplicate EH region because new note region already exists");
|
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;
|
ptr = function_eh_regions[region].handlers;
|
||||||
|
|
||||||
for ( ; ptr; ptr = ptr->next)
|
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);
|
add_new_handler (new_region, new_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_region;
|
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.
|
/* Routine to see if exception handling is turned on.
|
||||||
DO_WARN is non-zero if we want to inform the user that exception
|
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;
|
struct eh_entry *entry;
|
||||||
rtx note;
|
rtx note;
|
||||||
|
int ret, r;
|
||||||
|
|
||||||
if (! doing_eh (0))
|
if (! doing_eh (0))
|
||||||
return;
|
return;
|
||||||
|
@ -1417,9 +1528,9 @@ expand_eh_region_end (handler)
|
||||||
entry = pop_eh_entry (&ehstack);
|
entry = pop_eh_entry (&ehstack);
|
||||||
|
|
||||||
note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
|
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);
|
= 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. */
|
/* We share outer_context between regions; only emit it once. */
|
||||||
&& INSN_UID (entry->outer_context) == 0)
|
&& INSN_UID (entry->outer_context) == 0)
|
||||||
{
|
{
|
||||||
|
@ -1439,7 +1550,7 @@ expand_eh_region_end (handler)
|
||||||
entry->finalization = handler;
|
entry->finalization = handler;
|
||||||
|
|
||||||
/* create region entry in final exception table */
|
/* 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);
|
enqueue_eh_entry (&ehqueue, entry);
|
||||||
|
|
||||||
|
@ -1673,8 +1784,14 @@ start_catch_handler (rtime)
|
||||||
void
|
void
|
||||||
end_catch_handler ()
|
end_catch_handler ()
|
||||||
{
|
{
|
||||||
if (! doing_eh (1) || (flag_new_exceptions && ! exceptions_via_longjmp))
|
if (! doing_eh (1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (flag_new_exceptions && ! exceptions_via_longjmp)
|
||||||
|
{
|
||||||
|
emit_barrier ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* A NULL label implies the catch clause was a catch all or cleanup */
|
/* A NULL label implies the catch clause was a catch all or cleanup */
|
||||||
if (catchstack.top->entry->false_label == NULL_RTX)
|
if (catchstack.top->entry->false_label == NULL_RTX)
|
||||||
|
@ -1786,7 +1903,7 @@ expand_start_all_catch ()
|
||||||
void
|
void
|
||||||
expand_end_all_catch ()
|
expand_end_all_catch ()
|
||||||
{
|
{
|
||||||
rtx new_catch_clause, outer_context = NULL_RTX;
|
rtx new_catch_clause;
|
||||||
struct eh_entry *entry;
|
struct eh_entry *entry;
|
||||||
|
|
||||||
if (! doing_eh (1))
|
if (! doing_eh (1))
|
||||||
|
@ -1798,11 +1915,17 @@ expand_end_all_catch ()
|
||||||
|
|
||||||
if (! exceptions_via_longjmp)
|
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. */
|
/* Finish the rethrow region. size_zero_node is just a NOP. */
|
||||||
expand_eh_region_end (size_zero_node);
|
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
|
/* 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
|
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
|
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
|
thrown from) so that the outer EH region can then try to process
|
||||||
the exception. */
|
the exception. */
|
||||||
expand_rethrow (outer_context);
|
|
||||||
|
|
||||||
/* Now we have the complete catch sequence. */
|
/* Now we have the complete catch sequence. */
|
||||||
new_catch_clause = get_insns ();
|
new_catch_clause = get_insns ();
|
||||||
|
@ -1842,7 +1964,22 @@ expand_rethrow (label)
|
||||||
if (exceptions_via_longjmp)
|
if (exceptions_via_longjmp)
|
||||||
emit_throw ();
|
emit_throw ();
|
||||||
else
|
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
|
/* End all the pending exception regions on protect_list. The handlers
|
||||||
|
@ -1976,12 +2113,29 @@ output_exception_table_entry (file, n)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
rtx sym;
|
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);
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
||||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
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);
|
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||||
|
|
||||||
assemble_integer (handler->handler_label,
|
if (handler == NULL)
|
||||||
POINTER_SIZE / BITS_PER_UNIT, 1);
|
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 (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);
|
assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||||
else
|
else
|
||||||
if (handler->type_info == CATCH_ALL_TYPE)
|
if (handler->type_info == CATCH_ALL_TYPE)
|
||||||
|
@ -2007,7 +2164,7 @@ output_exception_table_entry (file, n)
|
||||||
}
|
}
|
||||||
putc ('\n', file); /* blank line */
|
putc ('\n', file); /* blank line */
|
||||||
/* We only output the first label under the old scheme */
|
/* We only output the first label under the old scheme */
|
||||||
if (! flag_new_exceptions)
|
if (! flag_new_exceptions || handler == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2038,6 +2195,7 @@ void
|
||||||
output_exception_table ()
|
output_exception_table ()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
char buf[256];
|
||||||
extern FILE *asm_out_file;
|
extern FILE *asm_out_file;
|
||||||
|
|
||||||
if (! doing_eh (0) || ! eh_table)
|
if (! doing_eh (0) || ! eh_table)
|
||||||
|
@ -2062,6 +2220,10 @@ output_exception_table ()
|
||||||
;
|
;
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
assemble_integer (const0_rtx, i , 1);
|
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)
|
for (i = 0; i < eh_table_size; ++i)
|
||||||
|
@ -2071,6 +2233,9 @@ output_exception_table ()
|
||||||
clear_function_eh_region ();
|
clear_function_eh_region ();
|
||||||
|
|
||||||
/* Ending marker for table. */
|
/* 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_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||||
|
|
||||||
/* for binary compatability, the old __throw checked the second
|
/* for binary compatability, the old __throw checked the second
|
||||||
|
@ -2229,6 +2394,10 @@ check_exception_handler_labels ()
|
||||||
void
|
void
|
||||||
init_eh ()
|
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. */
|
/* Initialize the per-function EH information. */
|
||||||
|
@ -2348,6 +2517,11 @@ scan_region (insn, n, delete_outer)
|
||||||
/* Assume we can delete the region. */
|
/* Assume we can delete the region. */
|
||||||
int delete = 1;
|
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
|
if (insn == NULL_RTX
|
||||||
|| GET_CODE (insn) != NOTE
|
|| GET_CODE (insn) != NOTE
|
||||||
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
|
|| 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;
|
tree finalization;
|
||||||
int label_used;
|
int label_used;
|
||||||
rtx false_label;
|
rtx false_label;
|
||||||
|
rtx rethrow_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
|
/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
|
||||||
|
@ -177,13 +178,6 @@ typedef struct handler_info
|
||||||
} 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
|
/* Add new handler information to an exception range. The first parameter
|
||||||
specifies the range number (returned from new_eh_entry()). The second
|
specifies the range number (returned from new_eh_entry()). The second
|
||||||
parameter specifies the handler. By default the handler is inserted at
|
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
|
/* 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. */
|
||||||
|
|
||||||
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. */
|
/* 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 bzero_libfunc;
|
||||||
|
|
||||||
extern rtx throw_libfunc;
|
extern rtx throw_libfunc;
|
||||||
|
extern rtx rethrow_libfunc;
|
||||||
extern rtx sjthrow_libfunc;
|
extern rtx sjthrow_libfunc;
|
||||||
extern rtx sjpopnthrow_libfunc;
|
extern rtx sjpopnthrow_libfunc;
|
||||||
extern rtx terminate_libfunc;
|
extern rtx terminate_libfunc;
|
||||||
|
|
58
gcc/flow.c
58
gcc/flow.c
|
@ -721,6 +721,7 @@ make_edges (i)
|
||||||
int i;
|
int i;
|
||||||
{
|
{
|
||||||
rtx insn, x;
|
rtx insn, x;
|
||||||
|
rtx pending_eh_region = NULL_RTX;
|
||||||
|
|
||||||
/* See if control drops into the next block. */
|
/* See if control drops into the next block. */
|
||||||
if (i + 1 < n_basic_blocks)
|
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
|
/* If this is a CALL_INSN, then mark it as reaching the active EH
|
||||||
handler for this CALL_INSN. If we're handling asynchronous
|
handler for this CALL_INSN. If we're handling asynchronous
|
||||||
exceptions mark every insn as reaching the active EH handler.
|
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
|
/* We know something about the structure of the function __throw in
|
||||||
libgcc2.c. It is the only function that ever contains eh_stub labels.
|
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
|
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)
|
NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
|
||||||
{
|
{
|
||||||
int num = CODE_LABEL_NUMBER (insn);
|
int num = CODE_LABEL_NUMBER (insn);
|
||||||
/* A NULL handler indicates a region is no longer needed */
|
/* A NULL handler indicates a region is no longer needed,
|
||||||
if (get_first_handler (num) == NULL)
|
unless its the target of a rethrow. */
|
||||||
|
if (get_first_handler (num) == NULL && !rethrow_used (num))
|
||||||
{
|
{
|
||||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||||
NOTE_SOURCE_FILE (insn) = 0;
|
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. */
|
/* In save_for_inline, nonzero if past the parm-initialization insns. */
|
||||||
static int in_nonparm_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
|
/* Subroutine for `save_for_inline{copying,nocopy}'. Performs initialization
|
||||||
needed to save FNDECL's insns and info for future inline expansion. */
|
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 */
|
/* we have to duplicate the handlers for the original */
|
||||||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
||||||
{
|
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
|
||||||
handler_info *ptr, *temp;
|
save_for_inline_eh_labelmap);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have to forward these both to match the new exception
|
/* We have to forward these both to match the new exception
|
||||||
region. */
|
region. */
|
||||||
|
@ -1075,11 +1074,15 @@ copy_for_inline (orig)
|
||||||
{
|
{
|
||||||
case QUEUED:
|
case QUEUED:
|
||||||
case CONST_INT:
|
case CONST_INT:
|
||||||
case SYMBOL_REF:
|
|
||||||
case PC:
|
case PC:
|
||||||
case CC0:
|
case CC0:
|
||||||
return x;
|
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:
|
case CONST_DOUBLE:
|
||||||
/* We have to make a new CONST_DOUBLE to ensure that we account for
|
/* 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. */
|
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;
|
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
|
/* Integrate the procedure defined by FNDECL. Note that this function
|
||||||
may wind up calling itself. Since the static variables are not
|
may wind up calling itself. Since the static variables are not
|
||||||
reentrant, we do not assign them until after the possibility
|
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 */
|
/* we have to duplicate the handlers for the original */
|
||||||
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
|
||||||
{
|
{
|
||||||
handler_info *ptr, *temp;
|
/* We need to duplicate the handlers for the EH region
|
||||||
int nr;
|
and we need to indicate where the label map is */
|
||||||
nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
|
eif_eh_map = map;
|
||||||
ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
|
duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy),
|
||||||
for ( ; ptr; ptr = ptr->next)
|
CODE_LABEL_NUMBER (label),
|
||||||
{
|
expand_inline_function_eh_labelmap);
|
||||||
temp = get_new_handler ( get_label_from_map (map,
|
|
||||||
CODE_LABEL_NUMBER (ptr->handler_label)),
|
|
||||||
ptr->type_info);
|
|
||||||
add_new_handler (nr, temp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have to forward these both to match the new exception
|
/* We have to forward these both to match the new exception
|
||||||
|
@ -2533,6 +2543,13 @@ copy_rtx_and_substitute (orig, map)
|
||||||
map)),
|
map)),
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if (SYMBOL_REF_NEED_ADJUST (orig))
|
||||||
|
{
|
||||||
|
eif_eh_map = map;
|
||||||
|
return rethrow_symbol_map (orig,
|
||||||
|
expand_inline_function_eh_labelmap);
|
||||||
|
}
|
||||||
|
|
||||||
return orig;
|
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;
|
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 *
|
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)
|
if (table)
|
||||||
{
|
{
|
||||||
|
int pos = 0;
|
||||||
/* The new model assumed the table is sorted inner-most out so the
|
/* The new model assumed the table is sorted inner-most out so the
|
||||||
first region we find which matches is the correct one */
|
first region we find which matches is the correct one */
|
||||||
|
|
||||||
int pos;
|
|
||||||
void *ret;
|
|
||||||
exception_table *tab = &(table->table[0]);
|
exception_table *tab = &(table->table[0]);
|
||||||
|
|
||||||
/* Subtract 1 from the PC to avoid hitting the next region */
|
/* 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
|
/* We can't do a binary search because the table is in inner-most
|
||||||
to outermost address ranges within functions */
|
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].start_region <= pc && tab[pos].end_region > pc)
|
||||||
{
|
{
|
||||||
if (tab[pos].match_info)
|
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 */
|
/* match info but no matcher is NOT a match */
|
||||||
if (matcher)
|
if (matcher)
|
||||||
{
|
{
|
||||||
ret = (*matcher)(eh_info, tab[pos].match_info, table);
|
void *ret = (*matcher)((void *) eh_info,
|
||||||
if (ret)
|
tab[pos].match_info, table);
|
||||||
return tab[pos].exception_handler;
|
if (ret)
|
||||||
|
{
|
||||||
|
if (retval == NULL)
|
||||||
|
retval = tab[pos].exception_handler;
|
||||||
|
*cleanup = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return tab[pos].exception_handler;
|
{
|
||||||
|
if (retval == NULL)
|
||||||
|
retval = tab[pos].exception_handler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return retval;
|
||||||
return (void *) 0;
|
|
||||||
}
|
}
|
||||||
#endif /* DWARF2_UNWIND_INFO */
|
#endif /* DWARF2_UNWIND_INFO */
|
||||||
#endif /* EH_TABLE_LOOKUP */
|
#endif /* EH_TABLE_LOOKUP */
|
||||||
|
@ -3643,54 +3680,47 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
|
||||||
return caller_udata;
|
return caller_udata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We first search for an exception handler, and if we don't find
|
/* Hook to call before __terminate if only cleanup handlers remain. */
|
||||||
it, we call __terminate on the current stack frame so that we may
|
void
|
||||||
use the debugger to walk the stack and understand why no handler
|
__unwinding_cleanup ()
|
||||||
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 *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
|
/* throw_helper performs some of the common grunt work for a throw. This
|
||||||
try and rethrow an exception, when there is no exception currently
|
routine is called by throw and rethrows. This is pretty much split
|
||||||
active. */
|
out from the old __throw routine. An addition has been added which allows
|
||||||
if (! eh->info)
|
for a dummy call to a routine __unwinding_cleanup() when there are nothing
|
||||||
__terminate ();
|
but cleanups remaining. This allows a debugger to examine the state
|
||||||
|
at which the throw was executed, before any cleanups, rather than
|
||||||
/* Start at our stack frame. */
|
at the terminate point after the stack has been unwound. */
|
||||||
label:
|
|
||||||
udata = __frame_state_for (&&label, udata);
|
|
||||||
if (! udata)
|
|
||||||
__terminate ();
|
|
||||||
|
|
||||||
/* We need to get the value from the CFA register. */
|
static void *
|
||||||
udata->cfa = __builtin_dwarf_cfa ();
|
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.
|
handler = (void *) 0;
|
||||||
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;
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
frame_state *p = udata;
|
frame_state *p = udata;
|
||||||
|
@ -3702,32 +3732,64 @@ label:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (udata->eh_ptr == NULL)
|
if (udata->eh_ptr == NULL)
|
||||||
new_exception_model = 0;
|
new_eh_model = 0;
|
||||||
else
|
else
|
||||||
new_exception_model = (((exception_descriptor *)(udata->eh_ptr))->
|
new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
|
||||||
runtime_id_field == NEW_EH_RUNTIME);
|
runtime_id_field == NEW_EH_RUNTIME);
|
||||||
|
|
||||||
if (new_exception_model)
|
if (rethrow)
|
||||||
handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
|
{
|
||||||
|
rethrow = 0;
|
||||||
|
handler = find_exception_handler (eh->table_index, udata->eh_ptr,
|
||||||
|
eh_info, 1, &cleanup);
|
||||||
|
eh->table_index = (void *)0;
|
||||||
|
}
|
||||||
else
|
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)
|
if (handler)
|
||||||
{
|
if (cleanup)
|
||||||
args_size = udata->args_size;
|
{
|
||||||
break;
|
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
|
/* Otherwise, we continue searching. We subtract 1 from PC to avoid
|
||||||
hitting the beginning of the next region. */
|
hitting the beginning of the next region. */
|
||||||
pc = get_return_addr (udata, sub_udata) - 1;
|
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
|
/* If we haven't found a handler by now, this is an unhandled
|
||||||
exception. */
|
exception. */
|
||||||
if (! handler)
|
if (! handler)
|
||||||
__terminate ();
|
__terminate();
|
||||||
|
|
||||||
eh->handler_label = handler;
|
eh->handler_label = handler;
|
||||||
|
|
||||||
|
@ -3781,6 +3843,114 @@ label:
|
||||||
copy_reg (i, udata, my_udata);
|
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! */
|
/* Now go! */
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ rtx memset_libfunc;
|
||||||
rtx bzero_libfunc;
|
rtx bzero_libfunc;
|
||||||
|
|
||||||
rtx throw_libfunc;
|
rtx throw_libfunc;
|
||||||
|
rtx rethrow_libfunc;
|
||||||
rtx sjthrow_libfunc;
|
rtx sjthrow_libfunc;
|
||||||
rtx sjpopnthrow_libfunc;
|
rtx sjpopnthrow_libfunc;
|
||||||
rtx terminate_libfunc;
|
rtx terminate_libfunc;
|
||||||
|
@ -4294,6 +4295,7 @@ init_optabs ()
|
||||||
bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
|
bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
|
||||||
|
|
||||||
throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
|
throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
|
||||||
|
rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
|
||||||
sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
|
sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
|
||||||
sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
|
sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
|
||||||
terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
|
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_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
|
||||||
"REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
|
"REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
|
||||||
"REG_BR_PRED", "REG_EH_CONTEXT",
|
"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 dump_and_abort PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
|
||||||
static void read_name PROTO((char *, FILE *));
|
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,
|
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
|
but are too complex for DWARF to interpret what they imply. The attached
|
||||||
rtx is used instead of intuition. */
|
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)
|
#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_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
|
||||||
REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
|
REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
|
||||||
REG_BR_PRED = 20, REG_EH_CONTEXT = 21,
|
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. */
|
/* The base value for branch probability notes. */
|
||||||
#define REG_BR_PROB_BASE 10000
|
#define REG_BR_PROB_BASE 10000
|
||||||
|
|
||||||
|
@ -617,6 +626,10 @@ extern char *note_insn_name[];
|
||||||
/* Flag in a SYMBOL_REF for machine-specific purposes. */
|
/* Flag in a SYMBOL_REF for machine-specific purposes. */
|
||||||
#define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
|
#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. */
|
/* 1 means a SYMBOL_REF has been the library function in emit_library_call. */
|
||||||
#define SYMBOL_REF_USED(RTX) ((RTX)->used)
|
#define SYMBOL_REF_USED(RTX) ((RTX)->used)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue