This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Implementing Exception Propagation (N2179)


Hi once more,

So I've implemented this as I said in my last mail: by splitting out the actual exception object and adding reference counting to that. Attached is a patch for this. It should be applied to the trunk. It's built against a tree that's about a week old.

GCC passes the test suite with this patch, except for a few tests. I've yet to run the test suite for the unmodified version to have a baseline to compare to, but I think none of the failures - except obviously the libstdc++ abi_check failure - have anything to do with my patch.

I've not written any tests yet, or even tried exception_ptr out. But normal throwing works.

This makes the questions I can't answer myself all the more pressing:

1) I've broken the C++ Base ABI. I believe that this ABI is not capable of supporting exception_ptr, and that breaking it is unavoidable. However, it seems that I should propose my changes to the base ABI group instead of just changing the GCC code. Who should I contact? Should I just send a mail to the base ABI group?

2) What should I change the exception class to? I may get an answer to this as a result of #1, but then, maybe not.

3) Should I change the G++ ABI namespace? It's currently __cxxabiv1. Should I change it to __cxxabiv2? It seems appropriate. And it would turn the crashes I saw when I accidentally linked against the old libstdc++ into load time failures.


Anyway, have fun trying out the patch. It contains an implementation of exception_ptr and nested_exception.


Sebastian
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	(revision 135411)
+++ gcc/cp/except.c	(working copy)
@@ -1,6 +1,7 @@
 /* Handle exceptional things in C++.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2007  Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann <tiemann@cygnus.com>
    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
    initial re-implementation courtesy Tad Hunt.
@@ -707,14 +708,23 @@
 	 expression first.  Since there could be temps in the
 	 expression, we need to handle that, too.  We also expand
 	 the call to __cxa_allocate_exception first (which doesn't
-	 matter, since it can't throw).  */
+	 matter, since it can't throw).
 
+         Also, note the __cxa_allocate_exception doesn't return a
+         pointer to the target object, but to the unwind wrapper.
+         Dereference once to get the target object.  */
+
       /* Allocate the space for the exception.  */
       allocate_expr = do_allocate_exception (temp_type);
       allocate_expr = get_target_expr (allocate_expr);
       ptr = TARGET_EXPR_SLOT (allocate_expr);
-      object = build_nop (build_pointer_type (temp_type), ptr);
+      /* That's a double pointer. */
+      tmp = build_pointer_type (temp_type);
+      tmp = build_pointer_type (tmp);
+      object = build_nop (tmp, ptr);
+      /* Dereference it twice to get the object. */
       object = cp_build_indirect_ref (object, NULL, tf_warning_or_error);
+      object = cp_build_indirect_ref (object, NULL, tf_warning_or_error);
 
       elided = (TREE_CODE (exp) == TARGET_EXPR);
 
Index: libstdc++-v3/libsupc++/eh_type.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_type.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_type.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Exception handling routines for catching.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -43,7 +43,7 @@
   __cxa_eh_globals *globals = __cxa_get_globals ();
   __cxa_exception *header = globals->caughtExceptions;
   if (header)
-    return header->exceptionType;
+    return __get_exception_info_from_header(header)->exceptionType;
   else
     return 0;
 }
Index: libstdc++-v3/libsupc++/Makefile.in
===================================================================
--- libstdc++-v3/libsupc++/Makefile.in	(revision 135411)
+++ libstdc++-v3/libsupc++/Makefile.in	(working copy)
@@ -79,7 +79,7 @@
 	bad_cast.cc bad_typeid.cc class_type_info.cc del_op.cc \
 	del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc eh_alloc.cc \
 	eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
-	eh_exception.cc eh_globals.cc eh_personality.cc \
+	eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
 	eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
 	eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
 	fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -91,7 +91,7 @@
 	bad_typeid.lo class_type_info.lo del_op.lo del_opnt.lo \
 	del_opv.lo del_opvnt.lo dyncast.lo eh_alloc.lo eh_arm.lo \
 	eh_aux_runtime.lo eh_call.lo eh_catch.lo eh_exception.lo \
