From 9a0d1e1b11fc8a7fd41f038d7b243b6d2573ed64 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 14 May 1998 13:39:15 +0000 Subject: First cut of changes to utilize the new exception handling model From-SVN: r19746 --- gcc/ChangeLog | 62 ++++++ gcc/cp/ChangeLog | 16 ++ gcc/cp/except.c | 64 ++++-- gcc/cp/exception.cc | 34 ++++ gcc/cp/parse.y | 6 +- gcc/cp/semantics.c | 10 +- gcc/eh-common.h | 133 +++++++++++++ gcc/except.c | 562 +++++++++++++++++++++++++++++++++++++++------------- gcc/except.h | 82 +++++++- gcc/final.c | 5 + gcc/flow.c | 55 +++-- gcc/function.h | 1 + gcc/integrate.c | 45 ++++- gcc/libgcc2.c | 98 ++++++--- 14 files changed, 960 insertions(+), 213 deletions(-) create mode 100644 gcc/eh-common.h (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c99ab5e..1f14869 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,65 @@ +Thu May 14 16:30:47 EDT 1998 Andrew MacLeod + + * eh-common.h: New file for basic EH data structures. + * except.h: Various prototypes and structures for NEW_EH_MODEL + * function.h (struct function): Add a struct eh_stack for the catch + clause stack. + * except.c (gen_exception_label): New function to generate an + exception label. + (push_eh_entry): Use gen_exception_label() and init 'label_used' field. + (push_entry): New function to push an existing entry onto a stack. + (receive_exception_label): New function to emit the code required + at the start of all catch blocks. + (struct func_eh_entry): New structure for maintaining handlers + associated with EH regions. + (new_eh_region_entry): New function to register an EH region. + (add_new_handler): New function to register a handler with a region. + (get_new_handler): Creates anew handler entry for registering. + (find_func_region): New function to convert a NOTE eh region number + to an Eh region index. + (get_first_handler): New function to get the first handler in a region. + (clear_function_eh_region): New function to release memory. + (duplicate_handlers): New function to duplicate a list of handlers. + (expand_eh_region_end): Create a new region entry node as well. + (expand_leftover_cleanups): Call receive_exception_label() and + register the cleanup as a handler to the current region. + (expand_start_catch): New function to start a catch clause. + (expand_end_catch): New function to end a catch clause. + (expand_start_all_catch): restructure to not do the equivilent of + what expand_start_catch() does now. Push the exception region being + handled onto the catch stack. + (output_exception_table_entry): Issue an entry for each handler + associated with a region. + (set_exception_lang_code): New function for setting the language code. + (set_exception_version_code): New function to set the version number. + (output_exception_table): Output version and language codes. + (find_exception_handler_labels): Find handler labels using new scheme. + (is_exception_handler_label): New function, returns 1 if label is + present as a handler in some exception region. + (check_exception_handler_labels): Use the new scheme. + (init_eh_for_function): Initialize the catch stack. + (save_eh_status): Save the catch stack. + (restore_eh_status): Restore the catch stack. + (scan_region): Don't remove unreferenced handler label. Flow does it. + (get_reg_for_handler): New function to get the eh_context pointer + passed by __throw. + (expand_builtin_eh_stub): Changes required for NEW_EH_MODEL only. + * final.c (final_scan_insn): With NEW_EH_MODEL, add EH table + entry when processing END region rather that START region. + * flow.c (find_basic_blocks_1): Find all potential handler regions + now that we don't automatically know what the labels might be. + Let scan_region() remove unreferenced EH BEGIN/END labels. + * integrate.c (get_label_from_map): Put inlined labels onto the + permanent obstack since we dont know which ones might be exception + labels. + (save_for_inline_copying): Make new copies of all the handlers. + (expand_inline_function): Make new copies of all the handlers. + * libgcc2.c: Remove local struct decls, and include eh-common.h. + (find_exception_handler): With NEW_EH_MODEL the first matching + region we find is the right one. Add eh_info as a new parameter. + (__throw): Pass eh_info to find_exception_handler. Set handler + and pass use different regs under NEW_EH_MODEL. + Thu May 14 12:58:21 1998 Jim Wilson * i960.h (hard_regno_mode_ok): Changed to function from array of diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bdd7a16..ae3695b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +Thu May 14 16:30:47 EDT 1998 Andrew MacLeod + + * exception.cc: Include eh-common.h. + (struct cp_eh_info): add eh_info struct with NEW_EH_MODEL. + (__cplus_type_matcher): First stab at new C++ runtime type matcher. + (__cp_push_exception): Initialize eh_info struct as well. + * except.c: Remove local structs and include eh-common.h. + (init_exception_processing): Set language and version codes. + (call_eh_info): add presence of eh_info to runtime description of + struct cp_eh_info. + (expand_end_eh_spec): call start_catch_block() and end_catch_block(). + * semantics.c (finish_try_block): call start_catch_block() and + end_catch_block(). + * parse.y (function_try_block): call start_catch_block() and + end_catch_block(). + Thu May 14 12:27:34 1998 Brendan Kehoe * typeck.c (original_type): New function. diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 6a98a13..5b68314 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */ #include "function.h" #include "defaults.h" #include "toplev.h" +#include "eh-common.h" rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); @@ -66,14 +67,6 @@ static tree do_pop_exception PROTO((void)); #endif #ifdef EXCEPT_SECTION_ASM_OP -typedef struct { - void *start_region; - void *end_region; - void *exception_handler; - } exception_table; -#endif /* EXCEPT_SECTION_ASM_OP */ - -#ifdef EXCEPT_SECTION_ASM_OP /* on machines which support it, the exception table lives in another section, but it needs a label so we can reference it... This sets up that @@ -227,6 +220,11 @@ init_exception_processing () push_lang_context (lang_name_c); +#ifdef NEW_EH_MODEL + set_exception_lang_code (EH_LANG_C_plus_plus); + set_exception_version_code (1); +#endif + CatchMatch = builtin_function (flag_rtti ? "__throw_type_match_rtti" @@ -269,7 +267,8 @@ call_eh_info () fn = IDENTIFIER_GLOBAL_VALUE (fn); else { - tree t, fields[6]; + tree t1,t, fields[7]; + int fo = 0; /* Declare cp_eh_info * __cp_exception_info (void), as defined in exception.cc. */ @@ -278,25 +277,56 @@ call_eh_info () /* struct cp_eh_info. This must match exception.cc. Note that this type is not pushed anywhere. */ +#ifdef NEW_EH_MODEL + t1= make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, + get_identifier ("handler_label"), ptr_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, + get_identifier ("dynamic_handler_chain"), ptr_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, + get_identifier ("info"), ptr_type_node); + /* N.B.: The fourth field LEN is expected to be + the number of fields - 1, not the total number of fields. */ + finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node); + t1 = build_pointer_type (t1); + + t1= make_lang_type (RECORD_TYPE); + fields[0] = build_lang_field_decl (FIELD_DECL, + get_identifier ("match_function"), ptr_type_node); + fields[1] = build_lang_field_decl (FIELD_DECL, + get_identifier ("coerced_value"), ptr_type_node); + fields[2] = build_lang_field_decl (FIELD_DECL, + get_identifier ("language"), short_integer_type_node); + fields[3] = build_lang_field_decl (FIELD_DECL, + get_identifier ("version"), short_integer_type_node); + /* N.B.: The fourth field LEN is expected to be + the number of fields - 1, not the total number of fields. */ + finish_builtin_type (t1, "__eh_info", fields, 3, ptr_type_node); + fo = 1; +#endif t = make_lang_type (RECORD_TYPE); - fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"), +#ifdef NEW_EH_MODEL + fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("eh_info"), + t1); +#endif + fields[0+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"), ptr_type_node); - fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"), + fields[1+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"), ptr_type_node); - fields[2] = build_lang_field_decl + fields[2+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("cleanup"), build_pointer_type (build_function_type (ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, void_list_node)))); - fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"), + fields[3+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"), boolean_type_node); - fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"), + fields[4+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"), build_pointer_type (t)); - fields[5] = build_lang_field_decl + fields[5+fo] = build_lang_field_decl (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node); /* N.B.: The fourth field LEN is expected to be the number of fields - 1, not the total number of fields. */ - finish_builtin_type (t, "cp_eh_info", fields, 5, ptr_type_node); + finish_builtin_type (t, "cp_eh_info", fields, 5+fo, ptr_type_node); t = build_pointer_type (t); /* And now the function. */ @@ -681,6 +711,7 @@ expand_end_eh_spec (raises) int count = 0; expand_start_all_catch (); + expand_start_catch (NULL); expand_start_catch_block (NULL_TREE, NULL_TREE); /* Build up an array of type_infos. */ @@ -733,6 +764,7 @@ expand_end_eh_spec (raises) expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); expand_end_catch_block (); + expand_end_catch (); expand_end_all_catch (); } diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index d6709c5..461dba4 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -30,6 +30,7 @@ #include "typeinfo" #include "exception" #include +#include "eh-common.h" /* Define terminate, unexpected, set_terminate, set_unexpected as well as the default terminate func and default unexpected func. */ @@ -85,6 +86,9 @@ std::unexpected () struct cp_eh_info { +#ifdef NEW_EH_MODEL + __eh_info eh_info; +#endif void *value; void *type; void (*cleanup)(void *, int); @@ -133,6 +137,29 @@ __eh_free (void *p) free (p); } + +#ifdef NEW_EH_MODEL + +typedef void * (* rtimetype) (void); + +extern "C" void * +__cplus_type_matcher (cp_eh_info *info, exception_table *matching_info, + exception_descriptor *exception_table) +{ + void *ret; + + if (exception_table->lang.language != EH_LANG_C_plus_plus) + return NULL; + + /* we don't worry about version info yet, there is only one version! */ + + void *match_type = ((rtimetype) (matching_info->match_info)) (); + ret = __throw_type_match_rtti (match_type, info->type, info->value); + return ret; +} +#endif + + /* Compiler hook to push a new exception onto the stack. Used by expand_throw(). */ @@ -147,6 +174,13 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) p->handlers = 0; p->caught = false; +#ifdef NEW_EH_MODEL + p->eh_info.match_function = __cplus_type_matcher; + p->eh_info.language = EH_LANG_C_plus_plus; + p->eh_info.version = 1; + p->eh_info.coerced_value = NULL; +#endif + cp_eh_info **q = __get_eh_info (); p->next = *q; diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y index d9df9b8..9bdc979 100644 --- a/gcc/cp/parse.y +++ b/gcc/cp/parse.y @@ -3222,12 +3222,16 @@ function_try_block: expand_start_early_try_stmts (); } ctor_initializer_opt compstmt - { expand_start_all_catch (); } + { + expand_start_all_catch (); + expand_start_catch (NULL); + } handler_seq { int nested = (hack_decl_function_context (current_function_decl) != NULL_TREE); expand_end_all_catch (); + expand_end_catch (); finish_function (lineno, (int)$3, nested); } ; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d58ba1d..2501642 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -587,7 +587,10 @@ finish_try_block (try_block) if (processing_template_decl) RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block)); else - expand_start_all_catch (); + { + expand_start_all_catch (); + expand_start_catch (NULL); + } } /* Finish a handler-sequence for a try-block, which may be given by @@ -600,7 +603,10 @@ finish_handler_sequence (try_block) if (processing_template_decl) RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block)); else - expand_end_all_catch (); + { + expand_end_catch (); + expand_end_all_catch (); + } } /* Begin a handler. Returns a HANDLER if appropriate. */ diff --git a/gcc/eh-common.h b/gcc/eh-common.h new file mode 100644 index 0000000..708946b --- /dev/null +++ b/gcc/eh-common.h @@ -0,0 +1,133 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of GNU CC. */ + +/* This file contains the structures required for the language + independant exception handling model. Both the static compiler and + the runtime library share this file. */ + +/* The compiler flag NEW_EH_MODEL is used to determine whether the + compiler supports the new runtime typechecking mechanism or not. Under + the new model, runtime info is contained in the exception table, and + the __throw() library routine determines which handler to call based + on the results of a call to a matching function provided by the expcetion + thrower. Otherwise the old scheme of calling any handler which matches + an exception range is used, and the handler is responsible for all + checking of runtime conditions. If the handler wasn't suppose to + get the exception, it performs a re-throw. */ + +#include "gansidecl.h" + + +#ifndef NEW_EH_MODEL + +struct eh_context +{ + void **dynamic_handler_chain; + /* This is language dependent part of the eh context. */ + void *info; +}; + +#else + +/* The handler_label field MUST be the first field in this structure. The + __throw() library routine expects uses __eh_stub() from except.c, which + simply dereferences the context pointer to get the handler */ + +struct eh_context +{ + void *handler_label; + void **dynamic_handler_chain; + /* This is language dependent part of the eh context. */ + void *info; +}; + +#endif + + +#ifndef EH_TABLE_LOOKUP + +#ifndef NEW_EH_MODEL + +typedef struct exception_table +{ + void *start_region; + void *end_region; + void *exception_handler; +} exception_table; + +typedef exception_table exception_descriptor; + +#else + +typedef struct exception_table +{ + void *start_region; + void *end_region; + void *exception_handler; + void *match_info; /* runtime type info */ +} exception_table; + + +/* The language identifying portion of an exception table */ + +typedef struct exception_lang_info +{ + short language; + short version; +} exception_lang_info; + +/* Each function has an exception_descriptor which contains the + language info, and a table of exception ranges and handlers */ + +typedef struct exception_descriptor +{ + exception_lang_info lang; + exception_table table[1]; +} exception_descriptor; + + +/* A pointer to a matching function is initialized at runtime by the + specific language if run-time exceptions are supported. + The function takes 3 parameters + 1 - runtime exception that has been thrown info. (__eh_info *) + 2 - Match info pointer from the region being considered (void *) + 3 - exception table region is in (exception descriptor *) +*/ + +typedef void * (*__eh_matcher) PROTO ((void *, void *, void *)); + +/* This is the runtime exception information. This forms the minimum required + information for an exception info pointer in an eh_context structure. */ + +typedef struct __eh_info +{ + __eh_matcher match_function; + void *coerced_value; + short language; + short version; +} __eh_info; + +/* Convienient language codes for ID the originating language. Similar + to the codes in dwarf2.h. */ + +enum exception_source_language + { + EH_LANG_C89 = 0x0001, + EH_LANG_C = 0x0002, + EH_LANG_Ada83 = 0x0003, + EH_LANG_C_plus_plus = 0x0004, + EH_LANG_Cobol74 = 0x0005, + EH_LANG_Cobol85 = 0x0006, + EH_LANG_Fortran77 = 0x0007, + EH_LANG_Fortran90 = 0x0008, + EH_LANG_Pascal83 = 0x0009, + EH_LANG_Modula2 = 0x000a, + EH_LANG_Java = 0x000b, + EH_LANG_Mips_Assembler = 0x8001 + }; + +#endif + +#endif /* EH_TABLE_LOOKUP */ + + diff --git a/gcc/except.c b/gcc/except.c index 4d69240..a2213a8 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -390,6 +390,7 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "defaults.h" +#include "eh-common.h" #include "system.h" #include "rtl.h" #include "tree.h" @@ -442,6 +443,12 @@ rtx current_function_ehc; static struct eh_stack ehstack; + +/* This stack is used to represent what the current eh region is + for the catch blocks beings processed */ + +static struct eh_stack catchstack; + /* A queue used for tracking which exception regions have closed but whose handlers have not yet been expanded. Regions are emitted in groups in an attempt to improve paging performance. @@ -553,6 +560,20 @@ top_label_entry (stack) return (*stack)->u.tlabel; } +/* get an exception label. These must be on the permanent obstack */ + +rtx +gen_exception_label () +{ + rtx lab; + + push_obstacks_nochange (); + end_temporary_allocation (); + lab = gen_label_rtx (); + pop_obstacks (); + return lab; +} + /* Push a new eh_node entry onto STACK. */ static void @@ -563,9 +584,22 @@ push_eh_entry (stack) struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry)); entry->outer_context = gen_label_rtx (); - entry->exception_handler_label = gen_label_rtx (); entry->finalization = NULL_TREE; + entry->label_used = 0; + entry->exception_handler_label = gen_exception_label (); + + node->entry = entry; + node->chain = stack->top; + stack->top = node; +} +/* push an existing entry onto a stack. */ +static void +push_entry (stack, entry) + struct eh_stack *stack; + struct eh_entry *entry; +{ + struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node)); node->entry = entry; node->chain = stack->top; stack->top = node; @@ -631,6 +665,185 @@ dequeue_eh_entry (queue) return tempentry; } + +static void +receive_exception_label (handler_label) + rtx handler_label; +{ + emit_label (handler_label); + +#ifdef HAVE_exception_receiver + if (! exceptions_via_longjmp) + if (HAVE_exception_receiver) + emit_insn (gen_exception_receiver ()); +#endif + +#ifdef HAVE_nonlocal_goto_receiver + if (! exceptions_via_longjmp) + if (HAVE_nonlocal_goto_receiver) + emit_insn (gen_nonlocal_goto_receiver ()); +#endif +} + + +struct func_eh_entry +{ + int range_number; /* EH region number from EH NOTE insn's */ + struct handler_info *handlers; +}; + + +/* table of function eh regions */ +static struct func_eh_entry *function_eh_regions = NULL; +static int num_func_eh_entries = 0; +static int current_func_eh_entry = 0; + +#define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X) + +/* Add a new eh_entry for this function, and base it off of the information + in the EH_ENTRY parameter. A NULL parameter is invalid. The number + returned is an number which uniquely identifies this exception range. */ + +int +new_eh_region_entry (note_eh_region) + int note_eh_region; +{ + if (current_func_eh_entry == num_func_eh_entries) + { + if (num_func_eh_entries == 0) + { + function_eh_regions = + (struct func_eh_entry *) malloc (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)); + } + } + function_eh_regions[current_func_eh_entry].range_number = note_eh_region; + function_eh_regions[current_func_eh_entry].handlers = NULL; + + return current_func_eh_entry++; +} + +/* Add new handler information to an exception range. The first parameter + specifies the range number (returned from new_eh_entry()). The second + parameter specifies the handler. By default the handler is inserted at + the end of the list. A handler list may contain only ONE NULL_TREE + typeinfo entry. Regardless where it is positioned, a NULL_TREE entry + is always output as the LAST handler in the exception table for a region. */ + +void +add_new_handler (region, newhandler) + int region; + struct handler_info *newhandler; +{ + struct handler_info *last; + + newhandler->next = NULL; + last = function_eh_regions[region].handlers; + if (last == NULL) + function_eh_regions[region].handlers = newhandler; + else + { + for ( ; last->next != NULL; last = last->next) + last->next = newhandler; + } +} + +/* Create a new handler structure initialized with the handler label and + typeinfo fields passed in. */ + +struct handler_info * +get_new_handler (handler, typeinfo) + rtx handler; + void *typeinfo; +{ + struct handler_info* ptr; + ptr = (struct handler_info *) malloc (sizeof (struct handler_info)); + ptr->handler_label = handler; + ptr->type_info = typeinfo; + ptr->next = NULL; + + return ptr; +} + + + +/* 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! */ + +int +find_func_region (insn_region) + int insn_region; +{ + int x; + for (x = 0; x < current_func_eh_entry; x++) + if (function_eh_regions[x].range_number == insn_region) + return x; + + return -1; +} + +/* Get a pointer to the first handler in an exception region's list. */ + +struct handler_info * +get_first_handler (region) + int region; +{ + return function_eh_regions[find_func_region (region)].handlers; +} + +/* Clean out the function_eh_region table and free all memory */ + +static void +clear_function_eh_region () +{ + int x; + struct handler_info *ptr, *next; + for (x = 0; x < current_func_eh_entry; x++) + for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next) + { + next = ptr->next; + free (ptr); + } + free (function_eh_regions); + num_func_eh_entries = 0; + current_func_eh_entry = 0; +} + +/* Make a duplicate of an exception region by copying all the handlers + for an exception region. Return the new handler index. */ + +int +duplicate_handlers (old_note_eh_region, new_note_eh_region) + int old_note_eh_region, new_note_eh_region; +{ + struct handler_info *ptr, *new_ptr; + int new_region, region; + + region = find_func_region (old_note_eh_region); + if (region == -1) + error ("Cannot duplicate non-existant exception region."); + + if (find_func_region (new_note_eh_region) != -1) + error ("Cannot duplicate EH region because new note region already exists"); + + new_region = new_eh_region_entry (new_note_eh_region); + ptr = function_eh_regions[region].handlers; + + for ( ; ptr; ptr = ptr->next) + { + new_ptr = get_new_handler (ptr->handler_label, ptr->type_info); + add_new_handler (new_region, new_ptr); + } + + return new_region; +} + /* Routine to see if exception handling is turned on. DO_WARN is non-zero if we want to inform the user that exception @@ -1118,6 +1331,9 @@ expand_eh_region_end (handler) entry->finalization = handler; + /* create region entry in final exception table */ + new_eh_region_entry (NOTE_BLOCK_NUMBER (note)); + enqueue_eh_entry (&ehqueue, entry); /* If we have already started ending the bindings, don't recurse. @@ -1232,19 +1448,13 @@ expand_leftover_cleanups () abort (); /* Output the label for the start of the exception handler. */ - emit_label (entry->exception_handler_label); -#ifdef HAVE_exception_receiver - if (! exceptions_via_longjmp) - if (HAVE_exception_receiver) - emit_insn (gen_exception_receiver ()); -#endif + receive_exception_label (entry->exception_handler_label); -#ifdef HAVE_nonlocal_goto_receiver - if (! exceptions_via_longjmp) - if (HAVE_nonlocal_goto_receiver) - emit_insn (gen_nonlocal_goto_receiver ()); -#endif + /* 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); @@ -1270,6 +1480,37 @@ expand_start_try_stmts () expand_eh_region_start (); } +/* Called to begin a catch clause. The parameter is the object which + will be passed to the runtime type check routine. */ +void +expand_start_catch (rtime) + tree rtime; +{ + rtx handler_label = catchstack.top->entry->exception_handler_label; + int insn_region_num = CODE_LABEL_NUMBER (handler_label); + int eh_region_entry = find_func_region (insn_region_num); + + /* If we've already issued this label, pick a new one */ + if (catchstack.top->entry->label_used == 0) + handler_label = gen_exception_label (); + else + catchstack.top->entry->label_used = 1; + + receive_exception_label (handler_label); + + add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime)); +} + +/* End a catch clause by dequeuing the current region */ + +void +expand_end_catch () +{ + struct eh_entry *entry; + entry = pop_eh_entry (&catchstack); + free (entry); +} + /* Generate RTL for the start of a group of catch clauses. It is responsible for starting a new instruction sequence for the @@ -1308,12 +1549,13 @@ expand_start_all_catch () the handlers in this handler-seq. */ start_sequence (); - while (1) + entry = dequeue_eh_entry (&ehqueue); + for ( ; entry->finalization != integer_zero_node; + entry = dequeue_eh_entry (&ehqueue)) { rtx prev; - entry = dequeue_eh_entry (&ehqueue); - /* Emit the label for the exception handler for this region, and + /* 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; @@ -1322,29 +1564,15 @@ expand_start_all_catch () 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. */ - emit_label (entry->exception_handler_label); - -#ifdef HAVE_exception_receiver - if (! exceptions_via_longjmp) - if (HAVE_exception_receiver) - emit_insn (gen_exception_receiver ()); -#endif - -#ifdef HAVE_nonlocal_goto_receiver - if (! exceptions_via_longjmp) - if (HAVE_nonlocal_goto_receiver) - emit_insn (gen_nonlocal_goto_receiver ()); -#endif + + receive_exception_label (entry->exception_handler_label); - /* When we get down to the matching entry for this try block, stop. */ - if (entry->finalization == integer_zero_node) - { - /* Don't forget to free this entry. */ - free (entry); - break; - } + /* 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. */ + /* And now generate the insns for the cleanup handler. */ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0); prev = get_last_insn (); @@ -1358,6 +1586,12 @@ expand_start_all_catch () 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); + /* 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 do this because we are not physically within the region, if any, that @@ -1496,15 +1730,16 @@ protect_with_terminate (e) handler for the region. This is added by add_eh_table_entry and used by output_exception_table_entry. */ -static int *eh_table; -static int eh_table_size; -static int eh_table_max_size; +static int *eh_table = NULL; +static int eh_table_size = 0; +static int eh_table_max_size = 0; /* Note the need for an exception table entry for region N. If we don't need to output an explicit exception table, avoid all of the extra work. 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 label number of the exception handler for the region. */ @@ -1562,24 +1797,60 @@ output_exception_table_entry (file, n) { char buf[256]; rtx sym; + int eh_entry; + struct handler_info *handler; + + handler = get_first_handler (n); - ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n); - sym = gen_rtx_SYMBOL_REF (Pmode, buf); - assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + for ( ; handler != NULL; handler = handler->next) + { + ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n); + sym = gen_rtx_SYMBOL_REF (Pmode, buf); + assemble_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); + ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n); + sym = gen_rtx_SYMBOL_REF (Pmode, buf); + assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + + assemble_integer (handler->handler_label, + POINTER_SIZE / BITS_PER_UNIT, 1); - ASM_GENERATE_INTERNAL_LABEL (buf, "L", n); - sym = gen_rtx_SYMBOL_REF (Pmode, buf); - assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); +#ifdef NEW_EH_MODEL + /* for now make sure the sizes match */ + if (handler->type_info == NULL) + assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); + else + output_constant ((tree)(handler->type_info), + POINTER_SIZE / BITS_PER_UNIT); +#endif - putc ('\n', file); /* blank line */ + putc ('\n', file); /* blank line */ + } } /* Output the exception table if we have and need one. */ +#ifdef NEW_EH_MODEL + +static short language_code = 0; +static short version_code = 0; + +/* This routine will set the language code for exceptions. */ +void set_exception_lang_code (code) + short code; +{ + language_code = code; +} + +/* This routine will set the language version code for exceptions. */ +void set_exception_version_code (code) + short code; +{ + version_code = code; +} + +#endif + void output_exception_table () { @@ -1595,15 +1866,31 @@ output_exception_table () assemble_align (GET_MODE_ALIGNMENT (ptr_mode)); assemble_label ("__EXCEPTION_TABLE__"); +#ifdef NEW_EH_MODEL + assemble_integer (GEN_INT (language_code), 2 , 1); + assemble_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); +#endif + 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 (); /* Ending marker for table. */ assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); +#ifndef NEW_EH_MODEL + /* for binary compatability, the old __throw checked the second + position for a -1, so we should output at least 2 -1's */ assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); - assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); +#endif putc ('\n', asm_out_file); /* blank line */ } @@ -1662,9 +1949,6 @@ void find_exception_handler_labels () { rtx insn; - int max_labelno = max_label_num (); - int min_labelno = get_first_label_num (); - rtx *labels; exception_handler_labels = NULL_RTX; @@ -1672,53 +1956,42 @@ find_exception_handler_labels () if (! doing_eh (0)) return; - /* Generate a handy reference to each label. */ - - /* We call xmalloc here instead of alloca; we did the latter in the past, - but found that it can sometimes end up being asked to allocate space - for more than 1 million labels. */ - labels = (rtx *) xmalloc ((max_labelno - min_labelno) * sizeof (rtx)); - bzero ((char *) labels, (max_labelno - min_labelno) * sizeof (rtx)); - - /* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER. */ - labels -= min_labelno; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == CODE_LABEL) - if (CODE_LABEL_NUMBER (insn) >= min_labelno - && CODE_LABEL_NUMBER (insn) < max_labelno) - labels[CODE_LABEL_NUMBER (insn)] = insn; - } - /* For each start of a region, add its label to the list. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { + struct handler_info* ptr; if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - rtx label = NULL_RTX; - - if (NOTE_BLOCK_NUMBER (insn) >= min_labelno - && NOTE_BLOCK_NUMBER (insn) < max_labelno) - { - label = labels[NOTE_BLOCK_NUMBER (insn)]; - - if (label) - exception_handler_labels - = gen_rtx_EXPR_LIST (VOIDmode, - label, exception_handler_labels); - else - warning ("didn't find handler for EH region %d", - NOTE_BLOCK_NUMBER (insn)); - } - else - warning ("mismatched EH region %d", NOTE_BLOCK_NUMBER (insn)); + ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn)); + for ( ; ptr; ptr = ptr->next) + { + /* make sure label isn't in the list already */ + rtx x; + for (x = exception_handler_labels; x; x = XEXP (x, 1)) + if (XEXP (x, 0) == ptr->handler_label) + break; + if (! x) + exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode, + ptr->handler_label, exception_handler_labels); + } } } +} + +/* Return a value of 1 if the parameter label number is an exception handler + label. Return 0 otherwise. */ - free (labels + min_labelno); +int +is_exception_handler_label (lab) + int lab; +{ + rtx x; + for (x = exception_handler_labels ; x ; x = XEXP (x, 1)) + if (lab == CODE_LABEL_NUMBER (XEXP (x, 0))) + return 1; + return 0; } /* Perform sanity checking on the exception_handler_labels list. @@ -1730,60 +2003,24 @@ find_exception_handler_labels () void check_exception_handler_labels () { - rtx insn, handler; + rtx insn, insn2; /* If we aren't doing exception handling, there isn't much to check. */ if (! doing_eh (0)) return; - /* Ensure that the CODE_LABEL_NUMBER for the CODE_LABEL entry point - in each handler corresponds to the CODE_LABEL_NUMBER of the - handler. */ - - for (handler = exception_handler_labels; - handler; - handler = XEXP (handler, 1)) + /* Make sure there is no more than 1 copy of a label */ + for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1)) { - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == CODE_LABEL) - { - if (CODE_LABEL_NUMBER (insn) - == CODE_LABEL_NUMBER (XEXP (handler, 0))) - { - if (insn != XEXP (handler, 0)) - warning ("mismatched handler %d", - CODE_LABEL_NUMBER (insn)); - break; - } - } - } - if (insn == NULL_RTX) - warning ("handler not found %d", - CODE_LABEL_NUMBER (XEXP (handler, 0))); + int count = 0; + for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1)) + if (XEXP (insn, 0) == XEXP (insn2, 0)) + count++; + if (count != 1) + warning ("Counted %d copies of EH region %d in list.\n", count, + CODE_LABEL_NUMBER (insn)); } - /* Now go through and make sure that for each region there is a - corresponding label. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == NOTE - && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) - { - for (handler = exception_handler_labels; - handler; - handler = XEXP (handler, 1)) - { - if (CODE_LABEL_NUMBER (XEXP (handler, 0)) - == NOTE_BLOCK_NUMBER (insn)) - break; - } - if (handler == NULL_RTX && !flag_syntax_only) - warning ("region exists, no handler %d", - NOTE_BLOCK_NUMBER (insn)); - } - } } /* This group of functions initializes the exception handling data @@ -1805,6 +2042,7 @@ void init_eh_for_function () { ehstack.top = 0; + catchstack.top = 0; ehqueue.head = ehqueue.tail = 0; catch_clauses = NULL_RTX; false_label_stack = 0; @@ -1826,6 +2064,7 @@ save_eh_status (p) abort (); p->ehstack = ehstack; + p->catchstack = catchstack; p->ehqueue = ehqueue; p->catch_clauses = catch_clauses; p->false_label_stack = false_label_stack; @@ -1853,6 +2092,7 @@ restore_eh_status (p) catch_clauses = p->catch_clauses; ehqueue = p->ehqueue; ehstack = p->ehstack; + catchstack = p->catchstack; current_function_ehc = p->ehc; } @@ -1951,6 +2191,10 @@ scan_region (insn, n, delete_outer) delete_insn (start); delete_insn (insn); +/* We no longer removed labels here, since flow will now remove any + handler which cannot be called any more. */ + +#if 0 /* Only do this part if we have built the exception handler labels. */ if (exception_handler_labels) @@ -1984,6 +2228,7 @@ scan_region (insn, n, delete_outer) prev = &XEXP (x, 1); } } +#endif } return insn; } @@ -2133,6 +2378,20 @@ eh_regs (r1, r2, outgoing) *r2 = reg2; } + +/* Retrieve the register which contains the pointer to the eh_context + structure set the __throw. */ + +rtx +get_reg_for_handler () +{ + rtx reg1; + reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node), + current_function_decl); + return reg1; +} + + /* Emit inside of __throw a stub which adjusts the stack pointer and jumps to the exception handler. __throw will set up the necessary values and then return to the stub. */ @@ -2150,8 +2409,28 @@ expand_builtin_eh_stub () eh_regs (&handler, &offset, 0); adjust_stack (offset); +#ifdef NEW_EH_MODEL + + /* Handler is in fact a pointer to the _eh_context structure, we need + to pick out the handler field (first element), and jump to there, + leaving the pointer to _eh_conext in the same hardware register. */ + { + rtx jump_to, temp; + + temp = gen_rtx_MEM (Pmode, handler); + MEM_IN_STRUCT_P (temp) = 1; + RTX_UNCHANGING_P (temp) = 1; + emit_insn (gen_rtx_SET (Pmode, offset, temp)); + emit_insn (gen_rtx_USE (Pmode, handler)); + + emit_indirect_jump (offset); + + } + +#else emit_indirect_jump (handler); +#endif emit_label (after_stub); return gen_rtx_LABEL_REF (Pmode, stub_start); } @@ -2213,7 +2492,8 @@ set_insn_eh_region (first, region_num) /* Free the insn table, an make sure it cannot be used again. */ -void free_insn_eh_region () +void +free_insn_eh_region () { if (!doing_eh (0)) return; @@ -2229,7 +2509,8 @@ void free_insn_eh_region () this routine. If it is unavailable, passing a value of 0 will cause this routine to calculate it as well. */ -void init_insn_eh_region (first, max_uid) +void +init_insn_eh_region (first, max_uid) rtx first; int max_uid; { @@ -2255,8 +2536,9 @@ void init_insn_eh_region (first, max_uid) /* Check whether 2 instructions are within the same region. */ -int in_same_eh_region(insn1, insn2) - rtx insn1,insn2; +int +in_same_eh_region (insn1, insn2) + rtx insn1, insn2; { int ret, uid1, uid2; diff --git a/gcc/except.h b/gcc/except.h index d93a8c9..6cb6dc8 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -43,6 +43,10 @@ struct label_node { EXCEPTION_HANDLER_LABEL is the label corresponding to the handler for this region. + LABEL_USED indicates whether a CATCH block has already used this + label or not. New ones are needed for additional catch blocks if + it has. + FINALIZATION is the tree codes for the handler, or is NULL_TREE if one hasn't been generated yet, or is integer_zero_node to mark the end of a group of try blocks. */ @@ -50,8 +54,8 @@ struct label_node { struct eh_entry { rtx outer_context; rtx exception_handler_label; - tree finalization; + int label_used; }; /* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next @@ -145,17 +149,89 @@ extern int doing_eh PROTO ((int)); /* Toplevel initialization for EH. */ +#ifdef NEW_EH_MODEL + +void set_exception_lang_code PROTO((short)); +void set_exception_version_code PROTO((short)); + +#endif + +/* A list of handlers asocciated with an exception region. HANDLER_LABEL + is the the label that control should be transfered to if the data + in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO + means This is a cleanup, and must always be called. A value of + CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher + is still performed to avoid being caught by a different language + exception. NEXT is a pointer to the next handler for this region. + NULL means there are no more. */ + +#define CATCH_ALL_TYPE (tree *) -1 + +typedef struct handler_info +{ + rtx handler_label; + void *type_info; + struct handler_info *next; +} handler_info; + + +/* Add a new eh_entry for this function, The parameter specifies what + exception region number NOTE insns use to delimit this range. + The integer returned is uniquely identifies this exception range + within an internal table. */ + +int new_eh_region_entry PROTO((int)); + +/* Add new handler information to an exception range. The first parameter + specifies the range number (returned from new_eh_entry()). The second + parameter specifies the handler. By default the handler is inserted at + the end of the list. A handler list may contain only ONE NULL_TREE + typeinfo entry. Regardless where it is positioned, a NULL_TREE entry + is always output as the LAST handler in the exception table for a region. */ + +void add_new_handler PROTO((int, struct handler_info *)); + +/* Create a new handler structure initialized with the handler label and + typeinfo fields passed in. */ + +struct handler_info *get_new_handler PROTO((rtx, void *)); + +/* Make a duplicate of an exception region by copying all the handlers + for an exception region. Return the new handler index. */ + +int duplicate_handlers PROTO((int, int)); + + +/* Get a pointer to the first handler in an exception region's list. */ + +struct handler_info *get_first_handler PROTO((int)); + + extern void init_eh PROTO((void)); /* Initialization for the per-function EH data. */ extern void init_eh_for_function PROTO((void)); +/* Generate an exception label. Use instead of gen_label_rtx */ + +extern rtx gen_exception_label PROTO((void)); + /* Adds an EH table entry for EH entry number N. Called from final_scan_insn for NOTE_INSN_EH_REGION_BEG. */ extern void add_eh_table_entry PROTO((int n)); +/* Start a catch clause, triggered by runtime value paramter. */ + +#ifdef TREE_CODE +extern void expand_start_catch PROTO((tree)); +#endif + +/* End a catch clause. */ + +extern void expand_end_catch PROTO((void)); + /* Returns a non-zero value if we need to output an exception table. */ extern int exception_table_p PROTO((void)); @@ -225,6 +301,10 @@ extern void end_eh_unwinder PROTO((void)); extern void find_exception_handler_labels PROTO((void)); +/* Determine if an arbitrary label is an exception label */ + +extern int is_exception_handler_label PROTO((int)); + /* Performs sanity checking on the check_exception_handler_labels list. */ diff --git a/gcc/final.c b/gcc/final.c index d45b577..89436e4 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1988,7 +1988,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) && ! exceptions_via_longjmp) { ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn)); +#ifndef NEW_EH_MODEL add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); +#endif #ifdef ASM_OUTPUT_EH_REGION_BEG ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn)); #endif @@ -1999,6 +2001,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) && ! exceptions_via_longjmp) { ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn)); +#ifdef NEW_EH_MODEL + add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); +#endif #ifdef ASM_OUTPUT_EH_REGION_END ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn)); #endif diff --git a/gcc/flow.c b/gcc/flow.c index 14791e2..95beb78d 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -396,7 +396,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) register char *block_marked = (char *) alloca (n_basic_blocks); /* An array of CODE_LABELs, indexed by UID for the start of the active EH handler for each insn in F. */ - rtx *active_eh_handler; + int *active_eh_region; + int *nested_eh_region; /* List of label_refs to all labels whose addresses are taken and used as data. */ rtx label_value_list; @@ -406,7 +407,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) int in_libcall_block = 0; pass = 1; - active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx)); + active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int)); + nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int)); restart: label_value_list = 0; @@ -414,7 +416,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) bzero (block_live, n_basic_blocks); bzero (block_marked, n_basic_blocks); bzero (basic_block_computed_jump_target, n_basic_blocks); - bzero ((char *) active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx)); + bzero ((char *) active_eh_region, (max_uid_for_flow + 1) * sizeof (int)); + bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int)); current_function_has_computed_jump = 0; /* Initialize with just block 0 reachable and no blocks marked. */ @@ -482,20 +485,18 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) label_value_list); } - /* Keep a lifo list of the currently active exception handlers. */ + /* Keep a lifo list of the currently active exception notes. */ if (GET_CODE (insn) == NOTE) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) { - for (x = exception_handler_labels; x; x = XEXP (x, 1)) - if (CODE_LABEL_NUMBER (XEXP (x, 0)) == NOTE_BLOCK_NUMBER (insn)) - { - eh_note = gen_rtx_EXPR_LIST (VOIDmode, - XEXP (x, 0), eh_note); - break; - } - if (x == NULL_RTX) - abort (); + if (eh_note) + nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = + NOTE_BLOCK_NUMBER (XEXP (eh_note, 0)); + else + nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = 0; + eh_note = gen_rtx_EXPR_LIST (VOIDmode, + insn, eh_note); } else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END) eh_note = XEXP (eh_note, 1); @@ -509,8 +510,8 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) && (asynchronous_exceptions || (GET_CODE (insn) == CALL_INSN && ! in_libcall_block))) - active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0); - + active_eh_region[INSN_UID (insn)] = + NOTE_BLOCK_NUMBER (XEXP (eh_note, 0)); BLOCK_NUM (insn) = i; if (code != NOTE) @@ -655,11 +656,20 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))) { - if (active_eh_handler[INSN_UID (insn)]) - mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, - active_eh_handler[INSN_UID (insn)]), - insn, 0); - + if (active_eh_region[INSN_UID (insn)]) + { + int region; + handler_info *ptr; + region = active_eh_region[INSN_UID (insn)]; + for ( ; region; + region = nested_eh_region[region]) + { + ptr = get_first_handler (region); + for ( ; ptr ; ptr = ptr->next) + mark_label_ref (gen_rtx_LABEL_REF + (VOIDmode, ptr->handler_label), insn, 0); + } + } if (!asynchronous_exceptions) { for (x = nonlocal_label_list; @@ -764,6 +774,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) /* Now we have to find the EH_BEG and EH_END notes associated with this label and remove them. */ +#if 0 +/* Handlers and labels no longer needs to have the same values. + If there are no references, scan_region will remove any region + labels which are of no use. */ for (x = get_insns (); x; x = NEXT_INSN (x)) { if (GET_CODE (x) == NOTE @@ -778,6 +792,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p) NOTE_SOURCE_FILE (x) = 0; } } +#endif break; } prev = &XEXP (x, 1); diff --git a/gcc/function.h b/gcc/function.h index f90830b..e31f484 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -133,6 +133,7 @@ struct function /* For exception handling information. */ struct eh_stack ehstack; + struct eh_stack catchstack; struct eh_queue ehqueue; rtx catch_clauses; struct label_node *false_label_stack; diff --git a/gcc/integrate.c b/gcc/integrate.c index 2f8dde1..7a58888 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -95,7 +95,12 @@ get_label_from_map (map, i) rtx x = map->label_map[i]; if (x == NULL_RTX) - x = map->label_map[i] = gen_label_rtx(); + { + push_obstacks_nochange (); + end_temporary_allocation (); + x = map->label_map[i] = gen_label_rtx(); + pop_obstacks (); + } return x; } @@ -658,10 +663,28 @@ save_for_inline_copying (fndecl) if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END) { + int new_region = CODE_LABEL_NUMBER + (label_map[NOTE_BLOCK_NUMBER (copy)]); + + /* we have to duplicate the handlers for the original */ + if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) + { + handler_info *ptr, *temp; + int nr; + nr = new_eh_region_entry (new_region); + ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy)); + for ( ; ptr; ptr = ptr->next) + { + temp = get_new_handler ( + label_map[CODE_LABEL_NUMBER (ptr->handler_label)], + ptr->type_info); + add_new_handler (nr, temp); + } + } + /* We have to forward these both to match the new exception region. */ - NOTE_BLOCK_NUMBER (copy) - = CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]); + NOTE_BLOCK_NUMBER (copy) = new_region; } RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn); @@ -2038,6 +2061,22 @@ expand_inline_function (fndecl, parms, target, ignore, type, rtx label = get_label_from_map (map, NOTE_BLOCK_NUMBER (copy)); + /* we have to duplicate the handlers for the original */ + if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) + { + handler_info *ptr, *temp; + int nr; + nr = new_eh_region_entry (CODE_LABEL_NUMBER (label)); + ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy)); + for ( ; ptr; ptr = ptr->next) + { + temp = get_new_handler ( get_label_from_map (map, + CODE_LABEL_NUMBER (ptr->handler_label)), + ptr->type_info); + add_new_handler (nr, temp); + } + } + /* We have to forward these both to match the new exception region. */ NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label); diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 1b33c05..c860412 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -3046,14 +3046,10 @@ __empty () { } -/* EH context structure. */ -struct eh_context -{ - void **dynamic_handler_chain; - /* This is language dependent part of the eh context. */ - void *info; -}; +/* Include definitions of EH context and table layout */ + +#include "eh-common.h" /* This is a safeguard for dynamic handler chain. */ @@ -3361,11 +3357,6 @@ EH_TABLE_LOOKUP #else #ifdef DWARF2_UNWIND_INFO -typedef struct exception_table { - void *start; - void *end; - void *exception_handler; -} exception_table; /* This routine takes a PC and a pointer to the exception region TABLE for its translation unit, and returns the address of the exception handler @@ -3376,31 +3367,68 @@ typedef struct exception_table { an inner block. */ static void * -find_exception_handler (void *pc, exception_table *table) +find_exception_handler (void *pc, exception_descriptor *table, void *eh_info) { if (table) { +#ifdef NEW_EH_MODEL + /* The new model assumed the table is sorted inner-most out so the + first region we find which matches is the correct one */ + + int pos; + void *ret; + exception_table *tab = &(table->table[0]); + + /* Subtract 1 from the PC to avoid hitting the next region */ + pc--; + + /* We can't do a binary search because the table is in inner-most + to outermost address ranges within functions */ + for (pos = 0; tab[pos].start_region != (void *) -1; pos++) + { + if (tab[pos].start_region <= pc && tab[pos].end_region > pc) + { + if (tab[pos].match_info) + { + __eh_matcher matcher = ((__eh_info *)eh_info)->match_function; + /* match info but no matcher is NOT a match */ + if (matcher) + { + ret = (*matcher)(eh_info, tab[pos].match_info, table); + if (ret) + { + ((__eh_info *)eh_info)->coerced_value = ret; + return tab[pos].exception_handler; + } + } + } + else + return tab[pos].exception_handler; + } + } +#else int pos; int best = -1; /* We can't do a binary search because the table isn't guaranteed - to be sorted from function to function. */ - for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos) - { - if (table[pos].start <= pc && table[pos].end > pc) - { - /* This can apply. Make sure it is at least as small as - the previous best. */ - if (best == -1 || (table[pos].end <= table[best].end - && table[pos].start >= table[best].start)) - best = pos; - } - /* But it is sorted by starting PC within a function. */ - else if (best >= 0 && table[pos].start > pc) - break; - } + to be sorted from function to function. */ + for (pos = 0; table[pos].start_region != (void *) -1; ++pos) + { + if (table[pos].start_region <= pc && table[pos].end_region > pc) + { + /* This can apply. Make sure it is at least as small as + the previous best. */ + if (best == -1 || (table[pos].end_region <= table[best].end_region + && table[pos].start_region >= table[best].start_region)) + best = pos; + } + /* But it is sorted by starting PC within a function. */ + else if (best >= 0 && table[pos].start_region > pc) + break; + } if (best != -1) - return table[best].exception_handler; + return table[best].exception_handler; +#endif } return (void *) 0; @@ -3583,7 +3611,7 @@ label: if (! udata) break; - handler = find_exception_handler (pc, udata->eh_ptr); + handler = find_exception_handler (pc, udata->eh_ptr, eh->info); /* If we found one, we can stop searching. */ if (handler) @@ -3602,6 +3630,10 @@ label: if (! handler) __terminate (); +#ifdef NEW_EH_MODEL + eh->handler_label = handler; +#endif + if (pc == saved_pc) /* We found a handler in the throw context, no need to unwind. */ udata = my_udata; @@ -3669,7 +3701,13 @@ label: /* Set up the registers we use to communicate with the stub. We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */ + +#ifdef NEW_EH_MODEL + __builtin_set_eh_regs ((void *)eh, +#else __builtin_set_eh_regs (handler, +#endif + #ifdef STACK_GROWS_DOWNWARD udata->cfa - my_udata->cfa #else -- cgit v1.1