diff options
author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-12-12 04:53:20 +0000 |
---|---|---|
committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 1997-12-12 04:53:20 +0000 |
commit | 732992fad81a5d42283b07fd9442441acf685b5a (patch) | |
tree | b1e33498c494a6a7e60f2adbf6b766688bf20d7a /gcc/except.c | |
parent | b35797d55be1fdfacd475669c1c78ce9c74513db (diff) | |
download | gcc-732992fad81a5d42283b07fd9442441acf685b5a.tar.gz |
Thu Dec 11 20:42:18 1997 Teemu Torma <tot@trema.com>
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 <snyder@d0sgif.fnal.gov>:
* 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 <tot@trema.com>
* 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 <snyder@d0sgif.fnal.gov>:
* except.c (expand_builtin_throw): Use get_saved_pc_ref instead of
saved_pc.
(init_exception_processing): Removed saved_pc initialization.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@17052 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/except.c')
-rw-r--r-- | gcc/except.c | 233 |
1 files changed, 167 insertions, 66 deletions
diff --git a/gcc/except.c b/gcc/except.c index a39d8e5544c..11c3be87fc5 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 |