-	eh_globals.lo eh_personality.lo eh_term_handler.lo \
+	eh_globals.lo eh_personality.lo eh_ptr.lo eh_term_handler.lo \
 	eh_terminate.lo eh_throw.lo eh_type.lo eh_unex_handler.lo \
 	enum_type_info.lo function_type_info.lo \
 	fundamental_type_info.lo guard.lo new_handler.lo new_op.lo \
@@ -107,7 +107,7 @@
 	atexit_arm.cc bad_cast.cc bad_typeid.cc class_type_info.cc \
 	del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc dyncast.cc \
 	eh_alloc.cc eh_arm.cc eh_aux_runtime.cc eh_call.cc eh_catch.cc \
-	eh_exception.cc eh_globals.cc eh_personality.cc \
+	eh_exception.cc eh_globals.cc eh_personality.cc eh_ptr.cc \
 	eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \
 	eh_unex_handler.cc enum_type_info.cc function_type_info.cc \
 	fundamental_type_info.cc guard.cc new_handler.cc new_op.cc \
@@ -263,13 +263,9 @@
 VERSION = @VERSION@
 WARN_FLAGS = @WARN_FLAGS@
 WERROR = @WERROR@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_AS = @ac_ct_AS@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-ac_ct_RANLIB = @ac_ct_RANLIB@
-ac_ct_STRIP = @ac_ct_STRIP@
 am__leading_dot = @am__leading_dot@
 am__tar = @am__tar@
 am__untar = @am__untar@
@@ -282,6 +278,9 @@
 build_vendor = @build_vendor@
 check_msgfmt = @check_msgfmt@
 datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
@@ -301,21 +300,25 @@
 host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
+htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
 localstatedir = @localstatedir@
 lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 multi_basedir = @multi_basedir@
 oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
 port_specific_symbol_files = @port_specific_symbol_files@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
+psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
@@ -378,6 +381,7 @@
 	eh_exception.cc \
 	eh_globals.cc \
 	eh_personality.cc \
+	eh_ptr.cc \
 	eh_term_handler.cc \
 	eh_terminate.cc \
 	eh_throw.cc \
Index: libstdc++-v3/libsupc++/eh_alloc.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_alloc.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_alloc.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Allocate exception objects.
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008
 // Free Software Foundation, Inc.
 //
 // This file is part of GCC.
@@ -39,7 +39,6 @@
 #include <climits>
 #include <exception>
 #include "unwind-cxx.h"
-#include <ext/concurrence.h>
 
 #if _GLIBCXX_HOSTED
 using std::free;
@@ -58,6 +57,8 @@
 // ??? How to control these parameters.
 
 // Guess from the size of basic types how large a buffer is reasonable.
+// TODO: The comment below is out of date. Adjust it and maybe change the
+// emergency buffer sizes.
 // Note that the basic c++ exception header has 13 pointers and 2 ints,
 // so on a system with PSImode pointers we're talking about 56 bytes
 // just for overhead.
@@ -95,13 +96,12 @@
   __gnu_cxx::__mutex emergency_mutex;
 }
 
-extern "C" void *
-__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
+static void *
+__gxx_eh_allocate(std::size_t bytes) throw()
 {
   void *ret;
 
-  thrown_size += sizeof (__cxa_exception);
-  ret = malloc (thrown_size);
+  ret = malloc (bytes);
 
   if (! ret)
     {
@@ -110,7 +110,7 @@
       bitmask_type used = emergency_used;
       unsigned int which = 0;
 
-      if (thrown_size > EMERGENCY_OBJ_SIZE)
+      if (bytes > EMERGENCY_OBJ_SIZE)
 	goto failed;
       while (used & 1)
 	{
@@ -128,20 +128,11 @@
 	std::terminate ();
     }
 
-  // We have an uncaught exception as soon as we allocate memory.  This
-  // yields uncaught_exception() true during the copy-constructor that
-  // initializes the exception object.  See Issue 475.
-  __cxa_eh_globals *globals = __cxa_get_globals ();
-  globals->uncaughtExceptions += 1;
-
-  memset (ret, 0, sizeof (__cxa_exception));
-
-  return (void *)((char *)ret + sizeof (__cxa_exception));
+    return ret;
 }
 
-
-extern "C" void
-__cxxabiv1::__cxa_free_exception(void *vptr) throw()
+static void
+__gxx_eh_free(void *vptr) throw()
 {
   char *base = (char *) emergency_buffer;
   char *ptr = (char *) vptr;
@@ -155,5 +146,67 @@
       emergency_used &= ~((bitmask_type)1 << which);
     }
   else
-    free (ptr - sizeof (__cxa_exception));
+    free (ptr);
 }
