thread-safe exceptions (first cut)

scott snyder snyder@d0sgif.fnal.gov
Thu Sep 11 23:43:00 GMT 1997


hi -

Here's a first cut at thread-safe exceptions for egcs.
This seems to work for me on Digital Unix, but it almost certainly
needs more work before it can be added to the tree.  However, i'm not
going to be able to do any more on this for the next several weeks
(i'll be out of the country), so i thought i should send this around
in case someone else wanted to work on it.

Here are a couple notes on what i did:

 - I replaced references to __eh_pc with a call to a new library
   function __get_saved_pc, which works like __get_dynamic_handler_chain.
   In fact, perhaps these two should be merged into one routine.
   In any case, if the commented-out code in get_dynamic_handler_chain()
   to prevent multiple calls is ever fixed, the same thing should
   be done for get_saved_pc_ref().

 - I replaced the four C++-specific EH variables with a call to
   a new library function __get_cpp_eh_context, which returns
   a pointer to a structure.  In principle, this could be merged
   with __get_saved_pc as well, but it seemed like a good idea to keep
   the language-dependent part separate from the part which is
   supposed to be language-independent.  Since this is in the
   front end, calls to __get_saved_pc can be generated by building
   tree structures.  Here, i was able to simply turn on TREE_READONLY,
   and i found that multiple calls to __get_saved_pc got CSE'd away
   when i turned on optimization.  (Perhaps something similar can
   be done for __get_saved_pc and __get_dynamic_handler_chain?
   It looks like what's missing is that they need to have a LIBCALL
   block?)

 - I added the additional support routines to libgcc2.  If you compile
   with the defaults, exceptions should work, but they won't yet be
   thread-safe.  I added an alternate version of the code which
   is thread-safe with pthreads.  To enable that, you need to specify
   -D_PTHREADS when building libgcc.  Note that if you build libgcc
   in this way, then anything you compile with gcc will probably
   have to be linked with the pthreads libraries.  (On Dig. Unix 4.0,
   these are -lpthread -lmach -lexc.)

   This almost certainly needs more work to make this fit in with how
   the configuration process works.

   I've only tried to build this with _PTHREADS on Digital Unix 4.0.
   I don't know if it will work with other pthreads implementations.
   In particular, it _won't_ work as-is with DCE pthreads


I hope this is helpful to someone.
I'm appending a small program i used to test the thread safety
of exceptions, followed by the diffs against the 970910 snapshot.

sss

-- tthread.cc ----------------------------------------------------------------

#include <pthread.h>
#include <stdio.h>

class A
{
public:
  A (int the_n) : n (the_n) {}
  virtual ~A () {}
  int n;
};


class B : public A
{
public:
  B (int the_n) : A (the_n) {}
};


const int nloops = 5000;
const int nthreads = 40;


void throw_a (int n)
{
  throw A (n);
}


void throw_b (int n)
{
  throw B (n);
}


void* thread_body (void* arg)
{
  int n = (int) arg;

  printf ("Thread %d starting.\n", n);

  for (int i=0; i<nloops; i++) {
    try {
      throw_a (n);
      abort ();
    }
    catch (B&) {
      abort ();
    }
    catch (A& a) {
      if (a.n != n) abort ();
    }
    catch (...) {
      abort ();
    }

    try {
      throw_b (n);
      abort ();
    }
    catch (B& b) {
      if (b.n != n) abort ();
    }
    catch (A&) {
      abort ();
    }
    catch (...) {
      abort ();
    }
  }

  printf ("Thread %d terminating.\n", n);

  return 0;
}



main ()
{
  pthread_t threads[nthreads];

  for (int i=0; i<nthreads; i++) {
    if (pthread_create (&threads[i], 0, thread_body, (void*)i))
      abort ();
  }

  for (int i=0; i<nthreads; i++) {
    void* val;
    if (pthread_join (threads[i], &val))
      abort ();
  }
}
------------------------------------------------------------------------------

gcc/ChangeLog
Thu Sep 11 17:13:11 1997  scott snyder  <snyder@d0sgif.fnal.gov>

	* libgcc2.c: Add pthread support for exceptions.

	* libgcc2.c (cpp_eh_context, __get_cpp_eh_context,
	__get_saved_pc): New.
	(__eh_type, __eh_pc): Deleted.
	(__sjthrow): Use __get_cpp_eh_context()->type instead of
	__eh_type.
	(__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc.
	(__get_dynamic_handler_chain): Move __dynamic_handler_chain inside
	this fcn.

	* 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.

gcc/cp/ChangeLog
Thu Sep 11 17:14:24 1997  scott snyder  <snyder@d0sgif.fnal.gov>

	* exception.cc (uncaught_exception): Use __get_cpp_eh_context()
	instead of __eh_type and __eh_in_catch.

        * except.c (saved_in_catch, saved_cleanup, saved_throw_value,
	saved_throw_type): Deleted.
	(init_exception_processing): Remove their initializations.
	Initialize GetCPPEHContextRef and PFV_type_node.
	(GetCPPEHContextRef, PFV_type_nodebuild_saved_in_catch,
	build_saved_cleanup, build_saved_throw_value,
	build_saved_throw_type): New.
	(push_eh_cleanup): Use build_saved_* instead of saved_*.
	(expand_start_catch_block): Likewise.
	(expand_builtin_throw): Likewise.
	(expand_end_eh_spec): Likewise.
	(expand_throw): Likewise.




*** gcc/except.c-orig	Thu Sep 11 17:10:10 1997
--- gcc/except.c	Thu Sep 11 17:12:23 1997
***************
*** 458,468 ****
  
  struct label_node *false_label_stack = NULL;
  
- /* The rtx and the tree for the saved PC value.  */
- 
- rtx eh_saved_pc_rtx;
- tree eh_saved_pc;
- 
  rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
  
  /* Various support routines to manipulate the various data structures
--- 458,463 ----
***************
*** 748,753 ****
--- 743,767 ----
    return gen_rtx (MEM, Pmode, current_function_dcc);
  }
  
+ /* Get a reference to the saved_pc variable.
+ 
+    FIXME: When get_dynamic_handler_chain() is fixed to only make the libcall
+           once per function, this should be fixed in the same way. */
+ 
+ rtx
+ get_saved_pc_ref ()
+ {
+   rtx ehpc, current_function_ehpc;
+ 
+   ehpc = emit_library_call_value (get_saved_pc_libfunc,
+                                   NULL_RTX, 1,
+                                   Pmode, 0);
+   current_function_ehpc = copy_to_reg (ehpc);
+ 
+   /* We don't want a copy of the ehpc, but rather, the single ehpc.  */
+   return gen_rtx (MEM, Pmode, current_function_ehpc);
+ }
+ 
  /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
     LABEL is an rtx of code CODE_LABEL, in this function.  */
  
***************
*** 1122,1129 ****
  expand_internal_throw_indirect (context)
       rtx context;
  {
!   assemble_external (eh_saved_pc);
!   emit_move_insn (eh_saved_pc_rtx, context);
    emit_throw ();
  }
  
--- 1136,1142 ----
  expand_internal_throw_indirect (context)
       rtx context;
  {
!   emit_move_insn (get_saved_pc_ref (), context);
    emit_throw ();
  }
  
***************
*** 1598,1605 ****
    if (exceptions_via_longjmp)
      return;
  
-   assemble_external (eh_saved_pc);
- 
    expr = make_node (RTL_EXPR);
    TREE_TYPE (expr) = void_type_node;
    RTL_EXPR_RTL (expr) = const0_rtx;
--- 1611,1616 ----
***************
*** 1615,1621 ****
    /* Get the address we need to use to determine what exception
       handler should be invoked, and store it in __eh_pc.  */
    return_val_rtx = eh_outer_context (return_val_rtx);
!   emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
    
    /* Either set things up so we do a return directly to __throw, or
       we return here instead.  */
--- 1626,1632 ----
    /* Get the address we need to use to determine what exception
       handler should be invoked, and store it in __eh_pc.  */
    return_val_rtx = eh_outer_context (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.  */
***************
*** 1869,1880 ****
    /* 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));
- 
-   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);
  }
  
  /* Initialize the per-function EH information.  */
--- 1880,1885 ----
*** gcc/except.h-orig	Thu Sep 11 17:10:15 1997
--- gcc/except.h	Thu Sep 11 17:12:29 1997
***************
*** 246,255 ****
  
  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 ().  */
  
--- 246,251 ----
***************
*** 260,265 ****
--- 256,264 ----
  
  /* 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.  */
  
*** gcc/expr.h-orig	Thu Sep 11 17:10:24 1997
--- gcc/expr.h	Thu Sep 11 17:12:40 1997
***************
*** 417,422 ****
--- 417,423 ----
  extern rtx setjmp_libfunc;
  extern rtx longjmp_libfunc;
  extern rtx get_dynamic_handler_chain_libfunc;
+ extern rtx get_saved_pc_libfunc;
  
  extern rtx eqhf2_libfunc;
  extern rtx nehf2_libfunc;
*** gcc/libgcc2.c-orig	Thu Sep 11 17:10:31 1997
--- gcc/libgcc2.c	Thu Sep 11 17:12:50 1997
***************
*** 3131,3152 ****
     is raised when using the setjmp/longjmp exception handling codegen
     method.  */
  
  extern void longjmp (void *, int);
  
! 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
--- 3131,3257 ----
     is raised when using the setjmp/longjmp exception handling codegen
     method.  */
  
+ #ifndef _PTHREADS
  extern void longjmp (void *, int);
+ #endif
  
! struct cpp_eh_context
! {
!   void *type;
!   void *value;
!   void  (*cleanup) ();
!   int   in_catch;
! };
  
  static void *top_elt[2];
  
! /* Throw stub routine.
! 
!    This is work in progress, but not completed yet.  */
! 
! void
! __throw ()
! {
!   abort ();
! }
! 
! #ifdef _PTHREADS
! 
! #define __C_ASM_H /* suppress including c_asm.h on dec unix */
! #include <pthread.h>
! 
! struct full_eh_context {
!   void **dynamic_handler_chain;
!   void *saved_pc;
!   void *buf[2];
!   struct cpp_eh_context cpp;
! };
  
! 
! static pthread_key_t pthread_key;
! 
! static
! void __full_eh_context_dtor (void *block)
! {
!   if (block)
!     free (block);
! }
! 
! 
! static
! void __init_pthread_key ()
! {
!   if (pthread_key_create (&pthread_key, __full_eh_context_dtor))
!     __terminate;
! }
! 
! 
! static
! struct full_eh_context *__get_full_eh_context ()
! {
!   static pthread_once_t once = PTHREAD_ONCE_INIT;
!   struct full_eh_context *block;
! 
!   pthread_once (&once, __init_pthread_key);
! 
!   block = (struct full_eh_context*)pthread_getspecific (pthread_key);
! 
!   if (!block) {
!     block = (struct full_eh_context*) malloc (sizeof (struct full_eh_context));
!     memset (block, 0, sizeof (struct full_eh_context));
!     block->dynamic_handler_chain = top_elt;
!     block->buf[0] = &block->saved_pc;
!     block->buf[1] = &__throw;
!     if (!block)
!       __terminate ();
!     if (pthread_setspecific (pthread_key, block))
!       __terminate ();
!   }
! 
!   return block;
! }
! #endif
! 
! /* Routine to get the head of the current thread's dynamic handler chain
!    use for exception handling. */
  
  void ***
  __get_dynamic_handler_chain ()
  {
! #ifdef _PTHREADS
!   return &(__get_full_eh_context()->dynamic_handler_chain);
! #else
!   static void **dynamic_handler_chain = top_elt;
!   return &dynamic_handler_chain;
! #endif
! }
! 
! /* Routine to get the variable holding the place from which an exception
!    is being thrown. */
! 
! void**
! __get_saved_pc ()
! {
! #ifdef _PTHREADS
!   return &(__get_full_eh_context()->saved_pc);
! #else
!   static void* saved_pc;
!   return &saved_pc;
! #endif
! }
! 
! 
! /* Routine to get the C++ EH context structure. */
! 
! struct cpp_eh_context*
! __get_cpp_eh_context ()
! {
! #ifdef _PTHREADS
!   return &(__get_full_eh_context()->cpp);
! #else
!   static struct cpp_eh_context ehc;
!   return &ehc;
! #endif
  }
  
  /* This is used to throw an exception when the setjmp/longjmp codegen
***************
*** 3209,3215 ****
    /* 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
--- 3314,3320 ----
    /* 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 (! __get_cpp_eh_context()->type || (*dhc) == top_elt)
      __terminate ();
      
    /* Find the jmpbuf associated with the top element of the dynamic
***************
*** 3431,3459 ****
   return 0;
  }
  
- /* Throw stub routine.
- 
-    This is work in progress, but not completed yet.  */
- 
- void
- __throw ()
- {
-   abort ();
- }
- 
- /* This value identifies the place from which an exception is being
-    thrown.  */
- 
- void *__eh_pc;
- 
  /* See expand_builtin_throw for details.  */
  
  void **__eh_pcnthrow () {
    static void *buf[2] = {
!     &__eh_pc,
      &__throw
    };
    return buf;
  }
  
  void
--- 3536,3554 ----
   return 0;
  }
  
  /* See expand_builtin_throw for details.  */
  
  void **__eh_pcnthrow () {
+ #ifdef _PTHREADS
+   return &(__get_full_eh_context()->buf[0]);
+ #else
    static void *buf[2] = {
!     0,
      &__throw
    };
+   buf[0] = __get_saved_pc ();
    return buf;
+ #endif
  }
  
  void
*** gcc/optabs.c-orig	Thu Sep 11 17:10:37 1997
--- gcc/optabs.c	Thu Sep 11 17:13:01 1997
***************
*** 125,130 ****
--- 125,131 ----
  rtx setjmp_libfunc;
  rtx longjmp_libfunc;
  rtx get_dynamic_handler_chain_libfunc;
+ rtx get_saved_pc_libfunc;
  
  rtx eqhf2_libfunc;
  rtx nehf2_libfunc;
***************
*** 4290,4295 ****
--- 4291,4297 ----
    longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "longjmp");
  #endif
    get_dynamic_handler_chain_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_dynamic_handler_chain");
+   get_saved_pc_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_saved_pc");
  
    eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
    nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
*** gcc/cp/except.c-orig	Thu Sep 11 17:14:47 1997
--- gcc/cp/except.c	Thu Sep 11 17:15:44 1997
***************
*** 176,186 ****
--- 176,195 ----
  /* Used to cache a call to __unwind_function.  */
  static tree Unwind;
  
+ /* Same for __get_cpp_eh_context (); */
+ static tree GetCPPEHContextRef;
+ 
  /* Holds a ready to emit call to "terminate".  */
  static tree TerminateFunctionCall;
  
  static tree empty_fndecl;
  
+ /* void** */
+ static tree ptr_ptr_type_node;
+ 
+ /* void (*)() */
+ static tree PFV_type_node;
+ 
  /* ====================================================================== */
  
  
***************
*** 193,209 ****
  
     ========================================================================= */
  
- /* Holds the pc for doing "throw" */
- static tree saved_pc;
- /* Holds the type of the thing being thrown.  */
- static tree saved_throw_type;
- /* Holds the value being thrown.  */
- static tree saved_throw_value;
- /* Holds the cleanup for the value being thrown.  */
- static tree saved_cleanup;
- /* Indicates if we are in a catch clause.  */
- static tree saved_in_catch;
- 
  extern int throw_used;
  extern rtx catch_clauses;
  
--- 202,207 ----
***************
*** 239,244 ****
--- 237,243 ----
    tree catch_match_fndecl;
    tree find_first_exception_match_fndecl;
    tree unwind_fndecl;
+   tree get_cpp_eh_context_ref_fndecl;
    tree declspecs;
    tree d;
  
***************
*** 255,260 ****
--- 254,261 ----
    /* void (*pfvtype (void (*) ()))() */
    tree pfvtype = build_function_type (PFV, pfvlist);
  
+   PFV_type_node = PFV;
+ 
    set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
  					pfvtype, NOT_BUILT_IN);
    set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
