diff options
author | Alexander Kabaev <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
---|---|---|
committer | Alexander Kabaev <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
commit | bd0df3aa27aac083bd60b649fa5347076a5126eb (patch) | |
tree | f6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/except.c | |
parent | fabd8bcd49e1046bc9abdcb4efaea04638630b6f (diff) |
Gcc 3.3.1-pre as of 2003-07-11.
Notes
Notes:
svn path=/vendor/gcc/dist/; revision=117395
Diffstat (limited to 'contrib/gcc/except.c')
-rw-r--r-- | contrib/gcc/except.c | 746 |
1 files changed, 266 insertions, 480 deletions
diff --git a/contrib/gcc/except.c b/contrib/gcc/except.c index a258731e5cf1..b6f851bcbfb1 100644 --- a/contrib/gcc/except.c +++ b/contrib/gcc/except.c @@ -70,15 +70,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ggc.h" #include "tm_p.h" #include "target.h" +#include "langhooks.h" /* Provide defaults for stuff that may not be defined when using sjlj exceptions. */ -#ifndef EH_RETURN_STACKADJ_RTX -#define EH_RETURN_STACKADJ_RTX 0 -#endif -#ifndef EH_RETURN_HANDLER_RTX -#define EH_RETURN_HANDLER_RTX 0 -#endif #ifndef EH_RETURN_DATA_REGNO #define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM #endif @@ -99,20 +94,18 @@ tree (*lang_eh_runtime_type) PARAMS ((tree)); /* A hash table of label to region number. */ -struct ehl_map_entry +struct ehl_map_entry GTY(()) { rtx label; struct eh_region *region; }; -static htab_t exception_handler_label_map; - static int call_site_base; -static unsigned int sjlj_funcdef_number; -static htab_t type_to_runtime_map; +static GTY ((param_is (union tree_node))) + htab_t type_to_runtime_map; /* Describe the SjLj_Function_Context structure. */ -static tree sjlj_fc_type_node; +static GTY(()) tree sjlj_fc_type_node; static int sjlj_fc_call_site_ofs; static int sjlj_fc_data_ofs; static int sjlj_fc_personality_ofs; @@ -120,7 +113,7 @@ static int sjlj_fc_lsda_ofs; static int sjlj_fc_jbuf_ofs; /* Describes one exception region. */ -struct eh_region +struct eh_region GTY(()) { /* The immediately surrounding region. */ struct eh_region *outer; @@ -150,50 +143,51 @@ struct eh_region } type; /* Holds the action to perform based on the preceding type. */ - union { + union eh_region_u { /* A list of catch blocks, a surrounding try block, and the label for continuing after a catch. */ - struct { + struct eh_region_u_try { struct eh_region *catch; struct eh_region *last_catch; struct eh_region *prev_try; rtx continue_label; - } try; + } GTY ((tag ("ERT_TRY"))) try; /* The list through the catch handlers, the list of type objects matched, and the list of associated filters. */ - struct { + struct eh_region_u_catch { struct eh_region *next_catch; struct eh_region *prev_catch; tree type_list; tree filter_list; - } catch; + } GTY ((tag ("ERT_CATCH"))) catch; /* A tree_list of allowed types. */ - struct { + struct eh_region_u_allowed { tree type_list; int filter; - } allowed; + } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed; /* The type given by a call to "throw foo();", or discovered for a throw. */ - struct { + struct eh_region_u_throw { tree type; - } throw; + } GTY ((tag ("ERT_THROW"))) throw; /* Retain the cleanup expression even after expansion so that we can match up fixup regions. */ - struct { + struct eh_region_u_cleanup { tree exp; - } cleanup; + struct eh_region *prev_try; + } GTY ((tag ("ERT_CLEANUP"))) cleanup; /* The real region (by expression and by pointer) that fixup code should live in. */ - struct { + struct eh_region_u_fixup { tree cleanup_exp; struct eh_region *real_region; - } fixup; - } u; + } GTY ((tag ("ERT_FIXUP"))) fixup; + } GTY ((desc ("%0.type"))) u; /* Entry point for this region's handler before landing pads are built. */ rtx label; @@ -207,16 +201,25 @@ struct eh_region /* The RESX insn for handing off control to the next outermost handler, if appropriate. */ rtx resume; + + /* True if something in this region may throw. */ + unsigned may_contain_throw : 1; +}; + +struct call_site_record GTY(()) +{ + rtx landing_pad; + int action; }; /* Used to save exception status for each function. */ -struct eh_status +struct eh_status GTY(()) { /* The tree of all regions for this function. */ struct eh_region *region_tree; /* The same information as an indexable array. */ - struct eh_region **region_array; + struct eh_region ** GTY ((length ("%h.last_region_number"))) region_array; /* The most recently open region. */ struct eh_region *cur_region; @@ -224,12 +227,6 @@ struct eh_status /* This is the region for which we are processing catch blocks. */ struct eh_region *try_region; - /* A stack (TREE_LIST) of lists of handlers. The TREE_VALUE of each - node is itself a TREE_CHAINed list of handlers for regions that - are not yet closed. The TREE_VALUE of each entry contains the - handler for the corresponding entry on the ehstack. */ - tree protect_list; - rtx filter; rtx exc_ptr; @@ -240,11 +237,10 @@ struct eh_status varray_type ehspec_data; varray_type action_record_data; - struct call_site_record - { - rtx landing_pad; - int action; - } *call_site_data; + htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map; + + struct call_site_record * GTY ((length ("%h.call_site_data_used"))) + call_site_data; int call_site_data_used; int call_site_data_size; @@ -257,17 +253,9 @@ struct eh_status }; -static void mark_eh_region PARAMS ((struct eh_region *)); -static int mark_ehl_map_entry PARAMS ((PTR *, PTR)); -static void mark_ehl_map PARAMS ((void *)); - -static void free_region PARAMS ((struct eh_region *)); - static int t2r_eq PARAMS ((const PTR, const PTR)); static hashval_t t2r_hash PARAMS ((const PTR)); -static int t2r_mark_1 PARAMS ((PTR *, PTR)); -static void t2r_mark PARAMS ((PTR)); static void add_type_for_runtime PARAMS ((tree)); static tree lookup_type_for_runtime PARAMS ((tree)); @@ -315,7 +303,6 @@ static void sjlj_build_landing_pads PARAMS ((void)); static hashval_t ehl_hash PARAMS ((const PTR)); static int ehl_eq PARAMS ((const PTR, const PTR)); -static void ehl_free PARAMS ((PTR)); static void add_ehl_entry PARAMS ((rtx, struct eh_region *)); static void remove_exception_handler_label PARAMS ((rtx)); @@ -364,7 +351,7 @@ static void sjlj_output_call_site_table PARAMS ((void)); /* 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 nonzero if we want to inform the user that exception handling is turned off. This is used to ensure that -fexceptions has been specified if the @@ -391,13 +378,10 @@ doing_eh (do_warn) void init_eh () { - ggc_add_root (&exception_handler_label_map, 1, 1, mark_ehl_map); - if (! flag_exceptions) return; - type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL); - ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark); + type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL); /* Create the SjLj_Function_Context structure. This should match the definition in unwind-sjlj.c. */ @@ -405,8 +389,7 @@ init_eh () { tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp; - sjlj_fc_type_node = make_lang_type (RECORD_TYPE); - ggc_add_tree_root (&sjlj_fc_type_node, 1); + sjlj_fc_type_node = (*lang_hooks.types.make_type) (RECORD_TYPE); f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"), build_pointer_type (sjlj_fc_type_node)); @@ -417,7 +400,8 @@ init_eh () DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node; tmp = build_index_type (build_int_2 (4 - 1, 0)); - tmp = build_array_type (type_for_mode (word_mode, 1), tmp); + tmp = build_array_type ((*lang_hooks.types.type_for_mode) (word_mode, 1), + tmp); f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp); DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node; @@ -488,210 +472,9 @@ init_eh () void init_eh_for_function () { - cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status)); + cfun->eh = (struct eh_status *) + ggc_alloc_cleared (sizeof (struct eh_status)); } - -/* Mark EH for GC. */ - -static void -mark_eh_region (region) - struct eh_region *region; -{ - if (! region) - return; - - switch (region->type) - { - case ERT_UNKNOWN: - /* This can happen if a nested function is inside the body of a region - and we do a GC as part of processing it. */ - break; - case ERT_CLEANUP: - ggc_mark_tree (region->u.cleanup.exp); - break; - case ERT_TRY: - ggc_mark_rtx (region->u.try.continue_label); - break; - case ERT_CATCH: - ggc_mark_tree (region->u.catch.type_list); - ggc_mark_tree (region->u.catch.filter_list); - break; - case ERT_ALLOWED_EXCEPTIONS: - ggc_mark_tree (region->u.allowed.type_list); - break; - case ERT_MUST_NOT_THROW: - break; - case ERT_THROW: - ggc_mark_tree (region->u.throw.type); - break; - case ERT_FIXUP: - ggc_mark_tree (region->u.fixup.cleanup_exp); - break; - default: - abort (); - } - - ggc_mark_rtx (region->label); - ggc_mark_rtx (region->resume); - ggc_mark_rtx (region->landing_pad); - ggc_mark_rtx (region->post_landing_pad); -} - -static int -mark_ehl_map_entry (pentry, data) - PTR *pentry; - PTR data ATTRIBUTE_UNUSED; -{ - struct ehl_map_entry *entry = *(struct ehl_map_entry **) pentry; - ggc_mark_rtx (entry->label); - return 1; -} - -static void -mark_ehl_map (pp) - void *pp; -{ - htab_t map = *(htab_t *) pp; - if (map) - htab_traverse (map, mark_ehl_map_entry, NULL); -} - -void -mark_eh_status (eh) - struct eh_status *eh; -{ - int i; - - if (eh == 0) - return; - - /* If we've called collect_eh_region_array, use it. Otherwise walk - the tree non-recursively. */ - if (eh->region_array) - { - for (i = eh->last_region_number; i > 0; --i) - { - struct eh_region *r = eh->region_array[i]; - if (r && r->region_number == i) - mark_eh_region (r); - } - } - else if (eh->region_tree) - { - struct eh_region *r = eh->region_tree; - while (1) - { - mark_eh_region (r); - if (r->inner) - r = r->inner; - else if (r->next_peer) - r = r->next_peer; - else - { - do { - r = r->outer; - if (r == NULL) - goto tree_done; - } while (r->next_peer == NULL); - r = r->next_peer; - } - } - tree_done:; - } - - ggc_mark_tree (eh->protect_list); - ggc_mark_rtx (eh->filter); - ggc_mark_rtx (eh->exc_ptr); - ggc_mark_tree_varray (eh->ttype_data); - - if (eh->call_site_data) - { - for (i = eh->call_site_data_used - 1; i >= 0; --i) - ggc_mark_rtx (eh->call_site_data[i].landing_pad); - } - - ggc_mark_rtx (eh->ehr_stackadj); - ggc_mark_rtx (eh->ehr_handler); - ggc_mark_rtx (eh->ehr_label); - - ggc_mark_rtx (eh->sjlj_fc); - ggc_mark_rtx (eh->sjlj_exit_after); -} - -static inline void -free_region (r) - struct eh_region *r; -{ - /* Note that the aka bitmap is freed by regset_release_memory. But if - we ever replace with a non-obstack implementation, this would be - the place to do it. */ - free (r); -} - -void -free_eh_status (f) - struct function *f; -{ - struct eh_status *eh = f->eh; - - if (eh->region_array) - { - int i; - for (i = eh->last_region_number; i > 0; --i) - { - struct eh_region *r = eh->region_array[i]; - /* Mind we don't free a region struct more than once. */ - if (r && r->region_number == i) - free_region (r); - } - free (eh->region_array); - } - else if (eh->region_tree) - { - struct eh_region *next, *r = eh->region_tree; - while (1) - { - if (r->inner) - r = r->inner; - else if (r->next_peer) - { - next = r->next_peer; - free_region (r); - r = next; - } - else - { - do { - next = r->outer; - free_region (r); - r = next; - if (r == NULL) - goto tree_done; - } while (r->next_peer == NULL); - next = r->next_peer; - free_region (r); - r = next; - } - } - tree_done:; - } - - VARRAY_FREE (eh->ttype_data); - VARRAY_FREE (eh->ehspec_data); - VARRAY_FREE (eh->action_record_data); - if (eh->call_site_data) - free (eh->call_site_data); - - free (eh); - f->eh = NULL; - - if (exception_handler_label_map) - { - htab_delete (exception_handler_label_map); - exception_handler_label_map = NULL; - } -} - /* Start an exception handling region. All instructions emitted after this point are considered to be part of the region until @@ -708,7 +491,7 @@ expand_eh_region_start () return; /* Insert a new blank region as a leaf in the tree. */ - new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region)); + new_region = (struct eh_region *) ggc_alloc_cleared (sizeof (*new_region)); cur_region = cfun->eh->cur_region; new_region->outer = cur_region; if (cur_region) @@ -766,39 +549,43 @@ expand_eh_region_end_cleanup (handler) region->type = ERT_CLEANUP; region->label = gen_label_rtx (); region->u.cleanup.exp = handler; + region->u.cleanup.prev_try = cfun->eh->try_region; around_label = gen_label_rtx (); emit_jump (around_label); emit_label (region->label); - /* Give the language a chance to specify an action to be taken if an - exception is thrown that would propagate out of the HANDLER. */ - protect_cleanup_actions - = (lang_protect_cleanup_actions - ? (*lang_protect_cleanup_actions) () - : NULL_TREE); + if (flag_non_call_exceptions || region->may_contain_throw) + { + /* Give the language a chance to specify an action to be taken if an + exception is thrown that would propagate out of the HANDLER. */ + protect_cleanup_actions + = (lang_protect_cleanup_actions + ? (*lang_protect_cleanup_actions) () + : NULL_TREE); - if (protect_cleanup_actions) - expand_eh_region_start (); + if (protect_cleanup_actions) + expand_eh_region_start (); - /* In case this cleanup involves an inline destructor with a try block in - it, we need to save the EH return data registers around it. */ - data_save[0] = gen_reg_rtx (Pmode); - emit_move_insn (data_save[0], get_exception_pointer (cfun)); - data_save[1] = gen_reg_rtx (word_mode); - emit_move_insn (data_save[1], get_exception_filter (cfun)); + /* In case this cleanup involves an inline destructor with a try block in + it, we need to save the EH return data registers around it. */ + data_save[0] = gen_reg_rtx (ptr_mode); + emit_move_insn (data_save[0], get_exception_pointer (cfun)); + data_save[1] = gen_reg_rtx (word_mode); + emit_move_insn (data_save[1], get_exception_filter (cfun)); - expand_expr (handler, const0_rtx, VOIDmode, 0); + expand_expr (handler, const0_rtx, VOIDmode, 0); - emit_move_insn (cfun->eh->exc_ptr, data_save[0]); - emit_move_insn (cfun->eh->filter, data_save[1]); + emit_move_insn (cfun->eh->exc_ptr, data_save[0]); + emit_move_insn (cfun->eh->filter, data_save[1]); - if (protect_cleanup_actions) - expand_eh_region_end_must_not_throw (protect_cleanup_actions); + if (protect_cleanup_actions) + expand_eh_region_end_must_not_throw (protect_cleanup_actions); - /* We need any stack adjustment complete before the around_label. */ - do_pending_stack_adjust (); + /* We need any stack adjustment complete before the around_label. */ + do_pending_stack_adjust (); + } /* We delay the generation of the _Unwind_Resume until we generate landing pads. We emit a marker here so as to get good control @@ -856,11 +643,11 @@ expand_start_catch (type_or_list) tree type_node; if (TREE_CODE (type_or_list) != TREE_LIST) - type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); + type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); type_node = type_list; for (; type_node; type_node = TREE_CHAIN (type_node)) - add_type_for_runtime (TREE_VALUE (type_node)); + add_type_for_runtime (TREE_VALUE (type_node)); } expand_eh_region_start (); @@ -1034,6 +821,22 @@ expand_eh_region_end_fixup (handler) fixup->u.fixup.cleanup_exp = handler; } +/* Note that the current EH region (if any) may contain a throw, or a + call to a function which itself may contain a throw. */ + +void +note_eh_region_may_contain_throw () +{ + struct eh_region *region; + + region = cfun->eh->cur_region; + while (region && !region->may_contain_throw) + { + region->may_contain_throw = 1; + region = region->outer; + } +} + /* Return an rtl expression for a pointer to the exception object within a handler. */ @@ -1044,7 +847,7 @@ get_exception_pointer (fun) rtx exc_ptr = fun->eh->exc_ptr; if (fun == cfun && ! exc_ptr) { - exc_ptr = gen_reg_rtx (Pmode); + exc_ptr = gen_reg_rtx (ptr_mode); fun->eh->exc_ptr = exc_ptr; } return exc_ptr; @@ -1066,55 +869,6 @@ get_exception_filter (fun) return filter; } -/* Begin a region that will contain entries created with - add_partial_entry. */ - -void -begin_protect_partials () -{ - /* Push room for a new list. */ - cfun->eh->protect_list - = tree_cons (NULL_TREE, NULL_TREE, cfun->eh->protect_list); -} - -/* Start a new exception region for a region of code that has a - cleanup action and push the HANDLER for the region onto - protect_list. All of the regions created with add_partial_entry - will be ended when end_protect_partials is invoked. - - ??? The only difference between this purpose and that of - expand_decl_cleanup is that in this case, we only want the cleanup to - run if an exception is thrown. This should also be handled using - binding levels. */ - -void -add_partial_entry (handler) - tree handler; -{ - expand_eh_region_start (); - - /* Add this entry to the front of the list. */ - TREE_VALUE (cfun->eh->protect_list) - = tree_cons (NULL_TREE, handler, TREE_VALUE (cfun->eh->protect_list)); -} - -/* End all the pending exception regions on protect_list. */ - -void -end_protect_partials () -{ - tree t; - - /* Pop the topmost entry. */ - t = TREE_VALUE (cfun->eh->protect_list); - cfun->eh->protect_list = TREE_CHAIN (cfun->eh->protect_list); - - /* End all the exception regions. */ - for (; t; t = TREE_CHAIN (t)) - expand_eh_region_end_cleanup (TREE_VALUE (t)); -} - - /* This section is for the exception handling specific optimization pass. */ /* Random access the exception region tree. It's just as simple to @@ -1130,7 +884,8 @@ collect_eh_region_array () if (! i) return; - array = xcalloc (cfun->eh->last_region_number + 1, sizeof (*array)); + array = ggc_alloc_cleared ((cfun->eh->last_region_number + 1) + * sizeof (*array)); cfun->eh->region_array = array; while (1) @@ -1219,7 +974,7 @@ remove_fixup_regions () /* Allow GC to maybe free some memory. */ if (fixup->type == ERT_CLEANUP) - fixup->u.cleanup.exp = NULL_TREE; + fixup->u.cleanup.exp = NULL_TREE; if (fixup->type != ERT_FIXUP) continue; @@ -1275,23 +1030,23 @@ remove_unreachable_regions (insns) continue; if (r->resume) - { + { if (uid_region_num[INSN_UID (r->resume)]) abort (); uid_region_num[INSN_UID (r->resume)] = i; - } + } if (r->label) - { + { if (uid_region_num[INSN_UID (r->label)]) abort (); uid_region_num[INSN_UID (r->label)] = i; - } + } if (r->type == ERT_TRY && r->u.try.continue_label) - { + { if (uid_region_num[INSN_UID (r->u.try.continue_label)]) abort (); uid_region_num[INSN_UID (r->u.try.continue_label)] = i; - } + } } for (insn = insns; insn; insn = NEXT_INSN (insn)) @@ -1431,12 +1186,12 @@ add_ehl_entry (label, region) LABEL_PRESERVE_P (label) = 1; - entry = (struct ehl_map_entry *) xmalloc (sizeof (*entry)); + entry = (struct ehl_map_entry *) ggc_alloc (sizeof (*entry)); entry->label = label; entry->region = region; slot = (struct ehl_map_entry **) - htab_find_slot (exception_handler_label_map, entry, INSERT); + htab_find_slot (cfun->eh->exception_handler_label_map, entry, INSERT); /* Before landing pad creation, each exception handler has its own label. After landing pad creation, the exception handlers may @@ -1448,29 +1203,20 @@ add_ehl_entry (label, region) *slot = entry; } -static void -ehl_free (pentry) - PTR pentry; -{ - struct ehl_map_entry *entry = (struct ehl_map_entry *)pentry; - LABEL_PRESERVE_P (entry->label) = 0; - free (entry); -} - void find_exception_handler_labels () { int i; - if (exception_handler_label_map) - htab_empty (exception_handler_label_map); + if (cfun->eh->exception_handler_label_map) + htab_empty (cfun->eh->exception_handler_label_map); else { /* ??? The expansion factor here (3/2) must be greater than the htab occupancy factor (4/3) to avoid unnecessary resizing. */ - exception_handler_label_map - = htab_create (cfun->eh->last_region_number * 3 / 2, - ehl_hash, ehl_eq, ehl_free); + cfun->eh->exception_handler_label_map + = htab_create_ggc (cfun->eh->last_region_number * 3 / 2, + ehl_hash, ehl_eq, NULL); } if (cfun->eh->region_tree == NULL) @@ -1522,7 +1268,7 @@ duplicate_eh_region_1 (o, map) struct inline_remap *map; { struct eh_region *n - = (struct eh_region *) xcalloc (1, sizeof (struct eh_region)); + = (struct eh_region *) ggc_alloc_cleared (sizeof (struct eh_region)); n->region_number = o->region_number + cfun->eh->last_region_number; n->type = o->type; @@ -1583,9 +1329,9 @@ duplicate_eh_region_2 (o, n_array) case ERT_CATCH: if (o->u.catch.next_catch) - n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number]; + n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number]; if (o->u.catch.prev_catch) - n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number]; + n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number]; break; default: @@ -1687,23 +1433,6 @@ t2r_hash (pentry) return TYPE_HASH (TREE_PURPOSE (entry)); } -static int -t2r_mark_1 (slot, data) - PTR *slot; - PTR data ATTRIBUTE_UNUSED; -{ - tree contents = (tree) *slot; - ggc_mark_tree (contents); - return 1; -} - -static void -t2r_mark (addr) - PTR addr; -{ - htab_traverse (*(htab_t *)addr, t2r_mark_1, NULL); -} - static void add_type_for_runtime (type) tree type; @@ -1735,7 +1464,7 @@ lookup_type_for_runtime (type) /* Represent an entry in @TTypes for either catch actions or exception filter actions. */ -struct ttypes_filter +struct ttypes_filter GTY(()) { tree t; int filter; @@ -1968,7 +1697,6 @@ build_post_landing_pads () struct eh_region *c; for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) { - /* ??? _Unwind_ForcedUnwind wants no match here. */ if (c->u.catch.type_list == NULL) emit_jump (c->label); else @@ -2003,7 +1731,7 @@ build_post_landing_pads () seq = get_insns (); end_sequence (); - emit_insns_before (seq, region->u.try.catch->label); + emit_insn_before (seq, region->u.try.catch->label); break; case ERT_ALLOWED_EXCEPTIONS: @@ -2027,7 +1755,7 @@ build_post_landing_pads () seq = get_insns (); end_sequence (); - emit_insns_before (seq, region->label); + emit_insn_before (seq, region->label); break; case ERT_CLEANUP: @@ -2080,11 +1808,11 @@ connect_post_landing_pads () emit_jump (outer->post_landing_pad); else emit_library_call (unwind_resume_libfunc, LCT_THROW, - VOIDmode, 1, cfun->eh->exc_ptr, Pmode); + VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode); seq = get_insns (); end_sequence (); - emit_insns_before (seq, region->resume); + emit_insn_before (seq, region->resume); delete_insn (region->resume); } } @@ -2153,14 +1881,14 @@ dw2_build_landing_pads () } emit_move_insn (cfun->eh->exc_ptr, - gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0))); + gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0))); emit_move_insn (cfun->eh->filter, gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1))); seq = get_insns (); end_sequence (); - emit_insns_before (seq, region->post_landing_pad); + emit_insn_before (seq, region->post_landing_pad); } } @@ -2335,7 +2063,7 @@ sjlj_mark_call_sites (lp_info) /* Don't separate a call from it's argument loads. */ before = insn; if (GET_CODE (insn) == CALL_INSN) - before = find_first_parameter_load (insn, NULL_RTX); + before = find_first_parameter_load (insn, NULL_RTX); start_sequence (); mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node), @@ -2344,7 +2072,7 @@ sjlj_mark_call_sites (lp_info) p = get_insns (); end_sequence (); - emit_insns_before (p, before); + emit_insn_before (p, before); last_call_site = this_call_site; } } @@ -2372,7 +2100,7 @@ sjlj_emit_function_enter (dispatch_label) if (cfun->uses_eh_lsda) { char buf[20]; - ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", sjlj_funcdef_number); + ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no); emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf))); } else @@ -2411,7 +2139,7 @@ sjlj_emit_function_enter (dispatch_label) if (GET_CODE (fn_begin) == NOTE && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG) break; - emit_insns_after (seq, fn_begin); + emit_insn_after (seq, fn_begin); } /* Call back from expand_function_end to know where we should put @@ -2441,7 +2169,7 @@ sjlj_emit_function_exit () post-dominates all can_throw_internal instructions. This is the last possible moment. */ - emit_insns_after (seq, cfun->eh->sjlj_exit_after); + emit_insn_after (seq, cfun->eh->sjlj_exit_after); } static void @@ -2505,8 +2233,8 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info) seq = get_insns (); end_sequence (); - emit_insns_before (seq, (cfun->eh->region_array[first_reachable] - ->post_landing_pad)); + emit_insn_before (seq, (cfun->eh->region_array[first_reachable] + ->post_landing_pad)); } static void @@ -2553,9 +2281,7 @@ finish_eh_generation () connect many of the handlers, and then type information will not be effective. Still, this is a win over previous implementations. */ - rebuild_jump_labels (get_insns ()); - find_basic_blocks (get_insns (), max_reg_num (), 0); - cleanup_cfg (CLEANUP_PRE_LOOP); + cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL); /* These registers are used by the landing pads. Make sure they have been generated. */ @@ -2578,7 +2304,7 @@ finish_eh_generation () find_exception_handler_labels (); rebuild_jump_labels (get_insns ()); find_basic_blocks (get_insns (), max_reg_num (), 0); - cleanup_cfg (CLEANUP_PRE_LOOP); + cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL); } static hashval_t @@ -2615,16 +2341,16 @@ remove_exception_handler_label (label) /* If exception_handler_label_map was not built yet, there is nothing to do. */ - if (exception_handler_label_map == NULL) + if (cfun->eh->exception_handler_label_map == NULL) return; tmp.label = label; slot = (struct ehl_map_entry **) - htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT); + htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT); if (! slot) abort (); - htab_clear_slot (exception_handler_label_map, (void **) slot); + htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot); } /* Splice REGION from the region tree etc. */ @@ -2654,7 +2380,7 @@ remove_eh_handler (region) if (outer) { if (!outer->aka) - outer->aka = BITMAP_XMALLOC (); + outer->aka = BITMAP_GGC_ALLOC (); if (region->aka) bitmap_a_or_b (outer->aka, outer->aka, region->aka); bitmap_set_bit (outer->aka, region->region_number); @@ -2713,8 +2439,6 @@ remove_eh_handler (region) remove_eh_handler (try); } } - - free_region (region); } /* LABEL heads a basic block that is about to be deleted. If this @@ -2737,7 +2461,7 @@ maybe_remove_eh_handler (label) tmp.label = label; slot = (struct ehl_map_entry **) - htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT); + htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT); if (! slot) return; region = (*slot)->region; @@ -2750,7 +2474,7 @@ maybe_remove_eh_handler (label) are no more contained calls, which we don't see here. */ if (region->type == ERT_MUST_NOT_THROW) { - htab_clear_slot (exception_handler_label_map, (void **) slot); + htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot); region->label = NULL_RTX; } else @@ -2764,7 +2488,7 @@ void for_each_eh_label (callback) void (*callback) PARAMS ((rtx)); { - htab_traverse (exception_handler_label_map, for_each_eh_label_1, + htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1, (void *)callback); } @@ -2783,7 +2507,7 @@ for_each_eh_label_1 (pentry, data) /* This section describes CFG exception edges for flow. */ /* For communicating between calls to reachable_next_level. */ -struct reachable_info +struct reachable_info GTY(()) { tree types_caught; tree types_allowed; @@ -2870,8 +2594,6 @@ reachable_next_level (region, type_thrown, info) for (c = region->u.try.catch; c ; c = c->u.catch.next_catch) { /* A catch-all handler ends the search. */ - /* ??? _Unwind_ForcedUnwind will want outer cleanups - to be run as well. */ if (c->u.catch.type_list == NULL) { add_reachable_handler (info, region, c); @@ -2995,7 +2717,7 @@ reachable_next_level (region, type_thrown, info) if (info && info->handlers) { add_reachable_handler (info, region, region); - return RNL_CAUGHT; + return RNL_CAUGHT; } else return RNL_BLOCKED; @@ -3053,10 +2775,20 @@ reachable_handlers (insn) region = region->outer; } - for (; region; region = region->outer) - if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) - break; - + while (region) + { + if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) + break; + /* If we have processed one cleanup, there is no point in + processing any more of them. Each cleanup will have an edge + to the next outer cleanup region, so the flow graph will be + accurate. */ + if (region->type == ERT_CLEANUP) + region = region->u.cleanup.prev_try; + else + region = region->outer; + } + return info.handlers; } @@ -3115,7 +2847,7 @@ can_throw_internal (insn) if (how == RNL_BLOCKED) return false; if (how != RNL_NOT_CAUGHT) - return true; + return true; } return false; @@ -3186,25 +2918,50 @@ can_throw_external (insn) return true; } -/* True if nothing in this function can throw outside this function. */ +/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls. */ -bool -nothrow_function_p () +void +set_nothrow_function_flags () { rtx insn; + + current_function_nothrow = 1; - if (! flag_exceptions) - return true; + /* Assume cfun->all_throwers_are_sibcalls until we encounter + something that can throw an exception. We specifically exempt + CALL_INSNs that are SIBLING_CALL_P, as these are really jumps, + and can't throw. Most CALL_INSNs are not SIBLING_CALL_P, so this + is optimistic. */ + cfun->all_throwers_are_sibcalls = 1; + + if (! flag_exceptions) + return; + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (can_throw_external (insn)) - return false; + { + current_function_nothrow = 0; + + if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn)) + { + cfun->all_throwers_are_sibcalls = 0; + return; + } + } + for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1)) if (can_throw_external (insn)) - return false; + { + current_function_nothrow = 0; - return true; + if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn)) + { + cfun->all_throwers_are_sibcalls = 0; + return; + } + } } @@ -3261,6 +3018,16 @@ expand_builtin_extract_return_addr (addr_tree) { rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0); + if (GET_MODE (addr) != Pmode + && GET_MODE (addr) != VOIDmode) + { +#ifdef POINTERS_EXTEND_UNSIGNED + addr = convert_memory_address (Pmode, addr); +#else + addr = convert_to_mode (Pmode, addr, 0); +#endif + } + /* First mask out any unwanted bits. */ #ifdef MASK_RETURN_ADDR expand_and (Pmode, addr, MASK_RETURN_ADDR, addr); @@ -3302,77 +3069,73 @@ expand_builtin_frob_return_addr (addr_tree) void expand_builtin_eh_return (stackadj_tree, handler_tree) - tree stackadj_tree, handler_tree; + tree stackadj_tree ATTRIBUTE_UNUSED; + tree handler_tree; { - rtx stackadj, handler; - - stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0); - handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0); + rtx tmp; +#ifdef EH_RETURN_STACKADJ_RTX + tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0); #ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (stackadj) != Pmode) - stackadj = convert_memory_address (Pmode, stackadj); - - if (GET_MODE (handler) != Pmode) - handler = convert_memory_address (Pmode, handler); + if (GET_MODE (tmp) != Pmode) + tmp = convert_memory_address (Pmode, tmp); +#endif + if (!cfun->eh->ehr_stackadj) + cfun->eh->ehr_stackadj = copy_to_reg (tmp); + else if (tmp != cfun->eh->ehr_stackadj) + emit_move_insn (cfun->eh->ehr_stackadj, tmp); #endif - if (! cfun->eh->ehr_label) - { - cfun->eh->ehr_stackadj = copy_to_reg (stackadj); - cfun->eh->ehr_handler = copy_to_reg (handler); - cfun->eh->ehr_label = gen_label_rtx (); - } - else - { - if (stackadj != cfun->eh->ehr_stackadj) - emit_move_insn (cfun->eh->ehr_stackadj, stackadj); - if (handler != cfun->eh->ehr_handler) - emit_move_insn (cfun->eh->ehr_handler, handler); - } + tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0); +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (tmp) != Pmode) + tmp = convert_memory_address (Pmode, tmp); +#endif + if (!cfun->eh->ehr_handler) + cfun->eh->ehr_handler = copy_to_reg (tmp); + else if (tmp != cfun->eh->ehr_handler) + emit_move_insn (cfun->eh->ehr_handler, tmp); + if (!cfun->eh->ehr_label) + cfun->eh->ehr_label = gen_label_rtx (); emit_jump (cfun->eh->ehr_label); } void expand_eh_return () { - rtx sa, ra, around_label; + rtx around_label; if (! cfun->eh->ehr_label) return; - sa = EH_RETURN_STACKADJ_RTX; - if (! sa) - { - error ("__builtin_eh_return not supported on this target"); - return; - } - current_function_calls_eh_return = 1; +#ifdef EH_RETURN_STACKADJ_RTX + emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx); +#endif + around_label = gen_label_rtx (); - emit_move_insn (sa, const0_rtx); emit_jump (around_label); emit_label (cfun->eh->ehr_label); clobber_return_register (); +#ifdef EH_RETURN_STACKADJ_RTX + emit_move_insn (EH_RETURN_STACKADJ_RTX, cfun->eh->ehr_stackadj); +#endif + #ifdef HAVE_eh_return if (HAVE_eh_return) - emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler)); + emit_insn (gen_eh_return (cfun->eh->ehr_handler)); else #endif { - ra = EH_RETURN_HANDLER_RTX; - if (! ra) - { - error ("__builtin_eh_return not supported on this target"); - ra = gen_reg_rtx (Pmode); - } - - emit_move_insn (sa, cfun->eh->ehr_stackadj); - emit_move_insn (ra, cfun->eh->ehr_handler); +#ifdef EH_RETURN_HANDLER_RTX + emit_move_insn (EH_RETURN_HANDLER_RTX, cfun->eh->ehr_handler); +#else + error ("__builtin_eh_return not supported on this target"); +#endif } emit_label (around_label); @@ -3563,7 +3326,7 @@ add_call_site (landing_pad, action) { size = (size ? size * 2 : 64); data = (struct call_site_record *) - xrealloc (data, sizeof (*data) * size); + ggc_realloc (data, sizeof (*data) * size); cfun->eh->call_site_data = data; cfun->eh->call_site_data_size = size; } @@ -3847,6 +3610,33 @@ sjlj_output_call_site_table () call_site_base += n; } +/* Tell assembler to switch to the section for the exception handling + table. */ + +void +default_exception_section () +{ + if (targetm.have_named_sections) + { + int flags; +#ifdef HAVE_LD_RO_RW_SECTION_MIXING + int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); + + flags = (! flag_pic + || ((tt_format & 0x70) != DW_EH_PE_absptr + && (tt_format & 0x70) != DW_EH_PE_aligned)) + ? 0 : SECTION_WRITE; +#else + flags = SECTION_WRITE; +#endif + named_section_flags (".gcc_except_table", flags); + } + else if (flag_pic) + data_section (); + else + readonly_data_section (); +} + void output_function_exception_table () { @@ -3859,17 +3649,12 @@ output_function_exception_table () int call_site_len; #endif int have_tt_data; - int funcdef_number; int tt_format_size = 0; /* Not all functions need anything. */ if (! cfun->uses_eh_lsda) return; - funcdef_number = (USING_SJLJ_EXCEPTIONS - ? sjlj_funcdef_number - : current_funcdef_number); - #ifdef IA64_UNWIND_INFO fputs ("\t.personality\t", asm_out_file); output_addr_const (asm_out_file, eh_personality_libfunc); @@ -3890,14 +3675,16 @@ output_function_exception_table () { tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1); #ifdef HAVE_AS_LEB128 - ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number); + ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", + current_function_funcdef_no); #endif tt_format_size = size_of_encoded_value (tt_format); assemble_align (tt_format_size * BITS_PER_UNIT); } - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", + current_function_funcdef_no); /* The LSDA header. */ @@ -3929,7 +3716,7 @@ output_function_exception_table () #ifdef HAVE_AS_LEB128 char ttype_after_disp_label[32]; ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD", - funcdef_number); + current_function_funcdef_no); dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label, "@TType base offset"); ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label); @@ -3975,9 +3762,9 @@ output_function_exception_table () #ifdef HAVE_AS_LEB128 ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB", - funcdef_number); + current_function_funcdef_no); ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE", - funcdef_number); + current_function_funcdef_no); dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label, "Call-site table length"); ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label); @@ -4019,7 +3806,7 @@ output_function_exception_table () assemble_integer (value, tt_format_size, tt_format_size * BITS_PER_UNIT, 1); else - dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL); + dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL); } #ifdef HAVE_AS_LEB128 @@ -4034,7 +3821,6 @@ output_function_exception_table () (i ? NULL : "Exception specification table")); function_section (current_function_decl); - - if (USING_SJLJ_EXCEPTIONS) - sjlj_funcdef_number += 1; } + +#include "gt-except.h" |