From 154bba13a4a3d494a12622c489ba9d7bd1f76a8b Mon Sep 17 00:00:00 2001 From: Teemu Torma Date: Fri, 12 Dec 1997 04:53:20 +0000 Subject: [PATCH] [multiple changes] Thu Dec 11 20:42:18 1997 Teemu Torma Thread-safe EH support for pthreads, DCE threads and Solaris threads. * integrate.c (expand_inline_function): If the inline fn uses eh context, make sure that the current fn has one. * toplev.c (rest_of_compilation): Call emit_eh_context. * except.c (use_eh_context): New fn. (get_eh_context_once): New fn. (call_get_eh_context): New fn. (emit_eh_context): New fn. (get_eh_context): Call either get_eh_context_once or call_get_eh_context, depending on what we have. (get_dynamic_handler_chain): Call get_eh_context_once. * except.h: Prototypes for fns above. * optabs.c (get_eh_context_libfunc): Removed. (init_optabs): Don't initialize it. * expr.h (get_eh_context_libfunc): Removed. * rtl.h, rtl.c: New reg_note REG_EH_CONTEXT. * config/pa/pa.h (CPP_SPEC): Support for -threads. * config/pa/pa-hpux10.h (LIB_SPEC): Ditto. * config/pa/t-pa (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): New multilib for -threads. * config/sparc/t-sol2: Added multilibs for -threads and made -pthreads alias to it. * config/sparc/sol2.h (CPP_SPEC, LIB_SPEC): Added -threads and -pthreads options. * libgcc-thr.h: New file. * libgcc2.c: (__get_cpp_eh_context): Removed. (struct cpp_eh_context): Removed. (struct eh_context): Replaced cpp_eh_context with generic language specific pointer. (__get_eh_info): New function. (__throw): Check eh_context::info. (__sjthrow): Ditto. * libgcc2.c: Include libgcc-thr.h. (new_eh_context, __get_eh_context, eh_pthread_initialize, eh_context_initialize, eh_context_static, eh_context_specific, eh_context_free): New functions. (get_eh_context, eh_context_key): New variables. (__sjthrow, __sjpopnthrow, __eh_pcnthrow, __throw): Use get_eh_context to get the context. (longjmp): Move the declaration inside #ifdef DONT_USE_BUILTIN_SETJMP. * frame.c: Include libgcc-thr.h. (object_mutex): Mutex to protect the object list. (find_fde, __register_frame, __register_frame_table, __deregister_frame): Hold the lock while accessing objects. * except.h (get_eh_context): Declare. * except.c (current_function_ehc): Define. (current_function_dhc, current_function_dcc): Removed. (get_eh_context): New function. (get_dynamic_handler_chain): Use get_eh_context. (get_saved_pc_ref): Ditto. (get_dynamic_cleanup_chain): Removed references to current_function_dcc. (save_eh_status, restore_eh_status): Save and restore current_function_ehc instead. * optabs.c (get_eh_context_libfunc): New variable. (init_optabs): Initialize it. * expr.h: Declare get_eh_context_libfunc. * function.h (struct function): Replaced dhc and dcc with ehc. * except.c (get_saved_pc_ref): New functions. (eh_saved_pc_rtx, eh_saved_pc): Deleted. (expand_internal_throw_indirect): Use get_saved_pc_ref() instead of eh_saved_pc. (end_eh_unwinder): Likewise. (init_eh): Remove initialization of eh_saved_pc. * optabs.c (get_saved_pc_libfunc): New variable. (init_optabs): Initialize it. * expr.h: Declare get_saved_pc_libfunc. * except.h (eh_saved_pc_rtx): Deleted. (get_saved_pc_ref): Declared. From Scott Snyder : * libgcc2.c (__get_saved_pc): New. (__eh_type, __eh_pc): Deleted. (__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc. (__get_dynamic_handler_chain): Move __dynamic_handler_chain inside this fcn. cp/: Thu Dec 11 20:43:33 1997 Teemu Torma * decl.c (ptr_ptr_type_node): Define. (init_decl_processing): Initialize it. * cp-tree.h: Declare it. * exception.cc (__cp_exception_info): Use __get_eh_info. (__cp_push_exception): Ditto. (__cp_pop_exception): Ditto. From Scott Snyder : * except.c (expand_builtin_throw): Use get_saved_pc_ref instead of saved_pc. (init_exception_processing): Removed saved_pc initialization. From-SVN: r17052 --- gcc/ChangeLog | 81 +++++++++++++ gcc/config/pa/pa-hpux10.h | 11 ++ gcc/config/pa/pa.h | 7 +- gcc/config/pa/t-pa | 6 + gcc/config/sparc/sol2.h | 9 +- gcc/config/sparc/t-sol2 | 7 ++ gcc/cp/ChangeLog | 14 +++ gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 5 + gcc/cp/except.c | 20 +--- gcc/cp/exception.cc | 15 ++- gcc/except.c | 233 +++++++++++++++++++++++++++----------- gcc/except.h | 21 +++- gcc/frame.c | 27 ++++- gcc/function.h | 24 +++- gcc/integrate.c | 6 + gcc/libgcc2.c | 206 ++++++++++++++++++++++++++++----- gcc/rtl.c | 2 +- gcc/rtl.h | 2 +- gcc/toplev.c | 3 + 20 files changed, 567 insertions(+), 134 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bb0666e46a3..8d36284cf57c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,84 @@ +Thu Dec 11 20:42:18 1997 Teemu Torma + + Thread-safe EH support for pthreads, DCE threads and Solaris threads. + + * integrate.c (expand_inline_function): If the inline fn uses eh + context, make sure that the current fn has one. + * toplev.c (rest_of_compilation): Call emit_eh_context. + * except.c (use_eh_context): New fn. + (get_eh_context_once): New fn. + (call_get_eh_context): New fn. + (emit_eh_context): New fn. + (get_eh_context): Call either get_eh_context_once or + call_get_eh_context, depending on what we have. + (get_dynamic_handler_chain): Call get_eh_context_once. + * except.h: Prototypes for fns above. + * optabs.c (get_eh_context_libfunc): Removed. + (init_optabs): Don't initialize it. + * expr.h (get_eh_context_libfunc): Removed. + * rtl.h, rtl.c: New reg_note REG_EH_CONTEXT. + * config/pa/pa.h (CPP_SPEC): Support for -threads. + * config/pa/pa-hpux10.h (LIB_SPEC): Ditto. + * config/pa/t-pa (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): + New multilib for -threads. + * config/sparc/t-sol2: Added multilibs for -threads and + made -pthreads alias to it. + * config/sparc/sol2.h (CPP_SPEC, LIB_SPEC): + Added -threads and -pthreads options. + * libgcc-thr.h: New file. + * libgcc2.c: (__get_cpp_eh_context): Removed. + (struct cpp_eh_context): Removed. + (struct eh_context): Replaced cpp_eh_context with generic language + specific pointer. + (__get_eh_info): New function. + (__throw): Check eh_context::info. + (__sjthrow): Ditto. + * libgcc2.c: Include libgcc-thr.h. + (new_eh_context, __get_eh_context, + eh_pthread_initialize, eh_context_initialize, eh_context_static, + eh_context_specific, eh_context_free): New functions. + (get_eh_context, eh_context_key): New variables. + (__sjthrow, __sjpopnthrow, __eh_pcnthrow, __throw): Use + get_eh_context to get the context. + (longjmp): Move the declaration inside + #ifdef DONT_USE_BUILTIN_SETJMP. + * frame.c: Include libgcc-thr.h. + (object_mutex): Mutex to protect the object list. + (find_fde, __register_frame, __register_frame_table, + __deregister_frame): Hold the lock while accessing objects. + * except.h (get_eh_context): Declare. + * except.c (current_function_ehc): Define. + (current_function_dhc, current_function_dcc): Removed. + (get_eh_context): New function. + (get_dynamic_handler_chain): Use get_eh_context. + (get_saved_pc_ref): Ditto. + (get_dynamic_cleanup_chain): Removed references to + current_function_dcc. + (save_eh_status, restore_eh_status): Save and restore + current_function_ehc instead. + * optabs.c (get_eh_context_libfunc): New variable. + (init_optabs): Initialize it. + * expr.h: Declare get_eh_context_libfunc. + * function.h (struct function): Replaced dhc and dcc with ehc. + * except.c (get_saved_pc_ref): New functions. + (eh_saved_pc_rtx, eh_saved_pc): Deleted. + (expand_internal_throw_indirect): Use get_saved_pc_ref() instead + of eh_saved_pc. + (end_eh_unwinder): Likewise. + (init_eh): Remove initialization of eh_saved_pc. + * optabs.c (get_saved_pc_libfunc): New variable. + (init_optabs): Initialize it. + * expr.h: Declare get_saved_pc_libfunc. + * except.h (eh_saved_pc_rtx): Deleted. + (get_saved_pc_ref): Declared. + + From Scott Snyder : + * libgcc2.c (__get_saved_pc): New. + (__eh_type, __eh_pc): Deleted. + (__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc. + (__get_dynamic_handler_chain): Move __dynamic_handler_chain inside + this fcn. + Thu Dec 11 17:23:48 1997 John F. Carr * sparc/sol2.h: Use 64 bit multiply and divide functions in diff --git a/gcc/config/pa/pa-hpux10.h b/gcc/config/pa/pa-hpux10.h index 9a2af5d578ca..0cd59127f682 100644 --- a/gcc/config/pa/pa-hpux10.h +++ b/gcc/config/pa/pa-hpux10.h @@ -30,6 +30,17 @@ Boston, MA 02111-1307, USA. */ "-z %{mlinker-opt:-O} %{!shared:-u main} %{static:-a archive} %{shared:-b}" #endif +/* Like the default, except no -lg. */ +#undef LIB_SPEC +#define LIB_SPEC \ + "%{!shared:\ + %{!p:\ + %{!pg:\ + %{!threads:-lc}\ + %{threads:-lcma -lc_r}}\ + %{p: -L/lib/libp/ -lc}\ + %{pg: -L/lib/libp/ -lc}}}" + /* The hpux10 assembler requires a .LEVEL pseudo-op at the start of the assembly file. */ #undef ASM_FILE_START diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index c286fb9fa047..a127c84673d6 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -241,9 +241,12 @@ extern int target_flags; #if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & 1) == 0 #define CPP_SPEC "%{msnake:-D__hp9000s700 -D_PA_RISC1_1}\ %{mpa-risc-1-1:-D__hp9000s700 -D_PA_RISC1_1}\ - %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}" + %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}\ + %{threads:-D_REENTRANT -D_DCE_THREADS}" #else -#define CPP_SPEC "%{!mpa-risc-1-0:%{!mnosnake:%{!msoft-float:-D__hp9000s700 -D_PA_RISC1_1}}} %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}" +#define CPP_SPEC "%{!mpa-risc-1-0:%{!mnosnake:%{!msoft-float:-D__hp9000s700 -D_PA_RISC1_1}}} \ + %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}\ + %{threads:-D_REENTRANT -D_DCE_THREADS}" #endif /* Defines for a K&R CC */ diff --git a/gcc/config/pa/t-pa b/gcc/config/pa/t-pa index a359918a1259..b6dcec1212ea 100644 --- a/gcc/config/pa/t-pa +++ b/gcc/config/pa/t-pa @@ -16,3 +16,9 @@ ee_fp.asm: $(srcdir)/config/pa/ee_fp.asm cp $(srcdir)/config/pa/ee_fp.asm . TARGET_LIBGCC2_CFLAGS = -fPIC + +MULTILIB_OPTIONS = threads +MULTILIB_DIRNAMES = threads + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index 5891222a0ce4..76cade44d9e0 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -30,6 +30,8 @@ Boston, MA 02111-1307, USA. */ #undef CPP_SUBTARGET_SPEC #define CPP_SUBTARGET_SPEC "\ +%{pthreads:-D_REENTRANT -D_PTHREADS} \ +%{!pthreads:%{threads:-D_REENTRANT -D_SOLARIS_THREADS}} \ %{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude} \ " @@ -131,7 +133,12 @@ Boston, MA 02111-1307, USA. */ #undef LIB_SPEC #define LIB_SPEC \ - "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} %{!shared:%{!symbolic:-lc}}" + "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} \ + %{!shared:\ + %{!symbolic:\ + %{pthreads:-lpthread} \ + %{!pthreads:%{threads:-lthread}} \ + -lc}}" #undef ENDFILE_SPEC #define ENDFILE_SPEC "crtend.o%s crtn.o%s" diff --git a/gcc/config/sparc/t-sol2 b/gcc/config/sparc/t-sol2 index d41254adb442..309aedfd9f9b 100644 --- a/gcc/config/sparc/t-sol2 +++ b/gcc/config/sparc/t-sol2 @@ -5,6 +5,13 @@ LIBGCC1 = CROSS_LIBGCC1 = LIBGCC1_TEST = +MULTILIB_OPTIONS = threads +MULTILIB_DIRNAMES = threads +MULTILIB_MATCHES = threads=pthreads + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + # gmon build rule: gmon.o: $(srcdir)/config/sparc/gmon-sol2.c $(GCC_PASSES) $(CONFIG_H) stmp-int-hdrs $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 88732201b200..d2070090997d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +Thu Dec 11 20:43:33 1997 Teemu Torma + + * decl.c (ptr_ptr_type_node): Define. + (init_decl_processing): Initialize it. + * cp-tree.h: Declare it. + * exception.cc (__cp_exception_info): Use __get_eh_info. + (__cp_push_exception): Ditto. + (__cp_pop_exception): Ditto. + + From Scott Snyder : + * except.c (expand_builtin_throw): Use get_saved_pc_ref instead of + saved_pc. + (init_exception_processing): Removed saved_pc initialization. + Wed Dec 10 11:04:45 1997 Jason Merrill * pt.c (instantiate_decl): Defer all templates but inline functions. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e1653020194c..48740a5e3cb0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1511,7 +1511,7 @@ extern tree vt_off_identifier; /* A node that is a list (length 1) of error_mark_nodes. */ extern tree error_mark_list; -extern tree ptr_type_node; +extern tree ptr_type_node, ptr_ptr_type_node; extern tree class_type_node, record_type_node, union_type_node, enum_type_node; extern tree unknown_type_node; extern tree opaque_type_node, signature_type_node; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7ece1d33d38d..fd753d8ad79d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -241,6 +241,10 @@ tree void_zero_node; tree ptr_type_node; tree const_ptr_type_node; +/* Node for type `void **'. */ + +tree ptr_ptr_type_node; + /* Nodes for types `char *' and `const char *'. */ tree string_type_node, const_string_type_node; @@ -5065,6 +5069,7 @@ init_decl_processing () ptr_type_node = build_pointer_type (void_type_node); const_ptr_type_node = build_pointer_type (build_type_variant (void_type_node, 1, 0)); + ptr_ptr_type_node = build_pointer_type (ptr_type_node); #if 0 record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node); #endif diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 3d62c7718452..0fa5c2425a8f 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -186,9 +186,6 @@ static tree Unwind; ========================================================================= */ #ifndef DWARF2_UNWIND_INFO -/* Holds the pc for doing "throw" */ -static tree saved_pc; - extern int throw_used; #endif @@ -258,15 +255,6 @@ init_exception_processing () pop_lang_context (); -#ifndef DWARF2_UNWIND_INFO - d = build_decl (VAR_DECL, get_identifier ("__eh_pc"), ptr_type_node); - TREE_PUBLIC (d) = 1; - DECL_EXTERNAL (d) = 1; - DECL_ARTIFICIAL (d) = 1; - cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0); - saved_pc = d; -#endif - /* If we use setjmp/longjmp EH, arrange for all cleanup actions to be protected with __terminate. */ protect_cleanup_actions_with_terminate = 1; @@ -812,8 +800,10 @@ expand_builtin_throw () /* search for an exception handler for the saved_pc */ handler = do_function_call (FirstExceptionMatch, - expr_tree_cons (NULL_TREE, saved_pc, - NULL_TREE), + expr_tree_cons (NULL_TREE, + make_tree (ptr_ptr_type_node, + get_saved_pc_ref ()), + NULL_TREE), ptr_type_node); /* did we find one? */ @@ -892,7 +882,7 @@ expand_builtin_throw () } else #endif - emit_move_insn (eh_saved_pc_rtx, next_pc); + emit_move_insn (get_saved_pc_ref (), next_pc); after_unwind = gen_label_rtx (); do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind)); diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index aa5a46e2b266..399d2c60dbcc 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -91,9 +91,9 @@ struct cp_eh_info long handlers; }; -/* Language-specific EH info pointer, defined in libgcc2. */ +/* Language-specific EH info pointer, defined in libgcc2. */ -extern cp_eh_info *__eh_info; // actually void* +extern "C" cp_eh_info **__get_eh_info (); // actually void ** /* Is P the type_info node for a pointer of some kind? */ @@ -105,7 +105,7 @@ extern bool __is_pointer (void *); extern "C" cp_eh_info * __cp_exception_info (void) { - return __eh_info; + return *__get_eh_info (); } /* Compiler hook to push a new exception onto the stack. @@ -120,8 +120,11 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) p->cleanup = cleanup; p->handlers = 0; p->caught = false; - p->next = __eh_info; - __eh_info = p; + + cp_eh_info **q = __get_eh_info (); + + p->next = *q; + *q = p; } /* Compiler hook to pop an exception that has been finalized. Used by @@ -131,7 +134,7 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) extern "C" void __cp_pop_exception (cp_eh_info *p) { - cp_eh_info **q = &__eh_info; + cp_eh_info **q = __get_eh_info (); --p->handlers; diff --git a/gcc/except.c b/gcc/except.c index a39d8e5544ce..11c3be87fc57 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -431,17 +431,10 @@ rtx exception_handler_labels; int throw_used; -/* The dynamic handler chain. Nonzero if the function has already - fetched a pointer to the dynamic handler chain for exception - handling. */ - -rtx current_function_dhc; - -/* The dynamic cleanup chain. Nonzero if the function has already - fetched a pointer to the dynamic cleanup chain for exception - handling. */ +/* The EH context. Nonzero if the function has already + fetched a pointer to the EH context for exception handling. */ -rtx current_function_dcc; +rtx current_function_ehc; /* A stack used for keeping track of the currently active exception handling region. As each exception region is started, an entry @@ -496,13 +489,6 @@ struct label_node *outer_context_label_stack = NULL; struct label_node *false_label_stack = NULL; -#ifndef DWARF2_UNWIND_INFO -/* The rtx and the tree for the saved PC value. */ - -rtx eh_saved_pc_rtx; -tree eh_saved_pc; -#endif - rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); static void expand_rethrow PROTO((rtx)); @@ -721,37 +707,20 @@ add_partial_entry (handler) pop_obstacks (); } -/* Get a reference to the dynamic handler chain. It points to the - pointer to the next element in the dynamic handler chain. It ends - when there are no more elements in the dynamic handler chain, when - the value is &top_elt from libgcc2.c. Immediately after the - pointer, is an area suitable for setjmp/longjmp when - DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for - __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP - isn't defined. +/* Emit code to get EH context to current function. */ - This routine is here to facilitate the porting of this code to - systems with threads. One can either replace the routine we emit a - call for here in libgcc2.c, or one can modify this routine to work - with their thread system. - - Ideally, we really only want one per real function, not one - per inlined function. */ - -rtx -get_dynamic_handler_chain () +static rtx +call_get_eh_context (before) + rtx before; { static tree fn; tree expr; - rtx insns; - - if (current_function_dhc) - return current_function_dhc; + rtx ehc, reg, insns; if (fn == NULL_TREE) { tree fntype; - fn = get_identifier ("__get_dynamic_handler_chain"); + fn = get_identifier ("__get_eh_context"); push_obstacks_nochange (); end_temporary_allocation (); fntype = build_pointer_type (build_pointer_type @@ -771,15 +740,105 @@ get_dynamic_handler_chain () expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), expr, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (expr) = 1; - expr = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); start_sequence (); - current_function_dhc = expand_expr (expr, NULL_RTX, VOIDmode, 0); + ehc = expand_expr (expr, NULL_RTX, VOIDmode, 0); + reg = copy_to_reg (ehc); + insns = get_insns (); end_sequence (); - emit_insns_before (insns, get_first_nonparm_insn ()); - return current_function_dhc; + if (before != 0) + emit_insns_before (insns, before); + else + emit_insns (insns); + + return reg; +} + +/* Get a reference to the EH context. + We will only generate a register for the current function EH context here, + and emit a USE insn to mark that this is a EH context register. + + Later, emit_eh_context will emit needed call to __get_eh_context + in libgcc2, and copy the value to the register we have generated. */ + +rtx +use_eh_context () +{ + if (current_function_ehc == 0) + { + rtx insn; + + current_function_ehc = gen_reg_rtx (Pmode); + + insn = gen_rtx (USE, + GET_MODE (current_function_ehc), + copy_rtx (current_function_ehc)); + insn = emit_insn_before (insn, get_first_nonparm_insn ()); + + REG_NOTES (insn) + = gen_rtx (EXPR_LIST, + REG_EH_CONTEXT, copy_rtx (current_function_ehc), + REG_NOTES (insn)); + } + return current_function_ehc; +} + +/* Get reference to EH context only once per fn. */ + +rtx +get_eh_context_once () +{ + rtx ehc; + + if (current_function_ehc == 0) + use_eh_context (); + + ehc = gen_reg_rtx (Pmode); + emit_move_insn (ehc, current_function_ehc); + + return ehc; +} + +/* Get reference to EH context by calling __get_eh_context. */ + +rtx +get_eh_context () +{ + rtx ehc; + + /* If we already have an EH context in the current function, + use it. */ + if (current_function_ehc) + ehc = get_eh_context_once (); + else + ehc = call_get_eh_context (0); + + return ehc; +} + +/* Get a reference to the dynamic handler chain. It points to the + pointer to the next element in the dynamic handler chain. It ends + when there are no more elements in the dynamic handler chain, when + the value is &top_elt from libgcc2.c. Immediately after the + pointer, is an area suitable for setjmp/longjmp when + DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for + __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP + isn't defined. */ + +rtx +get_dynamic_handler_chain () +{ + rtx ehc, dhc, result; + + ehc = get_eh_context_once (); + dhc = ehc; + + result = copy_to_reg (dhc); + + /* We don't want a copy of the dcc, but rather, the single dcc. */ + return gen_rtx (MEM, Pmode, result); } /* Get a reference to the dynamic cleanup chain. It points to the @@ -791,15 +850,31 @@ get_dynamic_handler_chain () rtx get_dynamic_cleanup_chain () { - rtx dhc, dcc; + rtx dhc, dcc, result; dhc = get_dynamic_handler_chain (); dcc = plus_constant (dhc, GET_MODE_SIZE (Pmode)); - current_function_dcc = copy_to_reg (dcc); + result = copy_to_reg (dcc); /* We don't want a copy of the dcc, but rather, the single dcc. */ - return gen_rtx (MEM, Pmode, current_function_dcc); + return gen_rtx (MEM, Pmode, result); +} + +/* Get a reference to the saved_pc variable. */ + +rtx +get_saved_pc_ref () +{ + rtx ehc, ehpc, result; + + /* Saved PC is the second word into the returned structure. */ + ehc = get_eh_context (); + ehpc = plus_constant (ehc, GET_MODE_SIZE (Pmode)); + result = copy_to_reg (ehpc); + + /* We don't want a copy of the ehpc, but rather, the single ehpc. */ + return gen_rtx (MEM, Pmode, result); } /* Generate code to evaluate X and jump to LABEL if the value is nonzero. @@ -1220,8 +1295,7 @@ expand_internal_throw () rtx label = gen_label_rtx (); emit_label (label); label = gen_rtx (LABEL_REF, Pmode, label); - assemble_external (eh_saved_pc); - emit_move_insn (eh_saved_pc_rtx, label); + emit_move_insn (get_saved_pc_ref (), label); } #endif emit_throw (); @@ -1698,8 +1772,6 @@ end_eh_unwinder () return; #else /* DWARF2_UNWIND_INFO */ - assemble_external (eh_saved_pc); - expr = make_node (RTL_EXPR); TREE_TYPE (expr) = void_type_node; RTL_EXPR_RTL (expr) = const0_rtx; @@ -1717,7 +1789,7 @@ end_eh_unwinder () return_val_rtx = eh_outer_context (return_val_rtx); return_val_rtx = expand_binop (Pmode, sub_optab, return_val_rtx, GEN_INT (1), NULL_RTX, 0, OPTAB_LIB_WIDEN); - emit_move_insn (eh_saved_pc_rtx, return_val_rtx); + emit_move_insn (get_saved_pc_ref (), return_val_rtx); /* Either set things up so we do a return directly to __throw, or we return here instead. */ @@ -1828,6 +1900,46 @@ emit_unwinder () emit_insns_after (insns, insn); } +/* Emit code to get EH context. + + We have to scan thru the code to find possible EH context registers. + Inlined functions may use it too, and thus we'll have to be able + to change them too. + + This is done only if using exceptions_via_longjmp. */ + +void +emit_eh_context () +{ + rtx insn; + rtx ehc = 0; + + if (! doing_eh (0)) + return; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == USE) + { + rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0); + if (reg) + { + rtx insns; + + /* If this is the first use insn, emit the call here. */ + if (ehc == 0) + ehc = call_get_eh_context (insn); + + start_sequence (); + emit_move_insn (XEXP (reg, 0), ehc); + insns = get_insns (); + end_sequence (); + + emit_insns_before (insns, insn); + } + } +} + /* Scan the current insns and build a list of handler labels. The resulting list is placed in the global variable exception_handler_labels. @@ -1977,14 +2089,6 @@ init_eh () /* Generate rtl to reference the variable in which the PC of the current context is saved. */ tree type = build_pointer_type (make_node (VOID_TYPE)); - -#ifndef DWARF2_UNWIND_INFO - eh_saved_pc = build_decl (VAR_DECL, get_identifier ("__eh_pc"), type); - DECL_EXTERNAL (eh_saved_pc) = 1; - TREE_PUBLIC (eh_saved_pc) = 1; - make_decl_rtl (eh_saved_pc, NULL_PTR, 1); - eh_saved_pc_rtx = DECL_RTL (eh_saved_pc); -#endif } /* Initialize the per-function EH information. */ @@ -1998,8 +2102,7 @@ init_eh_for_function () false_label_stack = 0; caught_return_label_stack = 0; protect_list = NULL_TREE; - current_function_dhc = NULL_RTX; - current_function_dcc = NULL_RTX; + current_function_ehc = NULL_RTX; } /* Save some of the per-function EH info into the save area denoted by @@ -2020,8 +2123,7 @@ save_eh_status (p) p->false_label_stack = false_label_stack; p->caught_return_label_stack = caught_return_label_stack; p->protect_list = protect_list; - p->dhc = current_function_dhc; - p->dcc = current_function_dcc; + p->ehc = current_function_ehc; init_eh (); } @@ -2043,8 +2145,7 @@ restore_eh_status (p) catch_clauses = p->catch_clauses; ehqueue = p->ehqueue; ehstack = p->ehstack; - current_function_dhc = p->dhc; - current_function_dcc = p->dcc; + current_function_ehc = p->ehc; } /* This section is for the exception handling specific optimization diff --git a/gcc/except.h b/gcc/except.h index 46b1f47879e2..abfeb478ea6c 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -201,6 +201,11 @@ extern void expand_internal_throw PROTO((void)); extern void expand_leftover_cleanups PROTO((void)); +/* If necessary, emit insns to get EH context for the current + function. */ + +extern void emit_eh_context PROTO((void)); + /* If necessary, emit insns for the start of per-function unwinder for the current function. */ @@ -240,21 +245,29 @@ extern struct label_node *false_label_stack; extern rtx exception_handler_labels; -/* The rtx for the saved PC value. */ - -extern rtx eh_saved_pc_rtx; - /* Performs optimizations for exception handling, such as removing unnecessary exception regions. Invoked from jump_optimize (). */ extern void exception_optimize PROTO((void)); +/* Use EH context once per fn. */ +extern rtx use_eh_context PROTO((void)); + +/* Get the EH contex only once per fn. */ +extern rtx get_eh_context_once PROTO((void)); + +/* Get the EH contex. */ +extern rtx get_eh_context PROTO((void)); + /* Get the dynamic handler chain. */ extern rtx get_dynamic_handler_chain PROTO((void)); /* Get the dynamic cleanup chain. */ extern rtx get_dynamic_cleanup_chain PROTO((void)); +/* Get the saved PC variable. */ +extern rtx get_saved_pc_ref PROTO((void)); + /* Throw an exception. */ extern void emit_throw PROTO((void)); diff --git a/gcc/frame.c b/gcc/frame.c index 747fb9f1c40b..296e6a9456d1 100644 --- a/gcc/frame.c +++ b/gcc/frame.c @@ -39,6 +39,13 @@ Boston, MA 02111-1307, USA. */ #include "dwarf2.h" #include #include "frame.h" +#include "libgcc-thr.h" + +#ifdef __GTHREAD_MUTEX_INIT +static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT; +#else +static __gthread_mutex_t object_mutex; +#endif /* Don't use `fancy_abort' here even if config.h says to use it. */ #ifdef abort @@ -296,6 +303,8 @@ find_fde (void *pc) struct object *ob; size_t lo, hi; + __gthread_mutex_lock (&object_mutex); + for (ob = objects; ob; ob = ob->next) { if (ob->pc_begin == 0) @@ -304,6 +313,8 @@ find_fde (void *pc) break; } + __gthread_mutex_unlock (&object_mutex); + if (ob == 0) return 0; @@ -509,8 +520,12 @@ __register_frame (void *begin, struct object *ob) ob->fde_array = 0; ob->count = 0; + __gthread_mutex_lock (&object_mutex); + ob->next = objects; objects = ob; + + __gthread_mutex_unlock (&object_mutex); } /* Similar, but BEGIN is actually a pointer to a table of unwind entries @@ -526,8 +541,12 @@ __register_frame_table (void *begin, struct object *ob) ob->pc_begin = ob->pc_end = 0; ob->count = 0; + __gthread_mutex_lock (&object_mutex); + ob->next = objects; objects = ob; + + __gthread_mutex_unlock (&object_mutex); } /* Called from crtend.o to deregister the unwind info for an object. */ @@ -535,8 +554,11 @@ __register_frame_table (void *begin, struct object *ob) void __deregister_frame (void *begin) { - struct object **p = &objects; + struct object **p; + __gthread_mutex_lock (&object_mutex); + + p = &objects; while (*p) { if ((*p)->fde_begin == begin) @@ -548,10 +570,13 @@ __deregister_frame (void *begin) if (ob->pc_begin) free (ob->fde_array); + __gthread_mutex_unlock (&object_mutex); return; } p = &((*p)->next); } + + __gthread_mutex_unlock (&object_mutex); abort (); } diff --git a/gcc/function.h b/gcc/function.h index f54622fa71d1..a0a37467ab59 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -136,8 +136,7 @@ struct function struct label_node *false_label_stack; struct label_node *caught_return_label_stack; tree protect_list; - rtx dhc; - rtx dcc; + rtx ehc; /* For expr.c. */ int pending_stack_adjust; @@ -200,6 +199,7 @@ struct function struct pool_sym **const_rtx_sym_hash_table; struct pool_constant *first_pool, *last_pool; int pool_offset; + rtx const_double_chain; }; /* The FUNCTION_DECL for an inline function currently being expanded. */ @@ -234,12 +234,24 @@ extern HOST_WIDE_INT get_frame_size PROTO((void)); /* These variables hold pointers to functions to save and restore machine-specific data, in push_function_context and pop_function_context. */ -extern void (*save_machine_status) (); -extern void (*restore_machine_status) (); +extern void (*save_machine_status) PROTO((struct function *)); +extern void (*restore_machine_status) PROTO((struct function *)); -/* Save and restore varasm.c status for a nested function. */ -extern void save_varasm_status PROTO((struct function *)); +/* Save and restore status information for a nested function. */ +extern void save_tree_status PROTO((struct function *, tree)); +extern void restore_tree_status PROTO((struct function *, tree)); +extern void save_varasm_status PROTO((struct function *, tree)); extern void restore_varasm_status PROTO((struct function *)); +extern void save_eh_status PROTO((struct function *)); +extern void restore_eh_status PROTO((struct function *)); +extern void save_stmt_status PROTO((struct function *)); +extern void restore_stmt_status PROTO((struct function *)); +extern void save_expr_status PROTO((struct function *)); +extern void restore_expr_status PROTO((struct function *)); +extern void save_emit_status PROTO((struct function *)); +extern void restore_emit_status PROTO((struct function *)); +extern void save_storage_status PROTO((struct function *)); +extern void restore_storage_status PROTO((struct function *)); #ifdef rtx #undef rtx diff --git a/gcc/integrate.c b/gcc/integrate.c index 2b2c8560918c..f69adb11485f 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -1805,6 +1805,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, inline_target. */ break; + /* If the inline fn needs eh context, make sure that + the current fn has one. */ + if (GET_CODE (pattern) == USE + && find_reg_note (insn, REG_EH_CONTEXT, 0) != 0) + use_eh_context (); + /* Ignore setting a function value that we don't want to use. */ if (map->inline_target == 0 && set != 0 diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index ad51863e9120..1ad63013a150 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -2962,11 +2962,9 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */ #ifdef L_eh -/* Shared exception handling support routines. */ +#include "libgcc-thr.h" -/* Language-specific information about the active exception(s). If there - are no active exceptions, it is set to 0. */ -void *__eh_info; +/* Shared exception handling support routines. */ void __default_terminate () @@ -2999,41 +2997,190 @@ __empty () { } +/* EH context structure. */ + +struct eh_context +{ + void **dynamic_handler_chain; + void *saved_pc; +#ifndef DWARF2_UNWIND_INFO + void *buf[2]; +#endif + /* This is language dependent part of the eh context. */ + void *info; +}; + +/* This is a safeguard for dynamic handler chain. */ + +static void *top_elt[2]; + +/* Allocate and return a new EH context structure. */ + +extern void __throw (); + +static void * +new_eh_context () +{ + struct eh_context *eh = (struct eh_context *) malloc (sizeof *eh); + if (! eh) + __terminate (); + + memset (eh, 0, sizeof *eh); + + eh->dynamic_handler_chain = top_elt; +#ifndef DWARF2_UNWIND_INFO + eh->buf[0] = &eh->saved_pc; + eh->buf[1] = &__throw; +#endif + + return eh; +} + +#if __GTHREADS +static __gthread_key_t eh_context_key; + +/* Destructor for struct eh_context. */ +static void +eh_context_free (void *ptr) +{ + if (ptr) + free (ptr); +} +#endif + +/* Pointer to function to return EH context. */ + +static struct eh_context *eh_context_initialize (); +static struct eh_context *eh_context_static (); +#if __GTHREADS +static struct eh_context *eh_context_specific (); +#endif + +static struct eh_context *(*get_eh_context) () = &eh_context_initialize; + +/* Routine to get EH context. + This one will simply call the function pointer. */ + +void * +__get_eh_context () +{ + return (void *) (*get_eh_context) (); +} + +/* Get and set the language specific info pointer. */ + +void ** +__get_eh_info () +{ + struct eh_context *eh = (*get_eh_context) (); + return (void **) &eh->info; +} + +#if __GTHREADS +static void +eh_threads_initialize () +{ + /* Try to create the key. If it fails, revert to static method, + otherwise start using thread specific EH contexts. */ + if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0) + get_eh_context = &eh_context_specific; + else + get_eh_context = &eh_context_static; +} +#endif /* no __GTHREADS */ + +/* Initialize EH context. + This will be called only once, since we change GET_EH_CONTEXT + pointer to another routine. */ + +static struct eh_context * +eh_context_initialize () +{ +#if __GTHREADS + + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + __gthread_once (&once, eh_threads_initialize); + +#else /* no __GTHREADS */ + + /* Use static version of EH context. */ + get_eh_context = &eh_context_static; + +#endif /* no __GTHREADS */ + + return (*get_eh_context) (); +} + +/* Return a static EH context. */ + +static struct eh_context * +eh_context_static () +{ + static struct eh_context *eh; + if (! eh) + eh = new_eh_context (); + return eh; +} + +#if __GTHREADS +/* Return a thread specific EH context. */ + +static struct eh_context * +eh_context_specific () +{ + struct eh_context *eh; + eh = (struct eh_context *) __gthread_getspecific (eh_context_key); + if (! eh) + { + eh = new_eh_context (); + if (__gthread_setspecific (eh_context_key, (void *) eh) != 0) + __terminate (); + } + + return eh; +} +#endif __GTHREADS + /* Support routines for setjmp/longjmp exception handling. */ /* Calls to __sjthrow are generated by the compiler when an exception is raised when using the setjmp/longjmp exception handling codegen method. */ +#ifdef DONT_USE_BUILTIN_SETJMP extern void longjmp (void *, int); - -static void *top_elt[2]; -void **__dynamic_handler_chain = top_elt; +#endif /* Routine to get the head of the current thread's dynamic handler chain - use for exception handling. - - TODO: make thread safe. */ + use for exception handling. */ void *** __get_dynamic_handler_chain () { - return &__dynamic_handler_chain; + struct eh_context *eh = (*get_eh_context) (); + return (void ***) &eh->dynamic_handler_chain; +} + +void ** +__get_saved_pc () +{ + struct eh_context *eh = (*get_eh_context) (); + return (void **) &eh->saved_pc; } /* This is used to throw an exception when the setjmp/longjmp codegen method is used for exception handling. - We call __terminate if there are no handlers left (we know this - when the dynamic handler chain is top_elt). Otherwise we run the - cleanup actions off the dynamic cleanup stack, and pop the top of - the dynamic handler chain, and use longjmp to transfer back to the - associated handler. */ + We call __terminate if there are no handlers left. Otherwise we run the + cleanup actions off the dynamic cleanup stack, and pop the top of the + dynamic handler chain, and use longjmp to transfer back to the associated + handler. */ void __sjthrow () { - void ***dhc = __get_dynamic_handler_chain (); + struct eh_context *eh = (*get_eh_context) (); + void ***dhc = &eh->dynamic_handler_chain; void *jmpbuf; void (*func)(void *, int); void *arg; @@ -3081,7 +3228,7 @@ __sjthrow () /* We must call terminate if we try and rethrow an exception, when there is no exception currently active and when there are no handlers left. */ - if (! __eh_info || (*dhc) == top_elt) + if (! eh->info || (*dhc) == top_elt) __terminate (); /* Find the jmpbuf associated with the top element of the dynamic @@ -3108,7 +3255,8 @@ __sjthrow () void __sjpopnthrow () { - void ***dhc = __get_dynamic_handler_chain (); + struct eh_context *eh = (*get_eh_context) (); + void ***dhc = &eh->dynamic_handler_chain; void *jmpbuf; void (*func)(void *, int); void *arg; @@ -3288,11 +3436,8 @@ __throw () /* See expand_builtin_throw for details. */ void **__eh_pcnthrow () { - static void *buf[2] = { - &__eh_pc, - &__throw - }; - return buf; + struct eh_context *eh = (*get_eh_context) (); + return &eh->buf[0]; } #if #machine(i386) @@ -3499,7 +3644,8 @@ in_reg_window (int reg, frame_state *udata) void __throw () { - void *pc, *handler, *retaddr, *__eh_pc; + struct eh_context *eh = (*get_eh_context) (); + void *saved_pc, *pc, *handler, *retaddr; frame_state ustruct, ustruct2; frame_state *udata = &ustruct; frame_state *sub_udata = &ustruct2; @@ -3509,7 +3655,7 @@ __throw () /* This is required for C++ semantics. We must call terminate if we try and rethrow an exception, when there is no exception currently active. */ - if (! __eh_info) + if (! eh->info) __terminate (); /* Start at our stack frame. */ @@ -3534,8 +3680,8 @@ label: __builtin_unwind_init (); /* Now reset pc to the right throw point. */ - __eh_pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; - pc = __eh_pc; + pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1; + saved_pc = pc; handler = 0; for (;;) @@ -3567,7 +3713,7 @@ label: if (! handler) __terminate (); - if (pc == __eh_pc) + if (pc == saved_pc) /* We found a handler in the throw context, no need to unwind. */ udata = my_udata; else @@ -3582,7 +3728,7 @@ label: void *handler_pc = pc; /* Start from the throw context again. */ - pc = __eh_pc; + pc = saved_pc; memcpy (udata, my_udata, sizeof (*udata)); while (pc != handler_pc) diff --git a/gcc/rtl.c b/gcc/rtl.c index dde2a8396a5e..69e517143db8 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -182,7 +182,7 @@ char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0", "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL", "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB", "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", - "REG_BR_PRED" }; + "REG_BR_PRED", "REG_EH_CONTEXT" }; static void dump_and_abort PROTO((int, int, FILE *)); static void read_name PROTO((char *, FILE *)); diff --git a/gcc/rtl.h b/gcc/rtl.h index 667cab72c5ba..62b134276874 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -325,7 +325,7 @@ enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4, REG_CC_SETTER = 11, REG_CC_USER = 12, REG_LABEL = 13, REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16, REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19, - REG_BR_PRED = 20 }; + REG_BR_PRED = 20, REG_EH_CONTEXT = 21 }; /* The base value for branch probability notes. */ #define REG_BR_PROB_BASE 10000 diff --git a/gcc/toplev.c b/gcc/toplev.c index 17318e25c44c..9cbd513fca2f 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3201,6 +3201,9 @@ rest_of_compilation (decl) goto exit_rest_of_compilation; } + /* Emit code to get eh context, if needed. */ + emit_eh_context (); + /* Add an unwinder for exception handling, if needed. This must be done before we finalize PIC code. */ emit_unwinder (); -- 2.43.5