***************
*** 307,355 ****
  
    TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
  
!   pop_lang_context ();
  
!   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
!   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
!   d = start_decl (d, declspecs, 0);
!   DECL_COMMON (d) = 1;
!   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
!   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
! 
!   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
!   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
!   d = start_decl (d, declspecs, 0);
!   DECL_COMMON (d) = 1;
!   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
!   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
! 
!   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
!   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
!   d = start_decl (d, declspecs, 0);
!   DECL_COMMON (d) = 1;
!   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
!   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
! 
!   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
!   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
!   d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
!   d = start_decl (d, declspecs, 0);
!   DECL_COMMON (d) = 1;
!   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
!   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
! 
!   declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
!   d = get_identifier ("__eh_in_catch");
!   d = start_decl (d, declspecs, 0);
!   DECL_COMMON (d) = 1;
!   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
!   saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
  
    /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
       be protected with __terminate.  */
    protect_cleanup_actions_with_terminate = 1;
  }
  
  /* Build a type value for use at runtime for a type that is matched
     against by the exception handling system.  */
  
--- 308,374 ----
  
    TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
  
!   /* void** */
!   ptr_ptr_type_node = build_pointer_type (ptr_type_node);
  
!   get_cpp_eh_context_ref_fndecl
!     = builtin_function ("__get_cpp_eh_context",
!                         build_function_type (ptr_ptr_type_node,
!                                              void_list_node),
!                         NOT_BUILT_IN, NULL_PTR);
!   /* Set this so that multiple calls to __get_cpp_eh_context can be CSE'd. */
!   TREE_READONLY (get_cpp_eh_context_ref_fndecl) = 1;
!   GetCPPEHContextRef = default_conversion (get_cpp_eh_context_ref_fndecl);
! 
!   pop_lang_context ();
  
    /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
       be protected with __terminate.  */
    protect_cleanup_actions_with_terminate = 1;
  }
  
