Import the setjump/longjump exception handling fixes from GCC 2.95.3.test3

that were removed from GCC 2.95.3.test4 and the subsequent release due
to problems on HP-UX.  However, they work just fine on all the BSD's.

W/o these patches the following program segmentation faults if compiled
with -O2 (but not -Os or -O or -O0):

#include <stdio.h>

class A {
public:
  A() { printf("c'tor A\n"); }
  ~A(){ printf("d'tor A\n"); }
};

class foo : public A {
public:
  foo()  { printf("C'tor foo\n"); throw 8; }
  ~foo() { printf("D'tor foo\n"); }
};

int main(){
  try { foo fii; }
  catch (int){ printf("catch ...\n"); }
  return 0;
}
This commit is contained in:
obrien 2001-03-24 01:58:31 +00:00
parent b2d278bd47
commit 83655f473e
4 changed files with 141 additions and 73 deletions

View File

@ -723,21 +723,41 @@ static void
receive_exception_label (handler_label)
rtx handler_label;
{
rtx around_label = NULL_RTX;
if (! flag_new_exceptions || exceptions_via_longjmp)
{
around_label = gen_label_rtx ();
emit_jump (around_label);
emit_barrier ();
}
emit_label (handler_label);
if (! exceptions_via_longjmp)
{
#ifdef HAVE_exception_receiver
if (! exceptions_via_longjmp)
if (HAVE_exception_receiver)
emit_insn (gen_exception_receiver ());
if (HAVE_exception_receiver)
emit_insn (gen_exception_receiver ());
else
#endif
#ifdef HAVE_nonlocal_goto_receiver
if (! exceptions_via_longjmp)
if (HAVE_nonlocal_goto_receiver)
emit_insn (gen_nonlocal_goto_receiver ());
if (HAVE_nonlocal_goto_receiver)
emit_insn (gen_nonlocal_goto_receiver ());
else
#endif
}
{ /* Nothing */ }
}
else
{
#ifndef DONT_USE_BUILTIN_SETJMP
expand_builtin_setjmp_receiver (handler_label);
#endif
}
if (around_label)
emit_label (around_label);
}
struct func_eh_entry
{
@ -1320,7 +1340,7 @@ static void
start_dynamic_handler ()
{
rtx dhc, dcc;
rtx x, arg, buf;
rtx arg, buf;
int size;
#ifndef DONT_USE_BUILTIN_SETJMP
@ -1362,18 +1382,17 @@ start_dynamic_handler ()
buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
#ifdef DONT_USE_BUILTIN_SETJMP
x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
buf, Pmode);
/* If we come back here for a catch, transfer control to the handler. */
jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
#else
{
/* A label to continue execution for the no exception case. */
rtx noex = gen_label_rtx();
x = expand_builtin_setjmp (buf, NULL_RTX, noex,
ehstack.top->entry->exception_handler_label);
emit_label (noex);
rtx x;
x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST,
TYPE_MODE (integer_type_node), 1,
buf, Pmode);
/* If we come back here for a catch, transfer control to the handler. */
jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
}
#else
expand_builtin_setjmp_setup (buf,
ehstack.top->entry->exception_handler_label);
#endif
/* We are committed to this, so update the handler chain. */

View File

