Make SJLJ exceptions more efficient
[deliverable/binutils-gdb.git] / gdb / common / common-exceptions.h
index 54e7404f046e7a2391e22ad7cc17c84e99e21cb2..d7b25502262e671e1c965699f4072d2a330b6062 100644 (file)
@@ -23,6 +23,7 @@
 #include <setjmp.h>
 #include <new>
 #include <memory>
+#include <string>
 
 /* Reasons for calling throw_exceptions().  NOTE: all reason values
    must be different from zero.  enum value 0 is reserved for internal
@@ -123,6 +124,15 @@ struct gdb_exception
   {
   }
 
+  gdb_exception (enum return_reason r, enum errors e,
+                const char *fmt, va_list ap)
+    ATTRIBUTE_PRINTF (4, 0)
+    : reason (r),
+      error (e),
+      message (std::make_shared<std::string> (string_vprintf (fmt, ap)))
+  {
+  }
+
   /* The copy constructor exists so that we can mark it "noexcept",
      which is a good practice for any sort of exception object.  */
   gdb_exception (const gdb_exception &other) noexcept
@@ -142,6 +152,8 @@ struct gdb_exception
     return *this;
   }
 
+  gdb_exception &operator= (gdb_exception &&other) noexcept = default;
+
   /* Return the contents of the exception message, as a C string.  The
      string remains owned by the exception object.  */
   const char *what () const noexcept
@@ -164,10 +176,6 @@ extern int exceptions_state_mc_action_iter (void);
 extern int exceptions_state_mc_action_iter_1 (void);
 extern int exceptions_state_mc_catch (struct gdb_exception *, int);
 
-/* For the C++ try/catch-based TRY/CATCH mechanism.  */
-
-extern void exception_rethrow (void) ATTRIBUTE_NORETURN;
-
 /* Macro to wrap up standard try/catch behavior.
 
    The double loop lets us correctly handle code "break"ing out of the
@@ -179,24 +187,21 @@ extern void exception_rethrow (void) ATTRIBUTE_NORETURN;
 
    *INDENT-OFF*
 
-   TRY
+   TRY_SJLJ
      {
      }
-   CATCH (e, RETURN_MASK_ERROR)
+   CATCH_SJLJ (e, RETURN_MASK_ERROR)
      {
        switch (e.reason)
          {
            case RETURN_ERROR: ...
          }
      }
-   END_CATCH
+   END_CATCH_SJLJ
 
-  Note that the SJLJ version of the macros are actually named
-  TRY_SJLJ/CATCH_SJLJ in order to make it possible to call them even
-  when TRY/CATCH are mapped to C++ try/catch.  The SJLJ variants are
-  needed in some cases where gdb exceptions need to cross third-party
-  library code compiled without exceptions support (e.g.,
-  readline).  */
+   The SJLJ variants are needed in some cases where gdb exceptions
+   need to cross third-party library code compiled without exceptions
+   support (e.g., readline).  */
 
 #define TRY_SJLJ \
      { \
@@ -215,65 +220,37 @@ extern void exception_rethrow (void) ATTRIBUTE_NORETURN;
 #define END_CATCH_SJLJ                         \
   }
 