+ /* The layout of the eh context structure for C++ is
+ 
+      __eh_type
+      __eh_value
+      __eh_cleanup
+      __eh_in_catch */
+ 
+ static tree
+ build_saved_throw_type ()
+ {
+   tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+   assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+   return build1 (INDIRECT_REF, ptr_type_node, t);
+ }
+ 
+ static tree
+ build_saved_throw_value ()
+ {
+   tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+   assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+   t = build_binary_op_nodefault (PLUS_EXPR, t, integer_one_node, PLUS_EXPR);
+   return build1 (INDIRECT_REF, ptr_type_node, t);
+ }
+ 
+ static tree
+ build_saved_cleanup ()
+ {
+   tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+   assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+   t = build_binary_op_nodefault (PLUS_EXPR, t, integer_two_node, PLUS_EXPR);
+   return build1 (INDIRECT_REF, PFV_type_node, t);
+ }
+ 
+ static tree
+ build_saved_in_catch ()
+ {
+   tree t = build_function_call (GetCPPEHContextRef, NULL_TREE);
+   assemble_external (TREE_OPERAND (GetCPPEHContextRef, 0));
+   t = build_binary_op_nodefault (PLUS_EXPR, t, integer_three_node, PLUS_EXPR);
+   return build1 (INDIRECT_REF, integer_type_node, t);
+ }
+ 
  /* Build a type value for use at runtime for a type that is matched
     against by the exception handling system.  */
  
***************
*** 404,413 ****
    int yes = suspend_momentary ();
  
    /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
!   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
    cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
! 		   build_modify_expr (saved_in_catch, NOP_EXPR,
! 				      build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
    expand_decl_cleanup (NULL_TREE, cleanup);
  
    resume_momentary (yes);
--- 423,437 ----
    int yes = suspend_momentary ();
  
    /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
!   tree cleanup = build_function_call (build_saved_cleanup(), NULL_TREE);
    cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
! 		   build_modify_expr
!                      (build_saved_in_catch(), NOP_EXPR,
!                       build_static_cast
!                         (boolean_type_node,
!                          build_modify_expr (build_saved_throw_type (),
!                                             NOP_EXPR,
!                                             integer_zero_node))));
    expand_decl_cleanup (NULL_TREE, cleanup);
  
    resume_momentary (yes);
***************
*** 424,429 ****
--- 448,454 ----
  expand_start_catch_block (declspecs, declarator)
       tree declspecs, declarator;
  {
+   rtx in_catch_rtx;
    rtx false_label_rtx;
    tree decl = NULL_TREE;
    tree init;
***************
*** 485,495 ****
  	  && TREE_CODE (init_type) != POINTER_TYPE)
  	init_type = build_reference_type (init_type);
  
!       exp = saved_throw_value;
        exp = tree_cons (NULL_TREE,
  		       build_eh_type_type (TREE_TYPE (decl)),
  		       tree_cons (NULL_TREE,
! 				  saved_throw_type,
  				  tree_cons (NULL_TREE, exp, NULL_TREE)));
        exp = build_function_call (CatchMatch, exp);
        call_rtx = expand_call (exp, NULL_RTX, 0);
--- 510,520 ----
  	  && TREE_CODE (init_type) != POINTER_TYPE)
  	init_type = build_reference_type (init_type);
  
!       exp = build_saved_throw_value ();
        exp = tree_cons (NULL_TREE,
  		       build_eh_type_type (TREE_TYPE (decl)),
  		       tree_cons (NULL_TREE,
! 				  build_saved_throw_type (),
  				  tree_cons (NULL_TREE, exp, NULL_TREE)));
        exp = build_function_call (CatchMatch, exp);
        call_rtx = expand_call (exp, NULL_RTX, 0);
***************
*** 521,527 ****
        /* Fall into the catch all section.  */
      }
  
!   emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
  
    /* If we are not doing setjmp/longjmp EH, because we are reordered
       out of line, we arrange to rethrow in the outer context so as to
--- 546,553 ----
        /* Fall into the catch all section.  */
      }
  
!   in_catch_rtx = expand_expr (build_saved_in_catch (), NULL_RTX, SImode, 0);
!   emit_move_insn (in_catch_rtx, const1_rtx);
  
    /* If we are not doing setjmp/longjmp EH, because we are reordered
       out of line, we arrange to rethrow in the outer context so as to
***************
*** 715,720 ****
--- 741,747 ----
    rtx top_of_loop;
    tree t;
    rtx x;
+   rtx throw_type_rtx;
  
    if (! doing_eh (0))
      return;
***************
*** 743,755 ****
    /* These two can be frontend specific.  If wanted, they can go in
       expand_throw.  */
    /* Do we have a valid object we are throwing? */