@ -192,6 +192,7 @@ static rtx expand_builtin PROTO((tree, rtx, rtx,
static int apply_args_size PROTO((void));
static int apply_result_size PROTO((void));
static rtx result_vector PROTO((int, rtx));
static rtx expand_builtin_setjmp PROTO((tree, rtx));
static rtx expand_builtin_apply_args PROTO((void));
static rtx expand_builtin_apply PROTO((rtx, rtx, rtx));
static void expand_builtin_return PROTO((rtx));
@ -8544,44 +8545,29 @@ expand_builtin_return_addr (fndecl_code, count, tem)
return tem;
}
/* __builtin_setjmp is passed a pointer to an array of five words (not
all will be used on all machines). It operates similarly to the C
library function of the same name, but is more efficient. Much of
the code below (and for longjmp) is copied from the handling of
non-local gotos.
/* Construct the leading half of a __builtin_setjmp call. Control will
return to RECEIVER_LABEL. This is used directly by sjlj exception
handling code. */
NOTE: This is intended for use by GNAT and the exception handling
scheme in the compiler and will only work in the method used by
them. */
rtx
expand_builtin_setjmp (buf_addr, target, first_label, next_label)
void
expand_builtin_setjmp_setup (buf_addr, receiver_label)
rtx buf_addr;
rtx target;
rtx first_label, next_label;
rtx receiver_label;
{
rtx lab1 = gen_label_rtx ();
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
enum machine_mode value_mode;
rtx stack_save;
value_mode = TYPE_MODE (integer_type_node);
#ifdef POINTERS_EXTEND_UNSIGNED
buf_addr = convert_memory_address (Pmode, buf_addr);
#endif
buf_addr = force_reg (Pmode, buf_addr);
if (target == 0 || GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (value_mode);
emit_queue ();
/* We store the frame pointer and the address of lab1 in the buffer
and use the rest of it for the stack save area, which is
machine-dependent. */
/* We store the frame pointer and the address of receiver_label in
the buffer and use the rest of it for the stack save area, which
is machine-dependent. */
#ifndef BUILTIN_SETJMP_FRAME_VALUE
#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
@ -8593,7 +8579,7 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
(gen_rtx_MEM (Pmode,
plus_constant (buf_addr,
GET_MODE_SIZE (Pmode)))),
force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, lab1)));
force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
stack_save = gen_rtx_MEM (sa_mode,
plus_constant (buf_addr,
@ -8606,20 +8592,22 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
emit_insn (gen_builtin_setjmp_setup (buf_addr));
#endif
/* Set TARGET to zero and branch to the first-time-through label. */
emit_move_insn (target, const0_rtx);
emit_jump_insn (gen_jump (first_label));
emit_barrier ();
emit_label (lab1);
/* Tell flow about the strange goings on. Putting `lab1' on
`nonlocal_goto_handler_labels' to indicates that function
calls may traverse the arc back to this label. */
/* Tell optimize_save_area_alloca that extra work is going to
need to go on during alloca. */
current_function_calls_setjmp = 1;
/* Set this so all the registers get saved in our frame; we need to be
able to copy the saved values for any registers from frames we unwind. */
current_function_has_nonlocal_label = 1;
nonlocal_goto_handler_labels =
gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
}
/* Construct the trailing part of a __builtin_setjmp call.
This is used directly by sjlj exception handling code. */
void
expand_builtin_setjmp_receiver (receiver_label)
rtx receiver_label ATTRIBUTE_UNUSED;
{
/* Clobber the FP when we get here, so we have to make sure it's
marked as used by this function. */
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
@ -8666,7 +8654,7 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
#ifdef HAVE_builtin_setjmp_receiver
if (HAVE_builtin_setjmp_receiver)
emit_insn (gen_builtin_setjmp_receiver (lab1));
emit_insn (gen_builtin_setjmp_receiver (receiver_label));
else
#endif
#ifdef HAVE_nonlocal_goto_receiver
@ -8678,11 +8666,67 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
; /* Nothing */
}
/* Set TARGET, and branch to the next-time-through label. */
emit_move_insn (target, const1_rtx);
emit_jump_insn (gen_jump (next_label));
emit_barrier ();
/* @@@ This is a kludge. Not all machine descriptions define a blockage
insn, but we must not allow the code we just generated to be reordered
by scheduling. Specifically, the update of the frame pointer must
happen immediately, not later. So emit an ASM_INPUT to act as blockage
insn. */
emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
}
/* __builtin_setjmp is passed a pointer to an array of five words (not
all will be used on all machines). It operates similarly to the C
library function of the same name, but is more efficient. Much of
the code below (and for longjmp) is copied from the handling of
non-local gotos.
NOTE: This is intended for use by GNAT and the exception handling
scheme in the compiler and will only work in the method used by
them. */
static rtx
expand_builtin_setjmp (arglist, target)
tree arglist;
rtx target;
{
rtx buf_addr, next_lab, cont_lab;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
return NULL_RTX;
if (target == 0 || GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (TYPE_MODE (integer_type_node));
buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
next_lab = gen_label_rtx ();
cont_lab = gen_label_rtx ();
expand_builtin_setjmp_setup (buf_addr, next_lab);
/* Set TARGET to zero and branch to the continue label. */
emit_move_insn (target, const0_rtx);
emit_jump_insn (gen_jump (cont_lab));
emit_barrier ();
emit_label (next_lab);
expand_builtin_setjmp_receiver (next_lab);
/* Set TARGET to one. */
emit_move_insn (target, const1_rtx);
emit_label (cont_lab);
/* Tell flow about the strange goings on. Putting `next_lab' on
`nonlocal_goto_handler_labels' to indicates that function
calls may traverse the arc back to this label. */
current_function_has_nonlocal_label = 1;
nonlocal_goto_handler_labels
= gen_rtx_EXPR_LIST (VOIDmode, next_lab, nonlocal_goto_handler_labels);
return target;
}
@ -9703,18 +9747,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
#endif
case BUILT_IN_SETJMP:
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
break;
else
{
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
VOIDmode, 0);
rtx lab = gen_label_rtx ();
rtx ret = expand_builtin_setjmp (buf_addr, target, lab, lab);
emit_label (lab);
return ret;
}
target = expand_builtin_setjmp (arglist, target);
if (target)
return target;
break;
/* __builtin_longjmp is passed a pointer to an array of five words.
It's similar to the C library longjmp function but works with

View File

@ -831,7 +831,8 @@ extern rtx store_expr PROTO((tree, rtx, int));
Useful after calling expand_expr with 1 as sum_ok. */
extern rtx force_operand PROTO((rtx, rtx));
extern rtx expand_builtin_setjmp PROTO((rtx, rtx, rtx, rtx));
extern void expand_builtin_setjmp_setup PARAMS ((rtx, rtx));
extern void expand_builtin_setjmp_receiver PARAMS ((rtx));
#ifdef TREE_CODE
/* Generate code for computing expression EXP.

View File

@ -3494,6 +3494,18 @@ force_const_mem (mode, x)
pop_obstacks ();
}
if (GET_CODE (x) == LABEL_REF)
{
extern rtx forced_labels;
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
XEXP (x, 0),
forced_labels);
pop_obstacks ();
}
/* Allocate a pool constant descriptor, fill it in, and chain it in. */