From 154bba13a4a3d494a12622c489ba9d7bd1f76a8b Mon Sep 17 00:00:00 2001
From: Teemu Torma <tot@trema.com>
Date: Fri, 12 Dec 1997 04:53:20 +0000
Subject: [PATCH] [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
---
 gcc/ChangeLog             |  81 +++++++++++++
 gcc/config/pa/pa-hpux10.h |  11 ++
 gcc/config/pa/pa.h        |   7 +-
 gcc/config/pa/t-pa        |   6 +
 gcc/config/sparc/sol2.h   |   9 +-
 gcc/config/sparc/t-sol2   |   7 ++
 gcc/cp/ChangeLog          |  14 +++
 gcc/cp/cp-tree.h          |   2 +-
 gcc/cp/decl.c             |   5 +
 gcc/cp/except.c           |  20 +---
 gcc/cp/exception.cc       |  15 ++-
 gcc/except.c              | 233 +++++++++++++++++++++++++++-----------
 gcc/except.h              |  21 +++-
 gcc/frame.c               |  27 ++++-
 gcc/function.h            |  24 +++-
 gcc/integrate.c           |   6 +
 gcc/libgcc2.c             | 206 ++++++++++++++++++++++++++++-----
 gcc/rtl.c                 |   2 +-
 gcc/rtl.h                 |   2 +-
 gcc/toplev.c              |   3 +
 20 files changed, 567 insertions(+), 134 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0bb0666e46a3..8d36284cf57c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/pa/pa-hpux10.h b/gcc/config/pa/pa-hpux10.h
index 9a2af5d578ca..0cd59127f682 100644
--- a/gcc/config/pa/pa-hpux10.h
+++ b/gcc/config/pa/pa-hpux10.h
@@ -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
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index c286fb9fa047..a127c84673d6 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -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 */
diff --git a/gcc/config/pa/t-pa b/gcc/config/pa/t-pa
index a359918a1259..b6dcec1212ea 100644
--- a/gcc/config/pa/t-pa
+++ b/gcc/config/pa/t-pa
@@ -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
diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h
index 5891222a0ce4..76cade44d9e0 100644
--- a/gcc/config/sparc/sol2.h
+++ b/gcc/config/sparc/sol2.h
@@ -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"
diff --git a/gcc/config/sparc/t-sol2 b/gcc/config/sparc/t-sol2
index d41254adb442..309aedfd9f9b 100644
--- a/gcc/config/sparc/t-sol2
+++ b/gcc/config/sparc/t-sol2
@@ -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) \
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 88732201b200..d2070090997d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e1653020194c..48740a5e3cb0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7ece1d33d38d..fd753d8ad79d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 3d62c7718452..0fa5c2425a8f 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -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));
diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc
index aa5a46e2b266..399d2c60dbcc 100644
--- a/gcc/cp/exception.cc
+++ b/gcc/cp/exception.cc
@@ -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;
 
diff --git a/gcc/except.c b/gcc/except.c
index a39d8e5544ce..11c3be87fc57 100644
--- a/gcc/except.c
+++ b/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.  */
-
-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.  */
+/* The EH context.  Nonzero if the function has already
+   fetched a pointer to the EH context  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
diff --git a/gcc/except.h b/gcc/except.h
index 46b1f47879e2..abfeb478ea6c 100644
--- a/gcc/except.h
+++ b/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));
diff --git a/gcc/frame.c b/gcc/frame.c
index 747fb9f1c40b..296e6a9456d1 100644
--- a/gcc/frame.c
+++ b/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 ();
 }
 
diff --git a/gcc/function.h b/gcc/function.h
index f54622fa71d1..a0a37467ab59 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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
diff --git a/gcc/integrate.c b/gcc/integrate.c
index 2b2c8560918c..f69adb11485f 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -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
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index ad51863e9120..1ad63013a150 100644
--- a/gcc/libgcc2.c
+++ b/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)
diff --git a/gcc/rtl.c b/gcc/rtl.c
index dde2a8396a5e..69e517143db8 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -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 *));
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 667cab72c5ba..62b134276874 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 17318e25c44c..9cbd513fca2f 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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 ();
-- 
GitLab