Commit e976b8b2 by Mike Stump

Add setjmp/longjmp exception handling.

From-SVN: r13968
parent 2284f91b
......@@ -590,7 +590,6 @@ expand_call (exp, target, ignore)
int old_pending_adj = 0;
int old_stack_arg_under_construction;
int old_inhibit_defer_pop = inhibit_defer_pop;
tree old_cleanups = cleanups_this_call;
rtx call_fusage = 0;
register tree p;
register int i, j;
......@@ -720,17 +719,6 @@ expand_call (exp, target, ignore)
/* If inlining succeeded, return. */
if ((HOST_WIDE_INT) temp != -1)
{
if (flag_short_temps)
{
/* Perform all cleanups needed for the arguments of this
call (i.e. destructors in C++). It is ok if these
destructors clobber RETURN_VALUE_REG, because the
only time we care about this is when TARGET is that
register. But in C++, we take care to never return
that register directly. */
expand_cleanups_to (old_cleanups);
}
#ifdef ACCUMULATE_OUTGOING_ARGS
/* If the outgoing argument list must be preserved, push
the stack before executing the inlined function if it
......@@ -1979,8 +1967,9 @@ expand_call (exp, target, ignore)
/* If value type not void, return an rtx for the value. */
/* If there are cleanups to be called, don't use a hard reg as target. */
if (cleanups_this_call != old_cleanups
/* If there are cleanups to be called, don't use a hard reg as target.
We need to double check this and see if it matters anymore. */
if (any_pending_cleanups ()
&& target && REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
target = 0;
......@@ -2153,13 +2142,6 @@ expand_call (exp, target, ignore)
}
#endif
if (flag_short_temps)
{
/* Perform all cleanups needed for the arguments of this call
(i.e. destructors in C++). */
expand_cleanups_to (old_cleanups);
}
/* If size of args is variable or this was a constructor call for a stack
argument, restore saved stack-pointer value. */
......
......@@ -82,8 +82,35 @@ struct eh_queue {
};
/* Start an exception handling region. All instructions emitted after
this point are considered to be part of the region until
expand_eh_region_end () is invoked. */
extern void expand_eh_region_start PROTO((void));
/* Start an exception handling region for the given cleanup action.
All instructions emitted after this point are considered to be part
of the region until expand_eh_region_end () is invoked. CLEANUP is
the cleanup action to perform. The return value is true if the
exception region was optimized away. If that case,
expand_eh_region_end does not need to be called for this cleanup,
nor should it be.
This routine notices one particular common case in C++ code
generation, and optimizes it so as to not need the exception
region. */
extern int expand_eh_region_start_tree PROTO((tree));
/* End an exception handling region. The information about the region
is found on the top of ehstack.
HANDLER is either the cleanup for the exception region, or if we're
marking the end of a try block, HANDLER is integer_zero_node.
HANDLER will be transformed to rtl when expand_leftover_cleanups ()
is invoked. */
extern void expand_eh_region_end PROTO((tree));
/* Push RLABEL or TLABEL onto LABELSTACK. Only one of RLABEL or TLABEL
......@@ -101,16 +128,6 @@ extern rtx pop_label_entry PROTO((struct label_node **labelstack));
extern tree top_label_entry PROTO((struct label_node **labelstack));
/* The stack used to keep track of the exception region corresponding to
the current instruction. */
extern struct eh_stack ehstack;
/* A queue used to track closed exception regions whose handlers have
not been emitted yet. */
extern struct eh_queue ehqueue;
/* A set of insns for the catch clauses in the current function. They
will be emitted at the end of the current function. */
......@@ -233,3 +250,30 @@ extern rtx eh_saved_pc_rtx;
unnecessary exception regions. Invoked from jump_optimize (). */
extern void exception_optimize 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));
/* Throw an exception. */
extern void emit_throw PROTO((void));
/* One to use setjmp/longjmp method of generating code. */
extern int exceptions_via_longjmp;
/* One to enable asynchronous exception support. */
extern int asynchronous_exceptions;
/* One to protect cleanup actions with a handler that calls
__terminate, zero otherwise. */
extern int protect_cleanup_actions_with_terminate;
#ifdef TREE_CODE
extern tree protect_with_terminate PROTO((tree));
#endif
......@@ -108,12 +108,6 @@ extern tree nonlocal_labels;
These are the arguments to function calls that have already returned. */
extern int pending_stack_adjust;
/* A list of all cleanups which belong to the arguments of
function calls being expanded by expand_call. */
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
extern tree cleanups_this_call;
#endif
/* When temporaries are created by TARGET_EXPRs, they are created at
this level of temp_slot_level, so that they can remain allocated
until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
......@@ -359,6 +353,12 @@ extern rtx memset_libfunc;
extern rtx bzero_libfunc;
extern rtx throw_libfunc;
extern rtx sjthrow_libfunc;
extern rtx sjpopnthrow_libfunc;
extern rtx terminate_libfunc;
extern rtx setjmp_libfunc;
extern rtx longjmp_libfunc;
extern rtx get_dynamic_handler_chain_libfunc;
extern rtx eqhf2_libfunc;
extern rtx nehf2_libfunc;
......@@ -705,9 +705,6 @@ extern void clear_pending_stack_adjust PROTO((void));
extern void do_pending_stack_adjust PROTO((void));
#ifdef TREE_CODE
/* Expand all cleanups up to OLD_CLEANUPS. */
extern void expand_cleanups_to PROTO((tree));
/* Generate code to evaluate EXP and jump to LABEL if the value is zero. */
extern void jumpifnot PROTO((tree, rtx));
......
......@@ -308,10 +308,6 @@ extern int flag_schedule_insns_after_reload;
extern int flag_delayed_branch;
/* Nonzero means to run cleanups after CALL_EXPRs. */
extern int flag_short_temps;
/* Nonzero means pretend it is OK to examine bits of target floats,
even if that isn't true. The resulting code will have incorrect constants,
but the same series of instructions that the native compiler would make. */
......
......@@ -135,11 +135,12 @@ struct function
struct label_node *false_label_stack;
struct label_node *caught_return_label_stack;
tree protect_list;
rtx dhc;
rtx dcc;
/* For expr.c. */
int pending_stack_adjust;
int inhibit_defer_pop;
tree cleanups_this_call;
rtx saveregs_value;
rtx apply_args_value;
rtx forced_labels;
......
......@@ -3102,6 +3102,172 @@ EH_TABLE_LOOKUP
#else
void
__default_terminate ()
{
abort ();
}
void (*__terminate_func)() = __default_terminate;
void
__terminate ()
{
(*__terminate_func)();
}
/* Calls to __sjthrow are generated by the compiler when an exception
is raised when using the setjmp/longjmp exception handling codegen
method. */
extern longjmp (void *, int);
extern void *__eh_type;
static void *top_elt[2];
void **__dynamic_handler_chain = top_elt;
/* Routine to get the head of the current thread's dynamic handler chain
use for exception handling.
TODO: make thread safe. */
void ***
__get_dynamic_handler_chain ()
{
return &__dynamic_handler_chain;
}
/* 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. */
void
__sjthrow ()
{
void ***dhc = __get_dynamic_handler_chain ();
void *jmpbuf;
void (*func)(void *, int);
void *arg;
void ***cleanup;
/* The cleanup chain is one word into the buffer. Get the cleanup
chain. */
cleanup = (void***)&(*dhc)[1];
/* If there are any cleanups in the chain, run them now. */
if (cleanup[0])
{
double store[200];
void **buf = (void**)store;
buf[1] = 0;
buf[0] = (*dhc);
/* try { */
if (! setjmp (&buf[2]))
{
*dhc = buf;
while (cleanup[0])
{
func = (void(*)(void*, int))cleanup[0][1];
arg = (void*)cleanup[0][2];
/* Update this before running the cleanup. */
cleanup[0] = (void **)cleanup[0][0];
(*func)(arg, 2);
}
*dhc = buf[0];
}
/* catch (...) */
else
{
__terminate ();
}
}
/* 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_type || (*dhc) == top_elt)
__terminate ();
/* Find the jmpbuf associated with the top element of the dynamic
handler chain. The jumpbuf starts two words into the buffer. */
jmpbuf = &(*dhc)[2];
/* Then we pop the top element off the dynamic handler chain. */
*dhc = (void**)(*dhc)[0];
/* And then we jump to the handler. */
#ifdef USE_BUILTIN_SETJMP
__builtin_longjmp (jmpbuf, 1);
#else
longjmp (jmpbuf, 1);
#endif
}
/* Run cleanups on the dynamic cleanup stack for the current dynamic
handler, then pop the handler off the dynamic handler stack, and
then throw. This is used to skip the first handler, and transfer
control to the next handler in the dynamic handler stack. */
void
__sjpopnthrow ()
{
void ***dhc = __get_dynamic_handler_chain ();
void *jmpbuf;
void (*func)(void *, int);
void *arg;
void ***cleanup;
/* The cleanup chain is one word into the buffer. Get the cleanup
chain. */
cleanup = (void***)&(*dhc)[1];
/* If there are any cleanups in the chain, run them now. */
if (cleanup[0])
{
double store[200];
void **buf = (void**)store;
buf[1] = 0;
buf[0] = (*dhc);
/* try { */
if (! setjmp (&buf[2]))
{
*dhc = buf;
while (cleanup[0])
{
func = (void(*)(void*, int))cleanup[0][1];
arg = (void*)cleanup[0][2];
/* Update this before running the cleanup. */
cleanup[0] = (void **)cleanup[0][0];
(*func)(arg, 2);
}
*dhc = buf[0];
}
/* catch (...) */
else
{
__terminate ();
}
}
/* Then we pop the top element off the dynamic handler chain. */
*dhc = (void**)(*dhc)[0];
__sjthrow ();
}
typedef struct {
void *start;
void *end;
......
......@@ -528,10 +528,6 @@ int flag_shared_data;
int flag_delayed_branch;
/* Nonzero means to run cleanups after CALL_EXPRs. */
int flag_short_temps;
/* Nonzero if we are compiling pure (sharable) code.
Value is 1 if we are doing reasonable (i.e. simple
offset into offset table) pic. Value is 2 if we can
......@@ -646,6 +642,8 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"pic", &flag_pic, 1},
{"PIC", &flag_pic, 2},
{"exceptions", &flag_exceptions, 1},
{"sjlj-exceptions", &exceptions_via_longjmp, 1},
{"asynchronous-exceptions", &asynchronous_exceptions, 1},
{"profile-arcs", &profile_arc_flag, 1},
{"test-coverage", &flag_test_coverage, 1},
{"branch-probabilities", &flag_branch_probabilities, 1},
......
......@@ -458,7 +458,10 @@ DEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", "e", 4)
manages to act on the proper value.
The cleanup is executed by the first enclosing CLEANUP_POINT_EXPR, if
it exists, otherwise it is the responsibility of the caller to manually
call expand_cleanups_to, as needed. */
call expand_start_target_temps/expand_end_target_temps, as needed.
This differs from TRY_CATCH_EXPR in that operand 2 is always
evaluated when an exception isn't throw when cleanups are run. */
DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", "e", 3)
/* Specify a cleanup point.
......@@ -689,6 +692,24 @@ DEFTREECODE (PREDECREMENT_EXPR, "predecrement_expr", "e", 2)
DEFTREECODE (PREINCREMENT_EXPR, "preincrement_expr", "e", 2)
DEFTREECODE (POSTDECREMENT_EXPR, "postdecrement_expr", "e", 2)
DEFTREECODE (POSTINCREMENT_EXPR, "postincrement_expr", "e", 2)
/* Evalute operand 1. If and only if an exception is thrown during
the evaluation of operand 1, evaluate operand 2.
This differs from WITH_CLEANUP_EXPR, in that operand 2 is never
evaluated unless an exception is throw. */
DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", "e", 2)
/* Pop the top element off the dynamic handler chain. Used in
conjunction with setjmp/longjmp based exception handling, see
except.c for more details. This is meant to be used only by the
exception handling backend, expand_dhc_cleanup specifically. */
DEFTREECODE (POPDHC_EXPR, "popdhc_expr", "s", 0)
/* Pop the top element off the dynamic cleanup chain. Used in
conjunction with the exception handling. This is meant to be used
only by the exception handling backend. */
DEFTREECODE (POPDCC_EXPR, "popdcc_expr", "s", 0)
/* These types of expressions have no useful value,
and always have side effects. */
......
......@@ -1690,7 +1690,14 @@ extern void expand_null_return PROTO((void));
extern void expand_return PROTO((tree));
extern void expand_start_bindings PROTO((int));
extern void expand_end_bindings PROTO((tree, int, int));
extern void start_cleanup_deferal PROTO((void));
extern void end_cleanup_deferal PROTO((void));
extern void mark_block_as_eh_region PROTO((void));
extern void mark_block_as_not_eh_region PROTO((void));
extern int is_eh_region PROTO((void));
extern int conditional_context PROTO((void));
extern tree last_cleanup_this_contour PROTO((void));
extern int expand_dhc_cleanup PROTO((void));
extern void expand_start_case PROTO((int, tree, tree,
char *));
extern void expand_end_case PROTO((tree));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment