X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexcept.c;h=5c666d4da55877e3a738c29ad07b791e48b1c329;hb=786c6b83c3028ecb4637cb1c7f9687491958e28f;hp=952021bbdcc6ba270b85ecad86cf64e2039e2d8f;hpb=da5038a3ba3d077ca2bfe548b31a4822ed2f0e8d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/except.c b/gcc/except.c index 952021bbdcc..5c666d4da55 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -1,5 +1,6 @@ /* Implements exception handling. - Copyright (C) 1989, 1992-1999 Free Software Foundation, Inc. + Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000 Free Software Foundation, Inc. Contributed by Mike Stump . This file is part of GNU CC. @@ -408,6 +409,8 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "intl.h" #include "obstack.h" +#include "ggc.h" +#include "tm_p.h" /* One to use setjmp/longjmp method of generating code for exception handling. */ @@ -451,24 +454,39 @@ static rtx last_rethrow_symbol = NULL_RTX; /* Prototypes for local functions. */ -static void push_eh_entry PROTO((struct eh_stack *)); -static struct eh_entry * pop_eh_entry PROTO((struct eh_stack *)); -static void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *)); -static struct eh_entry * dequeue_eh_entry PROTO((struct eh_queue *)); -static rtx call_get_eh_context PROTO((void)); -static void start_dynamic_cleanup PROTO((tree, tree)); -static void start_dynamic_handler PROTO((void)); -static void expand_rethrow PROTO((rtx)); -static void output_exception_table_entry PROTO((FILE *, int)); -static int can_throw PROTO((rtx)); -static rtx scan_region PROTO((rtx, int, int *)); -static void eh_regs PROTO((rtx *, rtx *, rtx *, int)); -static void set_insn_eh_region PROTO((rtx *, int)); +static void push_eh_entry PARAMS ((struct eh_stack *)); +static struct eh_entry * pop_eh_entry PARAMS ((struct eh_stack *)); +static void enqueue_eh_entry PARAMS ((struct eh_queue *, struct eh_entry *)); +static struct eh_entry * dequeue_eh_entry PARAMS ((struct eh_queue *)); +static rtx call_get_eh_context PARAMS ((void)); +static void start_dynamic_cleanup PARAMS ((tree, tree)); +static void start_dynamic_handler PARAMS ((void)); +static void expand_rethrow PARAMS ((rtx)); +static void output_exception_table_entry PARAMS ((FILE *, int)); +static rtx scan_region PARAMS ((rtx, int, int *)); +static void eh_regs PARAMS ((rtx *, rtx *, rtx *, int)); +static void set_insn_eh_region PARAMS ((rtx *, int)); #ifdef DONT_USE_BUILTIN_SETJMP -static void jumpif_rtx PROTO((rtx, rtx)); +static void jumpif_rtx PARAMS ((rtx, rtx)); #endif +static void find_exception_handler_labels_1 PARAMS ((rtx)); +static void mark_eh_node PARAMS ((struct eh_node *)); +static void mark_eh_stack PARAMS ((struct eh_stack *)); +static void mark_eh_queue PARAMS ((struct eh_queue *)); +static void mark_tree_label_node PARAMS ((struct label_node *)); +static void mark_func_eh_entry PARAMS ((void *)); +static rtx create_rethrow_ref PARAMS ((int)); +static void push_entry PARAMS ((struct eh_stack *, struct eh_entry*)); +static void receive_exception_label PARAMS ((rtx)); +static int new_eh_region_entry PARAMS ((int, rtx)); +static int find_func_region PARAMS ((int)); +static int find_func_region_from_symbol PARAMS ((rtx)); +static void clear_function_eh_region PARAMS ((void)); +static void process_nestinfo PARAMS ((int, eh_nesting_info *, int *)); +rtx expand_builtin_return_addr PARAMS ((enum built_in_function, int, rtx)); +static void emit_cleanup_handler PARAMS ((struct eh_entry *)); +static int eh_region_from_symbol PARAMS ((rtx)); -rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); /* Various support routines to manipulate the various data structures used by the exception handling code. */ @@ -476,23 +494,20 @@ rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); extern struct obstack permanent_obstack; /* Generate a SYMBOL_REF for rethrow to use */ + static rtx create_rethrow_ref (region_num) int region_num; { rtx def; - char *ptr; + const char *ptr; char buf[60]; - push_obstacks_nochange (); - end_temporary_allocation (); - ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num); - ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf)); + ptr = ggc_strdup (buf); def = gen_rtx_SYMBOL_REF (Pmode, ptr); SYMBOL_REF_NEED_ADJUST (def) = 1; - pop_obstacks (); return def; } @@ -547,7 +562,7 @@ top_label_entry (stack) return (*stack)->u.tlabel; } -/* get an exception label. These must be on the permanent obstack */ +/* Get an exception label. */ rtx gen_exception_label () @@ -576,13 +591,15 @@ push_eh_entry (stack) else entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab)); entry->rethrow_label = entry->outer_context; + entry->goto_entry_p = 0; node->entry = entry; node->chain = stack->top; stack->top = node; } -/* push an existing entry onto a stack. */ +/* Push an existing entry onto a stack. */ + static void push_entry (stack, entry) struct eh_stack *stack; @@ -624,13 +641,9 @@ enqueue_eh_entry (queue, entry) node->chain = NULL; if (queue->head == NULL) - { - queue->head = node; - } + queue->head = node; else - { - queue->tail->chain = node; - } + queue->tail->chain = node; queue->tail = node; } @@ -659,19 +672,40 @@ static void receive_exception_label (handler_label) rtx handler_label; { + rtx around_label = NULL_RTX; + + if (! flag_new_exceptions || exceptions_via_longjmp) + { + around_label = gen_label_rtx (); + emit_jump (around_label); + emit_barrier (); + } + emit_label (handler_label); -#ifdef HAVE_exception_receiver if (! exceptions_via_longjmp) - if (HAVE_exception_receiver) - emit_insn (gen_exception_receiver ()); + { +#ifdef HAVE_exception_receiver + if (HAVE_exception_receiver) + emit_insn (gen_exception_receiver ()); + else #endif - #ifdef HAVE_nonlocal_goto_receiver - if (! exceptions_via_longjmp) - if (HAVE_nonlocal_goto_receiver) - emit_insn (gen_nonlocal_goto_receiver ()); + if (HAVE_nonlocal_goto_receiver) + emit_insn (gen_nonlocal_goto_receiver ()); + else +#endif + { /* Nothing */ } + } + else + { +#ifndef DONT_USE_BUILTIN_SETJMP + expand_builtin_setjmp_receiver (handler_label); #endif + } + + if (around_label) + emit_label (around_label); } @@ -679,7 +713,8 @@ struct func_eh_entry { int range_number; /* EH region number from EH NOTE insn's. */ rtx rethrow_label; /* Label for rethrow. */ - int rethrow_ref; /* Is rethrow referenced? */ + int rethrow_ref; /* Is rethrow_label referenced? */ + int emitted; /* 1 if this entry has been emitted in assembly file. */ struct handler_info *handlers; }; @@ -691,10 +726,8 @@ static int current_func_eh_entry = 0; #define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X) -/* Add a new eh_entry for this function, and base it off of the information - in the EH_ENTRY parameter. A NULL parameter is invalid. - OUTER_CONTEXT is a label which is used for rethrowing. The number - returned is an number which uniquely identifies this exception range. */ +/* Add a new eh_entry for this function. The number returned is an + number which uniquely identifies this exception range. */ static int new_eh_region_entry (note_eh_region, rethrow) @@ -706,14 +739,14 @@ new_eh_region_entry (note_eh_region, rethrow) if (num_func_eh_entries == 0) { function_eh_regions = - (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50)); + (struct func_eh_entry *) xmalloc (SIZE_FUNC_EH (50)); num_func_eh_entries = 50; } else { num_func_eh_entries = num_func_eh_entries * 3 / 2; function_eh_regions = (struct func_eh_entry *) - realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries)); + xrealloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries)); } } function_eh_regions[current_func_eh_entry].range_number = note_eh_region; @@ -723,7 +756,8 @@ new_eh_region_entry (note_eh_region, rethrow) else function_eh_regions[current_func_eh_entry].rethrow_label = rethrow; function_eh_regions[current_func_eh_entry].handlers = NULL; - + function_eh_regions[current_func_eh_entry].emitted = 0; + return current_func_eh_entry++; } @@ -741,6 +775,12 @@ add_new_handler (region, newhandler) { struct handler_info *last; + /* If find_func_region returns -1, callers might attempt to pass us + this region number. If that happens, something has gone wrong; + -1 is never a valid region. */ + if (region == -1) + abort (); + newhandler->next = NULL; last = function_eh_regions[region].handlers; if (last == NULL) @@ -807,10 +847,7 @@ find_all_handler_type_matches (array) return 0; max_ptr = 100; - ptr = (void **)malloc (max_ptr * sizeof (void *)); - - if (ptr == NULL) - return 0; + ptr = (void **) xmalloc (max_ptr * sizeof (void *)); for (x = 0 ; x < current_func_eh_entry; x++) { @@ -834,15 +871,19 @@ find_all_handler_type_matches (array) if (n_ptr >= max_ptr) { max_ptr += max_ptr / 2; - ptr = (void **)realloc (ptr, max_ptr * sizeof (void *)); - if (ptr == NULL) - return 0; + ptr = (void **) xrealloc (ptr, max_ptr * sizeof (void *)); } ptr[n_ptr] = val; n_ptr++; } } } + + if (n_ptr == 0) + { + free (ptr); + ptr = NULL; + } *array = ptr; return n_ptr; } @@ -856,7 +897,7 @@ get_new_handler (handler, typeinfo) void *typeinfo; { struct handler_info* ptr; - ptr = (struct handler_info *) malloc (sizeof (struct handler_info)); + ptr = (struct handler_info *) xmalloc (sizeof (struct handler_info)); ptr->handler_label = handler; ptr->handler_number = CODE_LABEL_NUMBER (handler); ptr->type_info = typeinfo; @@ -868,9 +909,9 @@ get_new_handler (handler, typeinfo) /* Find the index in function_eh_regions associated with a NOTE region. If - the region cannot be found, a -1 is returned. This should never happen! */ + the region cannot be found, a -1 is returned. */ -int +static int find_func_region (insn_region) int insn_region; { @@ -888,7 +929,10 @@ struct handler_info * get_first_handler (region) int region; { - return function_eh_regions[find_func_region (region)].handlers; + int r = find_func_region (region); + if (r == -1) + abort (); + return function_eh_regions[r].handlers; } /* Clean out the function_eh_region table and free all memory */ @@ -904,7 +948,8 @@ clear_function_eh_region () next = ptr->next; free (ptr); } - free (function_eh_regions); + if (function_eh_regions) + free (function_eh_regions); num_func_eh_entries = 0; current_func_eh_entry = 0; } @@ -945,7 +990,8 @@ duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map) /* Given a rethrow symbol, find the EH region number this is for. */ -int + +static int eh_region_from_symbol (sym) rtx sym; { @@ -958,17 +1004,31 @@ eh_region_from_symbol (sym) return -1; } +/* Like find_func_region, but using the rethrow symbol for the region + rather than the region number itself. */ + +static int +find_func_region_from_symbol (sym) + rtx sym; +{ + return find_func_region (eh_region_from_symbol (sym)); +} /* When inlining/unrolling, we have to map the symbols passed to __rethrow as well. This performs the remap. If a symbol isn't foiund, the original one is returned. This is not an efficient routine, so don't call it on everything!! */ + rtx rethrow_symbol_map (sym, map) rtx sym; rtx (*map) PARAMS ((rtx)); { int x, y; + + if (! flag_new_exceptions) + return sym; + for (x = 0; x < current_func_eh_entry; x++) if (function_eh_regions[x].rethrow_label == sym) { @@ -989,6 +1049,10 @@ rethrow_symbol_map (sym, map) return sym; } +/* Returns nonzero if the rethrow label for REGION is referenced + somewhere (i.e. we rethrow out of REGION or some other region + masquerading as REGION). */ + int rethrow_used (region) int region; @@ -1057,16 +1121,19 @@ add_partial_entry (handler) { expand_eh_region_start (); - /* Make sure the entry is on the correct obstack. */ - push_obstacks_nochange (); - resume_temporary_allocation (); - /* Because this is a cleanup action, we may have to protect the handler with __terminate. */ handler = protect_with_terminate (handler); - protect_list = tree_cons (NULL_TREE, handler, protect_list); - pop_obstacks (); + /* For backwards compatibility, we allow callers to omit calls to + begin_protect_partials for the outermost region. So, we must + explicitly do so here. */ + if (!protect_list) + begin_protect_partials (); + + /* Add this entry to the front of the list. */ + TREE_VALUE (protect_list) + = tree_cons (NULL_TREE, handler, TREE_VALUE (protect_list)); } /* Emit code to get EH context to current function. */ @@ -1081,8 +1148,6 @@ call_get_eh_context () { tree fntype; fn = get_identifier ("__get_eh_context"); - push_obstacks_nochange (); - end_temporary_allocation (); fntype = build_pointer_type (build_pointer_type (build_pointer_type (void_type_node))); fntype = build_function_type (fntype, NULL_TREE); @@ -1091,9 +1156,10 @@ call_get_eh_context () TREE_PUBLIC (fn) = 1; DECL_ARTIFICIAL (fn) = 1; TREE_READONLY (fn) = 1; - make_decl_rtl (fn, NULL_PTR, 1); + make_decl_rtl (fn, NULL_PTR); assemble_external (fn); - pop_obstacks (); + + ggc_add_tree_root (&fn, 1); } expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); @@ -1259,14 +1325,19 @@ static void start_dynamic_handler () { rtx dhc, dcc; - rtx x, arg, buf; + rtx arg, buf; int size; #ifndef DONT_USE_BUILTIN_SETJMP /* The number of Pmode words for the setjmp buffer, when using the - builtin setjmp/longjmp, see expand_builtin, case - BUILT_IN_LONGJMP. */ - size = 5; + builtin setjmp/longjmp, see expand_builtin, case BUILT_IN_LONGJMP. */ + /* We use 2 words here before calling expand_builtin_setjmp. + expand_builtin_setjmp uses 2 words, and then calls emit_stack_save. + emit_stack_save needs space of size STACK_SAVEAREA_MODE (SAVE_NONLOCAL). + Subtract one, because the assign_stack_local call below adds 1. */ + size = (2 + 2 + (GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL)) + / GET_MODE_SIZE (Pmode)) + - 1); #else #ifdef JMP_BUF_SIZE size = JMP_BUF_SIZE; @@ -1301,18 +1372,17 @@ start_dynamic_handler () buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2); #ifdef DONT_USE_BUILTIN_SETJMP - x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1, - buf, Pmode); - /* If we come back here for a catch, transfer control to the handler. */ - jumpif_rtx (x, ehstack.top->entry->exception_handler_label); -#else { - /* A label to continue execution for the no exception case. */ - rtx noex = gen_label_rtx(); - x = expand_builtin_setjmp (buf, NULL_RTX, noex, - ehstack.top->entry->exception_handler_label); - emit_label (noex); + rtx x; + x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST, + TYPE_MODE (integer_type_node), 1, + buf, Pmode); + /* If we come back here for a catch, transfer control to the handler. */ + jumpif_rtx (x, ehstack.top->entry->exception_handler_label); } +#else + expand_builtin_setjmp_setup (buf, + ehstack.top->entry->exception_handler_label); #endif /* We are committed to this, so update the handler chain. */ @@ -1366,8 +1436,7 @@ expand_eh_region_start_tree (decl, cleanup) /* is the second argument 2? */ && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST - && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2 - && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0 + && compare_tree_int (TREE_VALUE (args), 2) == 0 /* Make sure there are no other arguments. */ && TREE_CHAIN (args) == NULL_TREE) @@ -1404,7 +1473,7 @@ expand_eh_region_start_for_decl (decl) /* We need a new block to record the start and end of the dynamic handler chain. We also want to prevent jumping into a try block. */ - expand_start_bindings (0); + expand_start_bindings (2); /* But we don't need or want a new temporary level. */ pop_temp_slots (); @@ -1423,7 +1492,7 @@ expand_eh_region_start_for_decl (decl) push_eh_entry (&ehstack); note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG); - NOTE_BLOCK_NUMBER (note) + NOTE_EH_HANDLER (note) = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label); if (exceptions_via_longjmp) start_dynamic_handler (); @@ -1453,6 +1522,7 @@ expand_eh_region_end (handler) tree handler; { struct eh_entry *entry; + struct eh_node *node; rtx note; int ret, r; @@ -1462,7 +1532,7 @@ expand_eh_region_end (handler) entry = pop_eh_entry (&ehstack); note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END); - ret = NOTE_BLOCK_NUMBER (note) + ret = NOTE_EH_HANDLER (note) = CODE_LABEL_NUMBER (entry->exception_handler_label); if (exceptions_via_longjmp == 0 && ! flag_new_exceptions /* We share outer_context between regions; only emit it once. */ @@ -1484,9 +1554,9 @@ expand_eh_region_end (handler) entry->finalization = handler; /* create region entry in final exception table */ - r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label); + r = new_eh_region_entry (NOTE_EH_HANDLER (note), entry->rethrow_label); - enqueue_eh_entry (&ehqueue, entry); + enqueue_eh_entry (ehqueue, entry); /* If we have already started ending the bindings, don't recurse. */ if (is_eh_region ()) @@ -1501,6 +1571,21 @@ expand_eh_region_end (handler) expand_end_bindings (NULL_TREE, 0, 0); } + + /* Go through the goto handlers in the queue, emitting their + handlers if we now have enough information to do so. */ + for (node = ehqueue->head; node; node = node->chain) + if (node->entry->goto_entry_p + && node->entry->outer_context == entry->rethrow_label) + emit_cleanup_handler (node->entry); + + /* We can't emit handlers for goto entries until their scopes are + complete because we don't know where they need to rethrow to, + yet. */ + if (entry->finalization != integer_zero_node + && (!entry->goto_entry_p + || find_func_region_from_symbol (entry->outer_context) != -1)) + emit_cleanup_handler (entry); } /* End the EH region for a goto fixup. We only need them in the region-based @@ -1513,6 +1598,8 @@ expand_fixup_region_start () return; expand_eh_region_start (); + /* Mark this entry as the entry for a goto. */ + ehstack.top->entry->goto_entry_p = 1; } /* End the EH region for a goto fixup. CLEANUP is the cleanup we just @@ -1532,7 +1619,7 @@ expand_fixup_region_end (cleanup) for (node = ehstack.top; node && node->entry->finalization != cleanup; ) node = node->chain; if (node == 0) - for (node = ehqueue.head; node && node->entry->finalization != cleanup; ) + for (node = ehqueue->head; node && node->entry->finalization != cleanup; ) node = node->chain; if (node == 0) abort (); @@ -1544,8 +1631,11 @@ expand_fixup_region_end (cleanup) and we could get an infinte loop when it tried to rethrow, or just generally incorrect execution following a throw. */ - dont_issue = ((INSN_UID (node->entry->outer_context) == 0) - && (ehstack.top->entry != node->entry)); + if (flag_new_exceptions) + dont_issue = 0; + else + dont_issue = ((INSN_UID (node->entry->outer_context) == 0) + && (ehstack.top->entry != node->entry)); ehstack.top->entry->outer_context = node->entry->outer_context; @@ -1565,16 +1655,7 @@ expand_fixup_region_end (cleanup) } /* If we are using the setjmp/longjmp EH codegen method, we emit a - call to __sjthrow. - - Otherwise, we emit a call to __throw and note that we threw - something, so we know we need to generate the necessary code for - __throw. - - Before invoking throw, the __eh_pc variable must have been set up - to contain the PC being thrown from. This address is used by - __throw to determine which exception region (if any) is - responsible for handling the exception. */ + call to __sjthrow. Otherwise, we emit a call to __throw. */ void emit_throw () @@ -1611,33 +1692,14 @@ expand_leftover_cleanups () { struct eh_entry *entry; - while ((entry = dequeue_eh_entry (&ehqueue)) != 0) + for (entry = dequeue_eh_entry (ehqueue); + entry; + entry = dequeue_eh_entry (ehqueue)) { - rtx prev; - - /* A leftover try block. Shouldn't be one here. */ + /* A leftover try block. Shouldn't be one here. */ if (entry->finalization == integer_zero_node) abort (); - /* Output the label for the start of the exception handler. */ - - receive_exception_label (entry->exception_handler_label); - - /* register a handler for this cleanup region */ - add_new_handler ( - find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), - get_new_handler (entry->exception_handler_label, NULL)); - - /* And now generate the insns for the handler. */ - expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); - - prev = get_last_insn (); - if (prev == NULL || GET_CODE (prev) != BARRIER) - /* Emit code to throw to the outer context if we fall off - the end of the handler. */ - expand_rethrow (entry->outer_context); - - do_pending_stack_adjust (); free (entry); } } @@ -1692,7 +1754,10 @@ start_catch_handler (rtime) rtx call_rtx, rtime_address; if (catchstack.top->entry->false_label != NULL_RTX) - fatal ("Compiler Bug: Never issued previous false_label"); + { + error ("Never issued previous false_label"); + abort (); + } catchstack.top->entry->false_label = gen_exception_label (); rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER); @@ -1703,7 +1768,9 @@ start_catch_handler (rtime) /* Now issue the call, and branch around handler if needed */ call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, - 0, SImode, 1, rtime_address, Pmode); + LCT_NORMAL, + TYPE_MODE (integer_type_node), + 1, rtime_address, Pmode); /* Did the function return true? */ emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX, @@ -1736,6 +1803,86 @@ end_catch_handler () catchstack.top->entry->false_label = NULL_RTX; } +/* Save away the current ehqueue. */ + +void +push_ehqueue () +{ + struct eh_queue *q; + q = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue)); + q->next = ehqueue; + ehqueue = q; +} + +/* Restore a previously pushed ehqueue. */ + +void +pop_ehqueue () +{ + struct eh_queue *q; + expand_leftover_cleanups (); + q = ehqueue->next; + free (ehqueue); + ehqueue = q; +} + +/* Emit the handler specified by ENTRY. */ + +static void +emit_cleanup_handler (entry) + struct eh_entry *entry; +{ + rtx prev; + rtx handler_insns; + + /* Since the cleanup could itself contain try-catch blocks, we + squirrel away the current queue and replace it when we are done + with this function. */ + push_ehqueue (); + + /* Put these handler instructions in a sequence. */ + do_pending_stack_adjust (); + start_sequence (); + + /* Emit the label for the cleanup handler for this region, and + expand the code for the handler. + + Note that a catch region is handled as a side-effect here; for a + try block, entry->finalization will contain integer_zero_node, so + no code will be generated in the expand_expr call below. But, the + label for the handler will still be emitted, so any code emitted + after this point will end up being the handler. */ + + receive_exception_label (entry->exception_handler_label); + + /* register a handler for this cleanup region */ + add_new_handler (find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), + get_new_handler (entry->exception_handler_label, NULL)); + + /* And now generate the insns for the cleanup handler. */ + expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); + + prev = get_last_insn (); + if (prev == NULL || GET_CODE (prev) != BARRIER) + /* Code to throw out to outer context when we fall off end of the + handler. We can't do this here for catch blocks, so it's done + in expand_end_all_catch instead. */ + expand_rethrow (entry->outer_context); + + /* Finish this sequence. */ + do_pending_stack_adjust (); + handler_insns = get_insns (); + end_sequence (); + + /* And add it to the CATCH_CLAUSES. */ + push_to_full_sequence (catch_clauses, catch_clauses_last); + emit_insns (handler_insns); + end_full_sequence (&catch_clauses, &catch_clauses_last); + + /* Now we've left the handler. */ + pop_ehqueue (); +} + /* Generate RTL for the start of a group of catch clauses. It is responsible for starting a new instruction sequence for the @@ -1774,48 +1921,18 @@ expand_start_all_catch () the handlers in this handler-seq. */ start_sequence (); - entry = dequeue_eh_entry (&ehqueue); - for ( ; entry->finalization != integer_zero_node; - entry = dequeue_eh_entry (&ehqueue)) - { - rtx prev; - - /* Emit the label for the cleanup handler for this region, and - expand the code for the handler. - - Note that a catch region is handled as a side-effect here; - for a try block, entry->finalization will contain - integer_zero_node, so no code will be generated in the - expand_expr call below. But, the label for the handler will - still be emitted, so any code emitted after this point will - end up being the handler. */ - - receive_exception_label (entry->exception_handler_label); - - /* register a handler for this cleanup region */ - add_new_handler ( - find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), - get_new_handler (entry->exception_handler_label, NULL)); - - /* And now generate the insns for the cleanup handler. */ - expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); - - prev = get_last_insn (); - if (prev == NULL || GET_CODE (prev) != BARRIER) - /* Code to throw out to outer context when we fall off end - of the handler. We can't do this here for catch blocks, - so it's done in expand_end_all_catch instead. */ - expand_rethrow (entry->outer_context); - - do_pending_stack_adjust (); - free (entry); - } + /* Throw away entries in the queue that we won't need anymore. We + need entries for regions that have ended but to which there might + still be gotos pending. */ + for (entry = dequeue_eh_entry (ehqueue); + entry->finalization != integer_zero_node; + entry = dequeue_eh_entry (ehqueue)) + free (entry); /* At this point, all the cleanups are done, and the ehqueue now has the current exception region at its head. We dequeue it, and put it on the catch stack. */ - - push_entry (&catchstack, entry); + push_entry (&catchstack, entry); /* If we are not doing setjmp/longjmp EH, because we are reordered out of line, we arrange to rethrow in the outer context. We need to @@ -1882,10 +1999,9 @@ expand_end_all_catch () pop_label_entry (&outer_context_label_stack); /* Add the new sequence of catches to the main one for this function. */ - push_to_sequence (catch_clauses); + push_to_full_sequence (catch_clauses, catch_clauses_last); emit_insns (new_catch_clause); - catch_clauses = get_insns (); - end_sequence (); + end_full_sequence (&catch_clauses, &catch_clauses_last); /* Here we fall through into the continuation code. */ } @@ -1901,12 +2017,16 @@ expand_rethrow (label) else if (flag_new_exceptions) { - rtx insn, val; + rtx insn; int region; if (label == NULL_RTX) label = last_rethrow_symbol; emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode); region = find_func_region (eh_region_from_symbol (label)); + /* If the region is -1, it doesn't exist yet. We shouldn't be + trying to rethrow there yet. */ + if (region == -1) + abort (); function_eh_regions[region].rethrow_ref = 1; /* Search backwards for the actual call insn. */ @@ -1924,17 +2044,37 @@ expand_rethrow (label) emit_jump (label); } +/* Begin a region that will contain entries created with + add_partial_entry. */ + +void +begin_protect_partials () +{ + /* Push room for a new list. */ + protect_list = tree_cons (NULL_TREE, NULL_TREE, protect_list); +} + /* End all the pending exception regions on protect_list. The handlers will be emitted when expand_leftover_cleanups is invoked. */ void end_protect_partials () { - while (protect_list) - { - expand_eh_region_end (TREE_VALUE (protect_list)); - protect_list = TREE_CHAIN (protect_list); - } + tree t; + + /* For backwards compatibility, we allow callers to omit the call to + begin_protect_partials for the outermost region. So, + PROTECT_LIST may be NULL. */ + if (!protect_list) + return; + + /* End all the exception regions. */ + for (t = TREE_VALUE (protect_list); t; t = TREE_CHAIN (t)) + expand_eh_region_end (TREE_VALUE (t)); + + /* Pop the topmost entry. */ + protect_list = TREE_CHAIN (protect_list); + } /* Arrange for __terminate to be called if there is an unhandled throw @@ -1951,10 +2091,6 @@ protect_with_terminate (e) { tree handler, result; - /* All cleanups must be on the function_obstack. */ - push_obstacks_nochange (); - resume_temporary_allocation (); - handler = make_node (RTL_EXPR); TREE_TYPE (handler) = void_type_node; RTL_EXPR_RTL (handler) = const0_rtx; @@ -1972,8 +2108,6 @@ protect_with_terminate (e) TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e); TREE_READONLY (result) = TREE_READONLY (e); - pop_obstacks (); - e = result; } @@ -1998,7 +2132,7 @@ static int eh_table_max_size = 0; Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen. (Or NOTE_INSN_EH_REGION_END sometimes) - N is the NOTE_BLOCK_NUMBER of the note, which comes from the code + N is the NOTE_EH_HANDLER of the note, which comes from the code label number of the exception handler for the region. */ void @@ -2025,6 +2159,24 @@ add_eh_table_entry (n) } } eh_table[eh_table_size++] = n; + + if (flag_new_exceptions) + { + /* We will output the exception table late in the compilation. That + references type_info objects which should have already been output + by that time. We explicitly mark those objects as being + referenced now so we know to emit them. */ + struct handler_info *handler = get_first_handler (n); + + for (; handler; handler = handler->next) + if (handler->type_info && handler->type_info != CATCH_ALL_TYPE) + { + tree tinfo = (tree)handler->type_info; + + tinfo = TREE_OPERAND (tinfo, 0); + TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1; + } + } #endif } @@ -2059,14 +2211,16 @@ output_exception_table_entry (file, 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 (! function_eh_regions[index].rethrow_ref) - rethrow = NULL_RTX; + /* Form and emit the rethrow label, if needed */ + if (flag_new_exceptions + && (handler || function_eh_regions[index].rethrow_ref)) + rethrow = function_eh_regions[index].rethrow_label; + else + rethrow = NULL_RTX; + if (function_eh_regions[index].emitted) + return; + function_eh_regions[index].emitted = 1; for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next) { @@ -2074,34 +2228,34 @@ output_exception_table_entry (file, n) if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL)) { ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n); - assemble_label(buf); + assemble_eh_label(buf); rethrow = NULL_RTX; } ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n); sym = gen_rtx_SYMBOL_REF (Pmode, buf); - assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n); sym = gen_rtx_SYMBOL_REF (Pmode, buf); - assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); if (handler == NULL) - assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1); else { ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number); sym = gen_rtx_SYMBOL_REF (Pmode, buf); - assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); } if (flag_new_exceptions) { if (handler == NULL || handler->type_info == NULL) - assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); else if (handler->type_info == CATCH_ALL_TYPE) - assemble_integer (GEN_INT (CATCH_ALL_TYPE), + assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE), POINTER_SIZE / BITS_PER_UNIT, 1); else output_constant ((tree)(handler->type_info), @@ -2135,61 +2289,101 @@ set_exception_version_code (code) version_code = code; } - +/* Free the EH table structures. */ void -output_exception_table () +free_exception_table () +{ + if (eh_table) + free (eh_table); + clear_function_eh_region (); +} + +/* Output the common content of an exception table. */ +void +output_exception_table_data () { int i; char buf[256]; extern FILE *asm_out_file; - if (! doing_eh (0) || ! eh_table) - return; - - exception_section (); - - /* Beginning marker for table. */ - assemble_align (GET_MODE_ALIGNMENT (ptr_mode)); - assemble_label ("__EXCEPTION_TABLE__"); - if (flag_new_exceptions) { - assemble_integer (GEN_INT (NEW_EH_RUNTIME), + assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME), POINTER_SIZE / BITS_PER_UNIT, 1); - assemble_integer (GEN_INT (language_code), 2 , 1); - assemble_integer (GEN_INT (version_code), 2 , 1); + assemble_eh_integer (GEN_INT (language_code), 2 , 1); + assemble_eh_integer (GEN_INT (version_code), 2 , 1); /* Add enough padding to make sure table aligns on a pointer boundry. */ i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4; for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT) ; if (i != 0) - assemble_integer (const0_rtx, i , 1); + assemble_eh_integer (const0_rtx, i , 1); - /* Generate the label for offset calculations on rethrows */ + /* Generate the label for offset calculations on rethrows. */ ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0); - assemble_label(buf); + assemble_eh_label(buf); } for (i = 0; i < eh_table_size; ++i) output_exception_table_entry (asm_out_file, eh_table[i]); - free (eh_table); - clear_function_eh_region (); +} + +/* Output an exception table for the entire compilation unit. */ +void +output_exception_table () +{ + char buf[256]; + extern FILE *asm_out_file; + + if (! doing_eh (0) || ! eh_table) + return; + + exception_section (); + + /* Beginning marker for table. */ + assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode)); + assemble_eh_label ("__EXCEPTION_TABLE__"); + + output_exception_table_data (); /* Ending marker for table. */ /* Generate the label for end of table. */ ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow)); - assemble_label(buf); - assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_label(buf); + assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); - /* for binary compatability, the old __throw checked the second + /* For binary compatibility, the old __throw checked the second position for a -1, so we should output at least 2 -1's */ if (! flag_new_exceptions) - assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); + assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); putc ('\n', asm_out_file); /* blank line */ } + +/* Used by the ia64 unwind format to output data for an individual + function. */ +void +output_function_exception_table () +{ + extern FILE *asm_out_file; + + if (! doing_eh (0) || ! eh_table) + return; + +#ifdef HANDLER_SECTION + HANDLER_SECTION; +#endif + + output_exception_table_data (); + + /* Ending marker for table. */ + assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); + + putc ('\n', asm_out_file); /* blank line */ +} + /* Emit code to get EH context. @@ -2231,45 +2425,28 @@ emit_eh_context () end_sequence (); emit_insns_before (insns, insn); - - /* At -O0, we must make the context register stay alive so - that the stupid.c register allocator doesn't get confused. */ - if (obey_regdecls != 0) - { - insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0)); - emit_insn_before (insns, get_last_insn ()); - } } } } -/* Scan the current insns and build a list of handler labels. The - resulting list is placed in the global variable exception_handler_labels. - - It is called after the last exception handling region is added to - the current function (when the rtl is almost all built for the - current function) and before the jump optimization pass. */ +/* Scan the insn chain F and build a list of handler labels. The + resulting list is placed in the global variable exception_handler_labels. */ -void -find_exception_handler_labels () +static void +find_exception_handler_labels_1 (f) + rtx f; { rtx insn; - exception_handler_labels = NULL_RTX; - - /* If we aren't doing exception handling, there isn't much to check. */ - if (! doing_eh (0)) - return; - /* For each start of a region, add its label to the list. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + for (insn = f; insn; insn = NEXT_INSN (insn)) { struct handler_info* ptr; if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn)); + ptr = get_first_handler (NOTE_EH_HANDLER (insn)); for ( ; ptr; ptr = ptr->next) { /* make sure label isn't in the list already */ @@ -2282,9 +2459,34 @@ find_exception_handler_labels () ptr->handler_label, exception_handler_labels); } } + else if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) + { + find_exception_handler_labels_1 (XEXP (PATTERN (insn), 0)); + find_exception_handler_labels_1 (XEXP (PATTERN (insn), 1)); + find_exception_handler_labels_1 (XEXP (PATTERN (insn), 2)); + } } } +/* Scan the current insns and build a list of handler labels. The + resulting list is placed in the global variable exception_handler_labels. + + It is called after the last exception handling region is added to + the current function (when the rtl is almost all built for the + current function) and before the jump optimization pass. */ +void +find_exception_handler_labels () +{ + exception_handler_labels = NULL_RTX; + + /* If we aren't doing exception handling, there isn't much to check. */ + if (! doing_eh (0)) + return; + + find_exception_handler_labels_1 (get_insns ()); +} + /* Return a value of 1 if the parameter label number is an exception handler label. Return 0 otherwise. */ @@ -2327,7 +2529,114 @@ check_exception_handler_labels () } } - + +/* Mark the children of NODE for GC. */ + +static void +mark_eh_node (node) + struct eh_node *node; +{ + while (node) + { + if (node->entry) + { + ggc_mark_rtx (node->entry->outer_context); + ggc_mark_rtx (node->entry->exception_handler_label); + ggc_mark_tree (node->entry->finalization); + ggc_mark_rtx (node->entry->false_label); + ggc_mark_rtx (node->entry->rethrow_label); + } + node = node ->chain; + } +} + +/* Mark S for GC. */ + +static void +mark_eh_stack (s) + struct eh_stack *s; +{ + if (s) + mark_eh_node (s->top); +} + +/* Mark Q for GC. */ + +static void +mark_eh_queue (q) + struct eh_queue *q; +{ + while (q) + { + mark_eh_node (q->head); + q = q->next; + } +} + +/* Mark NODE for GC. A label_node contains a union containing either + a tree or an rtx. This label_node will contain a tree. */ + +static void +mark_tree_label_node (node) + struct label_node *node; +{ + while (node) + { + ggc_mark_tree (node->u.tlabel); + node = node->chain; + } +} + +/* Mark EH for GC. */ + +void +mark_eh_status (eh) + struct eh_status *eh; +{ + if (eh == 0) + return; + + mark_eh_stack (&eh->x_ehstack); + mark_eh_stack (&eh->x_catchstack); + mark_eh_queue (eh->x_ehqueue); + ggc_mark_rtx (eh->x_catch_clauses); + + if (lang_mark_false_label_stack) + (*lang_mark_false_label_stack) (eh->x_false_label_stack); + mark_tree_label_node (eh->x_caught_return_label_stack); + + ggc_mark_tree (eh->x_protect_list); + ggc_mark_rtx (eh->ehc); + ggc_mark_rtx (eh->x_eh_return_stub_label); +} + +/* Mark ARG (which is really a struct func_eh_entry**) for GC. */ + +static void +mark_func_eh_entry (arg) + void *arg; +{ + struct func_eh_entry *fee; + struct handler_info *h; + int i; + + fee = *((struct func_eh_entry **) arg); + + for (i = 0; i < current_func_eh_entry; ++i) + { + ggc_mark_rtx (fee->rethrow_label); + for (h = fee->handlers; h; h = h->next) + { + ggc_mark_rtx (h->handler_label); + if (h->type_info != CATCH_ALL_TYPE) + ggc_mark_tree ((tree) h->type_info); + } + + /* Skip to the next entry in the array. */ + ++fee; + } +} + /* This group of functions initializes the exception handling data structures at the start of the compilation, initializes the data structures at the start of a function, and saves and restores the @@ -2342,45 +2651,58 @@ 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)); -} + ggc_add_rtx_root (&exception_handler_labels, 1); + ggc_add_rtx_root (&eh_return_context, 1); + ggc_add_rtx_root (&eh_return_stack_adjust, 1); + ggc_add_rtx_root (&eh_return_handler, 1); + ggc_add_rtx_root (&first_rethrow_symbol, 1); + ggc_add_rtx_root (&final_rethrow, 1); + ggc_add_rtx_root (&last_rethrow_symbol, 1); + ggc_add_root (&function_eh_regions, 1, sizeof (function_eh_regions), + mark_func_eh_entry); +} + /* Initialize the per-function EH information. */ void init_eh_for_function () { - current_function->eh = (struct eh_status *) xmalloc (sizeof (struct eh_status)); - - ehstack.top = 0; - catchstack.top = 0; - ehqueue.head = ehqueue.tail = 0; - catch_clauses = NULL_RTX; - false_label_stack = 0; - caught_return_label_stack = 0; - protect_list = NULL_TREE; - current_function_ehc = NULL_RTX; + cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status)); + ehqueue = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue)); eh_return_context = NULL_RTX; eh_return_stack_adjust = NULL_RTX; eh_return_handler = NULL_RTX; - eh_return_stub_label = NULL_RTX; +} + +void +free_eh_status (f) + struct function *f; +{ + free (f->eh->x_ehqueue); + free (f->eh); + f->eh = NULL; } /* This section is for the exception handling specific optimization - pass. First are the internal routines, and then the main - optimization pass. */ + pass. */ /* Determine if the given INSN can throw an exception. */ -static int +int can_throw (insn) rtx insn; { + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, 0); + /* Calls can always potentially throw exceptions, unless they have a REG_EH_REGION note with a value of 0 or less. */ if (GET_CODE (insn) == CALL_INSN) { rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - if (!note || XINT (XEXP (note, 0), 0) > 0) + if (!note || INTVAL (XEXP (note, 0)) > 0) return 1; } @@ -2395,6 +2717,27 @@ can_throw (insn) return 0; } +/* Return nonzero if nothing in this function can throw. */ + +int +nothrow_function_p () +{ + rtx insn; + + if (! flag_exceptions) + return 1; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (can_throw (insn)) + return 0; + for (insn = current_function_epilogue_delay_list; insn; + insn = XEXP (insn, 1)) + if (can_throw (insn)) + return 0; + + return 1; +} + /* Scan a exception region looking for the matching end and then remove it if possible. INSN is the start of the region, N is the region number, and DELETE_OUTER is to note if anything in this @@ -2423,14 +2766,14 @@ scan_region (insn, n, delete_outer) /* Assume we can delete the region. */ int delete = 1; - /* Can't delete something which is rethrown to. */ + /* Can't delete something which is rethrown from. */ if (rethrow_used (n)) delete = 0; if (insn == NULL_RTX || GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG - || NOTE_BLOCK_NUMBER (insn) != n + || NOTE_EH_HANDLER (insn) != n || delete_outer == NULL) abort (); @@ -2450,14 +2793,14 @@ scan_region (insn, n, delete_outer) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete); + insn = scan_region (insn, NOTE_EH_HANDLER (insn), &delete); } insn = NEXT_INSN (insn); } /* The _BEG/_END NOTEs must match and nest. */ - if (NOTE_BLOCK_NUMBER (insn) != n) + if (NOTE_EH_HANDLER (insn) != n) abort (); /* If anything in this exception region can throw, we can throw. */ @@ -2535,14 +2878,15 @@ exception_optimize () inbetween. We are also guaranteed that the value of insn returned will be valid, as otherwise scan_region won't return. */ - insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n); + insn = scan_region (insn, NOTE_EH_HANDLER (insn), &n); } } } -/* This function determines whether any of the exception regions in the - current function are targets of a rethrow or not, and set the - reference flag according. */ +/* This function determines whether the rethrow labels for any of the + exception regions in the current function are used or not, and set + the reference flag according. */ + void update_rethrow_references () { @@ -2553,13 +2897,11 @@ update_rethrow_references () if (!flag_new_exceptions) return; - saw_region = (int *) alloca (current_func_eh_entry * sizeof (int)); - saw_rethrow = (int *) alloca (current_func_eh_entry * sizeof (int)); - bzero ((char *) saw_region, (current_func_eh_entry * sizeof (int))); - bzero ((char *) saw_rethrow, (current_func_eh_entry * sizeof (int))); + saw_region = (int *) xcalloc (current_func_eh_entry, sizeof (int)); + saw_rethrow = (int *) xcalloc (current_func_eh_entry, sizeof (int)); /* Determine what regions exist, and whether there are any rethrows - to those regions or not. */ + from those regions or not. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == CALL_INSN) { @@ -2576,7 +2918,7 @@ update_rethrow_references () { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - region = find_func_region (NOTE_BLOCK_NUMBER (insn)); + region = find_func_region (NOTE_EH_HANDLER (insn)); saw_region[region] = 1; } } @@ -2585,6 +2927,10 @@ update_rethrow_references () for (x = 0; x < current_func_eh_entry; x++) if (saw_region[x]) function_eh_regions[x].rethrow_ref = saw_rethrow[x]; + + /* Clean up. */ + free (saw_region); + free (saw_rethrow); } /* Various hooks for the DWARF 2 __throw routine. */ @@ -2639,9 +2985,10 @@ expand_builtin_frob_return_addr (addr_tree) The first passes the exception context to the handler. For this we use the return value register for a void*. - The second holds the stack pointer value to be restored. For - this we use the static chain register if it exists and is different - from the previous, otherwise some arbitrary call-clobbered register. + The second holds the stack pointer value to be restored. For this + we use the static chain register if it exists, is different from + the previous, and is call-clobbered; otherwise some arbitrary + call-clobbered register. The third holds the address of the handler itself. Here we use some arbitrary call-clobbered register. */ @@ -2649,10 +2996,10 @@ expand_builtin_frob_return_addr (addr_tree) static void eh_regs (pcontext, psp, pra, outgoing) rtx *pcontext, *psp, *pra; - int outgoing; + int outgoing ATTRIBUTE_UNUSED; { rtx rcontext, rsp, rra; - int i; + unsigned int i; #ifdef FUNCTION_OUTGOING_VALUE if (outgoing) @@ -2668,7 +3015,8 @@ eh_regs (pcontext, psp, pra, outgoing) rsp = static_chain_incoming_rtx; else rsp = static_chain_rtx; - if (REGNO (rsp) == REGNO (rcontext)) + if (REGNO (rsp) == REGNO (rcontext) + || ! call_used_regs [REGNO (rsp)]) #endif /* STATIC_CHAIN_REGNUM */ rsp = NULL_RTX; @@ -2700,6 +3048,7 @@ eh_regs (pcontext, psp, pra, outgoing) /* Retrieve the register which contains the pointer to the eh_context structure set the __throw. */ +#if 0 rtx get_reg_for_handler () { @@ -2708,6 +3057,7 @@ get_reg_for_handler () current_function_decl); return reg1; } +#endif /* Set up the epilogue with the magic bits we'll need to return to the exception handler. */ @@ -2816,10 +3166,10 @@ set_insn_eh_region (first, region_num) for (insn = *first; insn; insn = NEXT_INSN (insn)) { - if ((GET_CODE (insn) == NOTE) && - (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)) + if ((GET_CODE (insn) == NOTE) + && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)) { - rnum = NOTE_BLOCK_NUMBER (insn); + rnum = NOTE_EH_HANDLER (insn); insn_eh_region[INSN_UID (insn)] = rnum; insn = NEXT_INSN (insn); set_insn_eh_region (&insn, rnum); @@ -2872,7 +3222,7 @@ init_insn_eh_region (first, max_uid) max_uid = INSN_UID (insn); maximum_uid = max_uid; - insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int)); + insn_eh_region = (int *) xmalloc ((max_uid + 1) * sizeof (int)); insn = first; set_insn_eh_region (&insn, 0); } @@ -2913,6 +3263,7 @@ in_same_eh_region (insn1, insn2) yet. At some point in the future we can trim out handlers which we know cannot be called. (ie, if a block has an INT type handler, control will never be passed to an outer INT type handler). */ + static void process_nestinfo (block, info, nested_eh_region) int block; @@ -2922,7 +3273,7 @@ process_nestinfo (block, info, nested_eh_region) handler_info *ptr, *last_ptr = NULL; int x, y, count = 0; int extra = 0; - handler_info **extra_handlers; + handler_info **extra_handlers = 0; int index = info->region_index[block]; /* If we've already processed this block, simply return. */ @@ -2953,7 +3304,7 @@ process_nestinfo (block, info, nested_eh_region) extra = 0; info->num_handlers[index] = count + extra; - info->handlers[index] = (handler_info **) malloc ((count + extra) + info->handlers[index] = (handler_info **) xmalloc ((count + extra) * sizeof (handler_info **)); /* First put all our handlers into the list. */ @@ -2991,6 +3342,7 @@ process_nestinfo (block, info, nested_eh_region) /* This function will allocate and initialize an eh_nesting_info structure. It returns a pointer to the completed data structure. If there are no exception regions, a NULL value is returned. */ + eh_nesting_info * init_eh_nesting_info () { @@ -3001,12 +3353,12 @@ init_eh_nesting_info () rtx insn; int x; - info = (eh_nesting_info *) malloc (sizeof (eh_nesting_info)); - info->region_index = (int *) malloc ((max_label_num () + 1) * sizeof (int)); - bzero ((char *) info->region_index, (max_label_num () + 1) * sizeof (int)); + if (! flag_exceptions) + return 0; - nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int)); - bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int)); + info = (eh_nesting_info *) xmalloc (sizeof (eh_nesting_info)); + info->region_index = (int *) xcalloc ((max_label_num () + 1), sizeof (int)); + nested_eh_region = (int *) xcalloc (max_label_num () + 1, sizeof (int)); /* Create the nested_eh_region list. If indexed with a block number, it returns the block number of the next outermost region, if any. @@ -3018,12 +3370,12 @@ init_eh_nesting_info () { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - int block = NOTE_BLOCK_NUMBER (insn); + int block = NOTE_EH_HANDLER (insn); region_count++; info->region_index[block] = region_count; if (eh_note) nested_eh_region [block] = - NOTE_BLOCK_NUMBER (XEXP (eh_note, 0)); + NOTE_EH_HANDLER (XEXP (eh_note, 0)); else nested_eh_region [block] = 0; eh_note = gen_rtx_EXPR_LIST (VOIDmode, insn, eh_note); @@ -3038,18 +3390,15 @@ init_eh_nesting_info () { free (info->region_index); free (info); + free (nested_eh_region); return NULL; } region_count++; - info->handlers = (handler_info ***) malloc (region_count - * sizeof (handler_info ***)); - info->num_handlers = (int *) malloc (region_count * sizeof (int)); - info->outer_index = (int *) malloc (region_count * sizeof (int)); - - bzero ((char *) info->handlers, region_count * sizeof (rtx *)); - bzero ((char *) info->num_handlers, region_count * sizeof (int)); - bzero ((char *) info->outer_index, region_count * sizeof (int)); + info->handlers = (handler_info ***) xcalloc (region_count, + sizeof (handler_info ***)); + info->num_handlers = (int *) xcalloc (region_count, sizeof (int)); + info->outer_index = (int *) xcalloc (region_count, sizeof (int)); /* Now initialize the handler lists for all exception blocks. */ for (x = 0; x <= max_label_num (); x++) @@ -3058,6 +3407,10 @@ init_eh_nesting_info () process_nestinfo (x, info, nested_eh_region); } info->region_count = region_count; + + /* Clean up. */ + free (nested_eh_region); + return info; } @@ -3073,6 +3426,7 @@ init_eh_nesting_info () HANDLERS is the address of a pointer to a vector of handler_info pointers. Upon return, this will have the handlers which can be reached by block. This function returns the number of elements in the handlers vector. */ + int reachable_handlers (block, info, insn, handlers) int block; @@ -3091,7 +3445,7 @@ reachable_handlers (block, info, insn, handlers) if (insn && GET_CODE (insn) == CALL_INSN) { /* RETHROWs specify a region number from which we are going to rethrow. - This means we wont pass control to handlers in the specified + This means we won't pass control to handlers in the specified region, but rather any region OUTSIDE the specified region. We accomplish this by setting block to the outer_index of the specified region. */ @@ -3111,7 +3465,7 @@ reachable_handlers (block, info, insn, handlers) note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); if (note) { - int b = XINT (XEXP (note, 0), 0); + int b = INTVAL (XEXP (note, 0)); if (b <= 0) index = 0; else @@ -3150,5 +3504,6 @@ free_eh_nesting_info (info) free (info->handlers[x]); free (info->handlers); } + free (info); } }