+
+extern "C" void *
+__cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
+{
+  __cxa_exception_info *info = __cxa_allocate_exception_object (thrown_size);
+  return __cxa_allocate_exception_wrapper (info);
+}
+
+extern "C" __cxa_exception_info *
+__cxxabiv1::__cxa_allocate_exception_object(std::size_t thrown_size) throw()
+{
+  void *obj = __gxx_eh_allocate (sizeof(__cxa_exception_info) + thrown_size);
+  memset (obj, 0, sizeof (__cxa_exception_info));
+  return static_cast<__cxa_exception_info *>(obj);
+}
+
+extern "C" __cxa_exception *
+__cxxabiv1::__cxa_allocate_exception_wrapper(__cxa_exception_info *obj) throw()
+{
+  void *mem = __gxx_eh_allocate (sizeof (__cxa_exception));
+  memset (mem, 0, sizeof (__cxa_exception));
+  __cxa_exception *header = static_cast<__cxa_exception*>(mem);
+  // exceptionObject points at the exception, not the info header
+  header->exceptionObject = obj + 1;
+
+  {
+    __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+    ++obj->referenceCount;
+  }
+
+  // We have an uncaught exception as soon as we allocate memory.  This
+  // yields uncaught_exception() true during the copy-constructor that
+  // initializes the exception object.  See Issue 475.
+  __cxa_eh_globals *globals = __cxa_get_globals ();
+  globals->uncaughtExceptions += 1;
+
+  return header;
+}
+
+extern "C" void
+__cxxabiv1::__cxa_free_exception(void *vptr) throw()
+{
+  __cxa_exception *header = static_cast<__cxa_exception*>(vptr);
+  __cxa_exception_info *info = __get_exception_info_from_header (header);
+  bool destroy = false;
+  {
+    __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+    if (--info->referenceCount == 0)
+      destroy = true;
+  }
+  if (destroy)
+    __cxa_free_exception_object (info);
+  __gxx_eh_free (vptr);
+}
+
+extern "C" void
+__cxxabiv1::__cxa_free_exception_object(__cxa_exception_info *obj) throw()
+{
+  if (obj->exceptionDestructor)
+    obj->exceptionDestructor (obj + 1);
+  __gxx_eh_free (obj);
+}
Index: libstdc++-v3/libsupc++/unwind-cxx.h
===================================================================
--- libstdc++-v3/libsupc++/unwind-cxx.h	(revision 135411)
+++ libstdc++-v3/libsupc++/unwind-cxx.h	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Exception handling and frame unwind runtime interface routines.
-// Copyright (C) 2001 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2008 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -39,22 +39,36 @@
 #include <exception>
 #include <cstddef>
 #include "unwind.h"
