[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:
parent
24a184c9e7
commit
154bba13a4
20 changed files with 567 additions and 134 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
233
gcc/except.c
233
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. */
|
||||
/* 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
|
||||
|
|
21
gcc/except.h
21
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));
|
||||
|
|
27
gcc/frame.c
27
gcc/frame.c
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
206
gcc/libgcc2.c
206
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)
|
||||
|
|
|
@ -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 *));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
Loading…
Add table
Reference in a new issue