[multiple changes]

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.

From-SVN: r17052
This commit is contained in:
Teemu Torma 1997-12-12 04:53:20 +00:00 committed by Jason Merrill
parent 24a184c9e7
commit 154bba13a4
20 changed files with 567 additions and 134 deletions

View File

@ -1,3 +1,84 @@
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.
Thu Dec 11 17:23:48 1997 John F. Carr <jfc@mit.edu>
* sparc/sol2.h: Use 64 bit multiply and divide functions in

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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"

View File

@ -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) \

View File

@ -1,3 +1,17 @@
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.
Wed Dec 10 11:04:45 1997 Jason Merrill <jason@yorick.cygnus.com>
* pt.c (instantiate_decl): Defer all templates but inline functions.

View File

@ -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;

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -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. */
/* The EH context. Nonzero if the function has already
fetched a pointer to the EH context 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. */
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

View File

@ -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));

View File

@ -39,6 +39,13 @@ Boston, MA 02111-1307, USA. */
#include "dwarf2.h"
#include <stddef.h>
#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 ();
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 *));

View File

@ -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

View File

@ -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 ();