+#include <ext/concurrence.h>
 
 #pragma GCC visibility push(default)
 
 namespace __cxxabiv1
 {
 
-// A C++ exception object consists of a header, which is a wrapper around
-// an unwind object header with additional C++ specific information,
-// followed by the exception object itself.
+// A C++ exception object consists of a C++-specific extension of an unwind
+// object header, which contains a pointer to the actual exception and some
+// additional information needed for bookkeeping.
 
-struct __cxa_exception
-{ 
+// This is the header for the actual object.
+struct __cxa_exception_info
+{
+  // How many exception_ptrs and __cxa_exceptions are referring to this
+  // exception.
+  int referenceCount;
+
   // Manage the exception object itself.
   std::type_info *exceptionType;
-  void (*exceptionDestructor)(void *); 
+  void (*exceptionDestructor)(void *);
+};
 
+// This is the extension of the unwind header.
+struct __cxa_exception
+{
+  // Pointer to the actual object. Also, before this address, the info header.
+  // Must be first!
+  void *exceptionObject;
+
   // The C++ standard has entertaining rules wrt calling set_terminate
   // and set_unexpected in the middle of the exception cleanup process.
   std::unexpected_handler unexpectedHandler;
@@ -97,7 +111,12 @@
 #endif
 };
 
+// This mutex protects the reference counts of all exception objects.
+// Doing it per-object would be unreasonable overhead.
+// Atomics would be better, but I'm not sure about their availability.
+extern __gnu_cxx::__mutex __cxa_eh_refcount_mutex;
 
+
 // The __cxa_eh_globals for the current thread can be obtained by using
 // either of the following functions.  The "fast" version assumes at least
 // one prior call of __cxa_get_globals has been made from the current
@@ -105,14 +124,30 @@
 extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
 extern "C" __cxa_eh_globals *__cxa_get_globals_fast () throw();
 
-// Allocate memory for the exception plus the thown object.
+// Allocate memory for the wrapper plus the thrown object. Returns the
+// unwind header wrapper. (Return type is void* for simplicity in the tree
+// declaration.)
 extern "C" void *__cxa_allocate_exception(std::size_t thrown_size) throw();
 
-// Free the space allocated for the exception.
-extern "C" void __cxa_free_exception(void *thrown_exception) throw();
+// Allocate memory for the thrown object and its info header. Returns a pointer
+// to the info header; the object is placed immediately afterwards.
+extern "C" __cxa_exception_info *
+__cxa_allocate_exception_object(std::size_t thrown_size) throw();
 
+// Allocate memory for the wrapper only, wrapping the given object. Returns
+// the unwind header wrapper.
+extern "C" __cxa_exception *
+__cxa_allocate_exception_wrapper(__cxa_exception_info *obj) throw();
+
+// Free the unwind wrapper, and the exception itself if it's no longer
+// referenced.
+extern "C" void __cxa_free_exception(void *unwind_wrapper) throw();
+
+// Free the exception object, unconditionally.
+extern "C" void __cxa_free_exception_object(__cxa_exception_info *obj) throw();
+
 // Throw the exception.
-extern "C" void __cxa_throw (void *thrown_exception,
+extern "C" void __cxa_throw (void *unwind_wrapper,
 			     std::type_info *tinfo,
 			     void (*dest) (void *))
      __attribute__((noreturn));
@@ -159,11 +194,10 @@
 
 // These are explicitly GNU C++ specific.
 
-// Acquire the C++ exception header from the C++ object.
-static inline __cxa_exception *
-__get_exception_header_from_obj (void *ptr)
+static inline __cxa_exception_info *
+__get_exception_info_from_header (__cxa_exception *hdr)
 {
-  return reinterpret_cast<__cxa_exception *>(ptr) - 1;
+  return reinterpret_cast<__cxa_exception_info *>(hdr->exceptionObject) - 1;
 }
 
 // Acquire the C++ exception header from the generic exception header.
@@ -184,7 +218,7 @@
 	 && c[3] == 'C'
 	 && c[4] == 'C'
 	 && c[5] == '+'
-	 && c[6] == '+'
+	 && c[6] == '1'
 	 && c[7] == '\0';
 }
 
@@ -197,7 +231,7 @@
   c[3] = 'C';
   c[4] = 'C';
   c[5] = '+';
-  c[6] = '+';
+  c[6] = '1';
   c[7] = '\0';
 }
 
@@ -207,7 +241,7 @@
   return (void*)eo->barrier_cache.bitpattern[0];
 }
 #else // !__ARM_EABI_UNWINDER__
-// This is the exception class we report -- "GNUCC++\0".
+// This is the exception class we report -- "GNUCC+1\0".
 const _Unwind_Exception_Class __gxx_exception_class
 = ((((((((_Unwind_Exception_Class) 'G' 
 	 << 8 | (_Unwind_Exception_Class) 'N')
@@ -215,7 +249,7 @@
        << 8 | (_Unwind_Exception_Class) 'C')
       << 8 | (_Unwind_Exception_Class) 'C')
      << 8 | (_Unwind_Exception_Class) '+')
-    << 8 | (_Unwind_Exception_Class) '+')
+    << 8 | (_Unwind_Exception_Class) '1')
    << 8 | (_Unwind_Exception_Class) '\0');
 
 static inline bool