!   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
! 		 GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
    emit_jump_insn (gen_beq (gotta_call_terminate));
  
    /* search for an exception handler for the saved_pc */
    handler = do_function_call (FirstExceptionMatch,
! 			      tree_cons (NULL_TREE, saved_pc,
  					 NULL_TREE),
  			      ptr_type_node);
    assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
--- 770,785 ----
    /* These two can be frontend specific.  If wanted, they can go in
       expand_throw.  */
    /* Do we have a valid object we are throwing? */
!   throw_type_rtx = expand_expr (build_saved_throw_type (), NULL_RTX, Pmode, 0);
!   emit_cmp_insn (throw_type_rtx, const0_rtx, EQ, NULL_RTX,
! 		 GET_MODE (throw_type_rtx), 0, 0);
    emit_jump_insn (gen_beq (gotta_call_terminate));
  
    /* search for an exception handler for the saved_pc */
    handler = do_function_call (FirstExceptionMatch,
! 			      tree_cons (NULL_TREE,
!                                          make_tree (ptr_ptr_type_node,
!                                                     get_saved_pc_ref ()),
  					 NULL_TREE),
  			      ptr_type_node);
    assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
***************
*** 830,836 ****
      }
    else
  #endif
!     emit_move_insn (eh_saved_pc_rtx, next_pc);
  
    after_unwind = gen_label_rtx ();
    do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