-/* We still need to wrap TRY/CATCH in C++ so that cleanups and C++
-   exceptions can coexist.
-
-   The TRY blocked is wrapped in a do/while(0) so that break/continue
-   within the block works the same as in C.
-
-   END_CATCH makes sure that even if the CATCH block doesn't want to
-   catch the exception, we stop at every frame in the unwind chain to
-   run its cleanups, which may e.g., have pointers to stack variables
-   that are going to be destroyed.
-
-   There's an outer scope around the whole TRY/END_CATCH in order to
-   cause a compilation error if you forget to add the END_CATCH at the
-   end a TRY/CATCH construct.  */
-
-#define TRY                                                            \
-  {                                                                    \
-    try                                                                        \
-      {                                                                        \
-       do                                                              \
-         {
-
-#define CATCH(EXCEPTION, MASK)                                         \
-         } while (0);                                                  \
-       }                                                               \
-    catch (struct gdb_exception ## _ ## MASK &EXCEPTION)
-
-#define END_CATCH                              \
-    catch (...)                                        \
-      {                                                \
-       exception_rethrow ();                   \
-      }                                                \
-  }
-
 /* The exception types client code may catch.  They're just shims
    around gdb_exception that add nothing but type info.  Which is used
    is selected depending on the MASK argument passed to CATCH.  */
 
-struct gdb_exception_RETURN_MASK_ALL : public gdb_exception
+struct gdb_exception_error : public gdb_exception
 {
-  explicit gdb_exception_RETURN_MASK_ALL (const gdb_exception &ex) noexcept
+  gdb_exception_error (enum errors e, const char *fmt, va_list ap)
+    ATTRIBUTE_PRINTF (3, 0)
+    : gdb_exception (RETURN_ERROR, e, fmt, ap)
+  {
+  }
+
+  explicit gdb_exception_error (const gdb_exception &ex) noexcept
     : gdb_exception (ex)
   {
+    gdb_assert (ex.reason == RETURN_ERROR);
   }
 };
 
-struct gdb_exception_RETURN_MASK_ERROR : public gdb_exception_RETURN_MASK_ALL
+struct gdb_exception_quit : public gdb_exception
 {
-  explicit gdb_exception_RETURN_MASK_ERROR (const gdb_exception &ex) noexcept
-    : gdb_exception_RETURN_MASK_ALL (ex)
+  gdb_exception_quit (const char *fmt, va_list ap)
+    ATTRIBUTE_PRINTF (2, 0)
+    : gdb_exception (RETURN_QUIT, GDB_NO_ERROR, fmt, ap)
   {
   }
-};
 
-struct gdb_exception_RETURN_MASK_QUIT : public gdb_exception_RETURN_MASK_ALL
-{
-  explicit gdb_exception_RETURN_MASK_QUIT (const gdb_exception &ex) noexcept
-    : gdb_exception_RETURN_MASK_ALL (ex)
+  explicit gdb_exception_quit (const gdb_exception &ex) noexcept
+    : gdb_exception (ex)
   {
+    gdb_assert (ex.reason == RETURN_QUIT);
   }
 };
 
@@ -284,11 +261,11 @@ struct gdb_exception_RETURN_MASK_QUIT : public gdb_exception_RETURN_MASK_ALL
    spread around the codebase.  */
 
 struct gdb_quit_bad_alloc
-  : public gdb_exception_RETURN_MASK_QUIT,
+  : public gdb_exception_quit,
     public std::bad_alloc
 {
   explicit gdb_quit_bad_alloc (const gdb_exception &ex) noexcept
-    : gdb_exception_RETURN_MASK_QUIT (ex),
+    : gdb_exception_quit (ex),
       std::bad_alloc ()
   {
   }
@@ -299,14 +276,14 @@ struct gdb_quit_bad_alloc
 /* Throw an exception (as described by "struct gdb_exception"),
    landing in the inner most containing exception handler established
    using TRY/CATCH.  */
-extern void throw_exception (struct gdb_exception exception)
+extern void throw_exception (const gdb_exception &exception)
      ATTRIBUTE_NORETURN;
 
 /* Throw an exception by executing a LONG JUMP to the inner most
    containing exception handler established using TRY_SJLJ.  Necessary
    in some cases where we need to throw GDB exceptions across
    third-party library code (e.g., readline).  */
-extern void throw_exception_sjlj (struct gdb_exception exception)
+extern void throw_exception_sjlj (const struct gdb_exception &exception)
      ATTRIBUTE_NORETURN;
 
 /* Convenience wrappers around throw_exception that throw GDB
@@ -320,7 +297,4 @@ extern void throw_error (enum errors error, const char *fmt, ...)
 extern void throw_quit (const char *fmt, ...)
      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
 
-/* A pre-defined non-exception.  */
-extern const struct gdb_exception exception_none;
-
 #endif /* COMMON_COMMON_EXCEPTIONS_H */
This page took 0.027409 seconds and 4 git commands to generate.