Index: libstdc++-v3/libsupc++/exception
===================================================================
--- libstdc++-v3/libsupc++/exception	(revision 135411)
+++ libstdc++-v3/libsupc++/exception	(working copy)
@@ -1,7 +1,7 @@
 // Exception Handling support header for -*- C++ -*-
 
 // Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-// 2004, 2005, 2006, 2007
+// 2004, 2005, 2006, 2007, 2008
 // Free Software Foundation
 //
 // This file is part of GCC.
@@ -79,6 +79,88 @@
     virtual const char* what() const throw();
   };
 
+  /**
+   * @brief An opaque pointer to an arbitrary exception.
+   */
+  class exception_ptr
+  {
+    void* _M_exception_object;
+
+    explicit exception_ptr(void* e)
+      : _M_exception_object(e)
+    {
+      addref();
+    }
+
+    void addref() throw();
+    void release() throw();
+
+	void *get() const { return _M_exception_object; }
+
+    friend exception_ptr current_exception() throw();
+    friend void rethrow_exception(exception_ptr);
+
+  public:
+    exception_ptr()
+      : _M_exception_object(0)
+    {
+    }
+
+    exception_ptr(const exception_ptr& o)
+      : _M_exception_object(o._M_exception_object)
+    {
+      addref();
+    }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    exception_ptr(exception_ptr&& o)
+      : _M_exception_object(o._M_exception_object)
+    {
+      o._M_exception_object = 0;
+    }
+#endif
+
+    exception_ptr& operator=(const exception_ptr& o)
+    {
+      exception_ptr(o).swap(*this);
+      return *this;
+    }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    exception_ptr& operator=(exception_ptr&& o)
+    {
+      exception_ptr(o).swap(*this);
+      return *this;
+    }
+#endif
+
+    ~exception_ptr()
+    {
+      release();
+    }
+
+    void swap(exception_ptr &o)
+    {
+      void *tmp = _M_exception_object;
+      _M_exception_object = o._M_exception_object;
+      o._M_exception_object = tmp;
+    }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    void swap(exception_ptr &&o)
+    {
+      void *tmp = _M_exception_object;
+      _M_exception_object = o._M_exception_object;
+      o._M_exception_object = tmp;
+    }
+#endif
+
+    friend bool operator ==(const exception_ptr& lhs, const exception_ptr& rhs)
+    {
+      return lhs._M_exception_object == rhs._M_exception_object;
+    }
+  };
+
   /// If you write a replacement %terminate handler, it must be of this type.
   typedef void (*terminate_handler) ();
 
@@ -110,6 +192,50 @@
    *  result in a call of @c terminate() (15.5.1)."
    */
   bool uncaught_exception() throw();
+
+  /** Obtain an %exception_ptr to the currently handled exception. If there
+   *  is none, or the currently handled exception is foreign, return the null
+   *  value.
+   */
+  exception_ptr current_exception() throw();
+
+  /// Throw the object pointed to by the %exception_ptr.
+  void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__));
+
+  /// Obtain an %exception_ptr pointing to a copy of the supplied object.
+  template <class E>
+  exception_ptr copy_exception(E e) throw();
+
+  /**
+   * @brief A mixin class for holding a nested exception.
+   *
+   * This class allows wrapping arbitrary exceptions in other exceptions.
+   */
+  class nested_exception
+  {
+    exception_ptr _M_inner;
+
+  public:
+    nested_exception() throw();
+    // Lacking =default, don't write explicit copy functions yet.
+    virtual ~nested_exception() throw();
+
+    void rethrow_nested() const __attribute__ ((noreturn));
+    exception_ptr nested_ptr() const { return _M_inner; }
+  };
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+  template <class T>
+  void throw_with_nested(T&& t) __attribute__ ((noreturn));
+#else
+  // Fall back to a normal reference.
+  template <class T>
+  void throw_with_nested(const T &t) __attribute ((noreturn));
+#endif
+
+  template <class E>
+  void throw_if_nested(const E& e);
+
 } // namespace std
 
 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
@@ -130,6 +256,8 @@
   
 } // extern "C++"
 
+#include <exception_inlines.h>
+
 #pragma GCC visibility pop
 
 #endif