--- 860,866 ----
      }
    else
  #endif
!     emit_move_insn (get_saved_pc_ref (), next_pc);
  
    after_unwind = gen_label_rtx ();
    do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
***************
*** 964,974 ****
        if (match_type)
  	{
  	  /* check TREE_VALUE (raises) here */
! 	  exp = saved_throw_value;
  	  exp = tree_cons (NULL_TREE,
  			   build_eh_type_type (match_type),
  			   tree_cons (NULL_TREE,
! 				      saved_throw_type,
  				      tree_cons (NULL_TREE, exp, NULL_TREE)));
  	  exp = build_function_call (CatchMatch, exp);
  	  assemble_external (TREE_OPERAND (CatchMatch, 0));
--- 994,1004 ----
        if (match_type)
  	{
  	  /* check TREE_VALUE (raises) here */
! 	  exp = build_saved_throw_value ();
  	  exp = tree_cons (NULL_TREE,
  			   build_eh_type_type (match_type),
  			   tree_cons (NULL_TREE,
! 				      build_saved_throw_type (),
  				      tree_cons (NULL_TREE, exp, NULL_TREE)));
  	  exp = build_function_call (CatchMatch, exp);
  	  assemble_external (TREE_OPERAND (CatchMatch, 0));
***************
*** 1144,1150 ****
  
         	  /* Build __tcf_ function. */
  	  cleanup = start_anon_func ();
! 	  object = build_delete (TREE_TYPE (exp), saved_throw_value, 
  				 integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
  	  expand_expr (object, const0_rtx, VOIDmode, 0);
  	  end_anon_func ();
--- 1174,1180 ----
  
         	  /* Build __tcf_ function. */
  	  cleanup = start_anon_func ();
! 	  object = build_delete (TREE_TYPE (exp), build_saved_throw_value (), 
  				 integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
  	  expand_expr (object, const0_rtx, VOIDmode, 0);
  	  end_anon_func ();
***************
*** 1155,1169 ****
        if (cleanup == empty_fndecl)
  	assemble_external (empty_fndecl);
  	
!       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
        expand_expr (e, const0_rtx, VOIDmode, 0);
  
!       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
        e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
        expand_expr (e, const0_rtx, VOIDmode, 0);
  
        cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
!       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
        expand_expr (cleanup, const0_rtx, VOIDmode, 0);
      }
    else
--- 1185,1199 ----
        if (cleanup == empty_fndecl)
  	assemble_external (empty_fndecl);
  	
!       e = build_modify_expr (build_saved_throw_type (), NOP_EXPR, throw_type);
        expand_expr (e, const0_rtx, VOIDmode, 0);
  
!       e = build_modify_expr (build_saved_throw_value (), NOP_EXPR, exp);
        e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
        expand_expr (e, const0_rtx, VOIDmode, 0);
  
        cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
!       cleanup = build_modify_expr (build_saved_cleanup(), NOP_EXPR, cleanup);
        expand_expr (cleanup, const0_rtx, VOIDmode, 0);
      }
    else
*** gcc/cp/exception.cc-orig	Thu Sep 11 17:14:51 1997
--- gcc/cp/exception.cc	Thu Sep 11 17:15:01 1997
***************
*** 91,102 ****
    throw bad_exception ();
  }
  
  bool
  uncaught_exception ()
  {
!   extern void *__eh_type;
!   extern bool __eh_in_catch;
!   return __eh_type && ! __eh_in_catch;
  }
  
  const char * exception::
--- 91,112 ----
    throw bad_exception ();
  }
  
+ // Must match definition in libgcc2.c.
+ struct cpp_eh_context
+ {
+   void *type;
+   void *value;
+   void  (*cleanup) ();
+   int   in_catch;
+ };
+ 
+ extern "C" { void** __get_cpp_eh_context (); }
+ 
  bool
  uncaught_exception ()
  {
!   cpp_eh_context* ehc = (cpp_eh_context*) __get_cpp_eh_context ();
!   return ehc->type && ! ehc->in_catch;
  }
  
  const char * exception::



More information about the Gcc mailing list