Index: libstdc++-v3/libsupc++/eh_throw.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_throw.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_throw.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Exception handling routines for throwing.
-// Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -38,6 +38,10 @@
 {
   __cxa_exception *header = __get_exception_header_from_ue (exc);
 
+  // TODO: The below comment was never really correct. The native handler uses
+  // _Unwind_DeleteException too. Also, relying on header->terminateHandler
+  // being valid is risky if we've already established that there's a problem.
+
   // If we haven't been caught by a foreign handler, then this is
   // some sort of unwind error.  In that case just die immediately.
   // _Unwind_DeleteException in the HP-UX IA64 libunwind library
@@ -46,20 +50,18 @@
   if (code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
     __terminate (header->terminateHandler);
 
-  if (header->exceptionDestructor)
-    header->exceptionDestructor (header + 1);
-
-  __cxa_free_exception (header + 1);
+  __cxa_free_exception (header);
 }
 
 
 extern "C" void
-__cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo, 
+__cxxabiv1::__cxa_throw (void *hdr, std::type_info *tinfo, 
 			 void (*dest) (void *))
 {
-  __cxa_exception *header = __get_exception_header_from_obj (obj);
-  header->exceptionType = tinfo;
-  header->exceptionDestructor = dest;
+  __cxa_exception *header = static_cast<__cxa_exception *>(hdr);
+  __cxa_exception_info *info = __get_exception_info_from_header (header);
+  info->exceptionType = tinfo;
+  info->exceptionDestructor = dest;
   header->unexpectedHandler = __unexpected_handler;
   header->terminateHandler = __terminate_handler;
   __GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class);
@@ -91,8 +93,15 @@
       if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
 	globals->caughtExceptions = 0;
       else
-	header->handlerCount = -header->handlerCount;
+        {
+          header->handlerCount = -header->handlerCount;
 
+          // throw; is a throw-expression too, so terminate and unexpected
+          // should have updated handlers. cf. [18.7.3.3]/2 and [18.7.2.4]/2
+          header->unexpectedHandler = __unexpected_handler;
+          header->terminateHandler = __terminate_handler;
+        }
+
 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
       _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
 #else
@@ -108,3 +117,33 @@
     }
   std::terminate ();
 }
+
+void
+std::rethrow_exception (exception_ptr p)
+{
+  if (!p.get())
+    std::terminate ();
+
+  __cxa_exception_info *info = static_cast<__cxa_exception_info *>(p.get()) - 1;
+
+  __cxa_exception *header = __cxa_allocate_exception_wrapper (info);
+
+  header->unexpectedHandler = __unexpected_handler;
+  header->terminateHandler = __terminate_handler;
+  __GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class);
+  header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
+
+#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
+  _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader);
+#else
+#if defined(_LIBUNWIND_STD_ABI)
+  _Unwind_RaiseException (&header->unwindHeader);
+#else
+  _Unwind_Resume_or_Rethrow (&header->unwindHeader);
+#endif
+#endif
+
+  // Some sort of unwinding error.  Note that terminate is a handler.
+  __cxa_begin_catch (&header->unwindHeader);
+  std::terminate ();
+}
Index: libstdc++-v3/libsupc++/exception_inlines.h
===================================================================
--- libstdc++-v3/libsupc++/exception_inlines.h	(revision 0)
+++ libstdc++-v3/libsupc++/exception_inlines.h	(revision 0)
@@ -0,0 +1,91 @@
+// -*- C++ -*- Inline and template implementation file for <exception>.
+//
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+/** @file exception_inlines.h
+ *  This is an internal header file, included by other library headers.
+ *  You should not attempt to use it directly.
+ */
+
+#ifndef __EXCEPTION_INLINES_H__
+#define __EXCEPTION_INLINES_H__
+
+// ??? The semantics of this in the face of rvalue and lvalue references aren't
+// quite right.
+
+namespace std
+{
+  template <class T>
+  class __with_nested_exception : public T, public nested_exception
+  {
+  public:
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+  __with_nested_exception(T&& t) : T(t) { }
+#else
+  __with_nested_exception(const T& t) : T(t) { }
+#endif
+  };
+}
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+template <class T>
+void
+std::throw_with_nested(T&& t)
+{
+  if(dynamic_cast<nested_exception&&>(t))
+    throw t;
+  else
+    throw __with_nested_exception<T>(t); 
+}
+#else
+template <class T>
+void
+std::throw_with_nested(const T& t)
+{
+  if(dynamic_cast<const nested_exception&>(t))
+    throw t;
+  else
+    throw __with_nested_exception<T>(t); 
+}
+#endif
+
+template <class E>
+std::exception_ptr std::copy_exception(E e) throw()
+{
+  try
+    {
+      throw e;
+    }
+  catch(...)
+    {
+      return current_exception ();
+    }
+}
+
+#endif
Index: libstdc++-v3/libsupc++/eh_ptr.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_ptr.cc	(revision 0)
+++ libstdc++-v3/libsupc++/eh_ptr.cc	(revision 0)
@@ -0,0 +1,87 @@
+// -*- C++ -*- Implement the members of exception_ptr.
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING.  If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+#include <bits/c++config.h>
+#include <exception>
+#include "unwind-cxx.h"
+
+using namespace __cxxabiv1;
+
+static inline __cxa_exception_info *
+__exception_info(void *obj)
+{
+	return static_cast<__cxa_exception_info *>(obj) - 1;
+}
+
+
+void
+std::exception_ptr::addref() throw()
+{
+  if (_M_exception_object)
+    {
+      __cxa_exception_info *info = __exception_info (_M_exception_object);
+      __gnu_cxx::__scoped_lock sentry(__cxa_eh_refcount_mutex);
+      ++info->referenceCount;
+    }
+}
+
+
+void
+std::exception_ptr::release() throw()
+{
+  if (_M_exception_object)
+    {
+      __cxa_exception_info *info = __exception_info (_M_exception_object);
+
+      __cxa_eh_refcount_mutex.lock ();
+      --info->referenceCount;
+      bool destroy = info->referenceCount == 0;
+      __cxa_eh_refcount_mutex.unlock ();
+
+      if (destroy)
+        __cxa_free_exception_object (info);
+    }
+}
+
+
+std::exception_ptr
+std::current_exception() throw()
+{
+  __cxa_eh_globals *globals = __cxa_get_globals ();
+  __cxa_exception *header = globals->caughtExceptions;
+
+  if (!header)
+    return std::exception_ptr();
+
+  // Since foreign exceptions can't be counted, we can't return them.
+  if (!__is_gxx_exception_class (header->unwindHeader.exception_class))
+    return std::exception_ptr();
+
+  return std::exception_ptr(header->exceptionObject);
+}
Index: libstdc++-v3/libsupc++/eh_catch.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_catch.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_catch.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Exception handling routines for catching.
-// Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2003, 2004, 2008 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -53,9 +53,7 @@
 
   // Foreign exceptions can't be stacked here.  If the exception stack is
   // empty, then fine.  Otherwise we really have no choice but to terminate.
-  // Note that this use of "header" is a lie.  It's fine so long as we only
-  // examine header->unwindHeader though.
-  if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
+  if (!__is_gxx_exception_class(exceptionObject->exception_class))
     {
       if (prev != 0)
 	std::terminate ();
@@ -103,8 +101,8 @@
   if (!header)
     return;
 
-  // A foreign exception couldn't have been stacked (see above),
-  // so by definition processing must be complete.
+  // A foreign exception couldn't have been stacked (see above) or been
+  // assigned to an exception_ptr, so by definition processing must be complete.
   if (!__is_gxx_exception_class(header->unwindHeader.exception_class))
     {
       globals->caughtExceptions = 0;
@@ -134,7 +132,6 @@
   header->handlerCount = count;
 }
 
-
 bool
 std::uncaught_exception() throw()
 {
Index: libstdc++-v3/libsupc++/eh_globals.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_globals.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_globals.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Manage the thread-local exception globals.
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008
 // Free Software Foundation, Inc.
 //
 // This file is part of GCC.
@@ -47,6 +47,8 @@
 
 using namespace __cxxabiv1;
 
+__gnu_cxx::__mutex __cxxabiv1::__cxa_eh_refcount_mutex;
+
 #if _GLIBCXX_HAVE_TLS
 
 namespace
Index: libstdc++-v3/libsupc++/eh_exception.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_exception.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_exception.cc	(working copy)
@@ -1,6 +1,6 @@
 // -*- C++ -*- std::exception implementation.
 // Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-// 2003, 2004, 2005, 2006, 2007
+// 2003, 2004, 2005, 2006, 2007, 2008
 // Free Software Foundation
 //
 // This file is part of GCC.
@@ -55,3 +55,16 @@
 {
   return "std::bad_exception";
 }
+
+std::nested_exception::nested_exception() throw()
+  : _M_inner(current_exception())
+{
+}
+
+std::nested_exception::~nested_exception() throw() { }
+
+void
+std::nested_exception::rethrow_nested() const
+{
+  rethrow_exception(_M_inner);
+}
Index: libstdc++-v3/libsupc++/eh_personality.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_personality.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_personality.cc	(working copy)
@@ -377,7 +377,7 @@
   const unsigned char *p;
   _Unwind_Ptr landing_pad, ip;
   int handler_switch_value;
-  void* thrown_ptr = ue_header + 1;
+  void* thrown_ptr;
   bool foreign_exception;
   int ip_before_insn = 0;
 
@@ -547,6 +547,12 @@
       if ((actions & _UA_FORCE_UNWIND)
 	  || foreign_exception)
 	thrown_ptr = 0;
+      else
+        {
+          // This is finally safe to do here.
+          __cxa_exception* xh = __get_exception_header_from_ue(ue_header);
+          thrown_ptr = __get_exception_info_from_header(xh) + 1;
+        }
 #else
       // During forced unwinding, match a magic exception type.
       if (actions & _UA_FORCE_UNWIND)
@@ -562,7 +568,10 @@
 	  thrown_ptr = 0;
 	}
       else
-	throw_type = xh->exceptionType;
+        {
+          throw_type = __get_exception_info_from_header(xh)->exceptionType;
+          thrown_ptr = xh->exceptionObject;
+        }
 #endif
 
       while (1)
@@ -754,13 +763,15 @@
 
       __cxa_eh_globals *globals = __cxa_get_globals_fast ();
       __cxa_exception *new_xh = globals->caughtExceptions;
-      void *new_ptr = new_xh + 1;
+      void *new_ptr = new_xh->exceptionObject;
 
       // We don't quite have enough stuff cached; re-parse the LSDA.
       parse_lsda_header (0, xh_lsda, &info);
 
       // If this new exception meets the exception spec, allow it.
-      if (check_exception_spec (&info, new_xh->exceptionType,
+      if (check_exception_spec (&info,
+                                __get_exception_info_from_header
+                                  (new_xh)->exceptionType,
 				new_ptr, xh_switch_value))
 	__throw_exception_again;
 
Index: libstdc++-v3/libsupc++/Makefile.am
===================================================================
--- libstdc++-v3/libsupc++/Makefile.am	(revision 135411)
+++ libstdc++-v3/libsupc++/Makefile.am	(working copy)
@@ -1,6 +1,6 @@
 ## Makefile for the GNU C++ Support library.
 ##
-## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
+## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
 ## Free Software Foundation, Inc.
 ##
 ## Process this file with automake to produce Makefile.in.
@@ -59,6 +59,7 @@
 	eh_exception.cc \
 	eh_globals.cc \
 	eh_personality.cc \
+	eh_ptr.cc \
 	eh_term_handler.cc \
 	eh_terminate.cc \
 	eh_throw.cc \
Index: libstdc++-v3/libsupc++/eh_call.cc
===================================================================
--- libstdc++-v3/libsupc++/eh_call.cc	(revision 135411)
+++ libstdc++-v3/libsupc++/eh_call.cc	(working copy)
@@ -1,5 +1,5 @@
 // -*- C++ -*- Helpers for calling unextected and terminate
-// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -125,7 +125,7 @@
 
       __cxa_eh_globals* globals = __cxa_get_globals_fast();
       __cxa_exception* new_xh = globals->caughtExceptions;
-      void* new_ptr = new_xh + 1;
+      void* new_ptr = new_xh->exceptionObject;
       const std::type_info* catch_type;
       int n;
       bool bad_exception_allowed = false;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]