Make m_throw a classic "cold" function rather than a static inline function.

Since the function shall be rarely called, there is no point in inlining/duplicating it
in several units.
This commit is contained in:
Patrick Pelissier committed 2023-04-16 19:26:15 +02:00
1 parent 7279011f0a
commit 5158059ec4
1 file changed
+51 -51
+51 -51
View File
@@ -266,11 +266,6 @@ typedef intptr_t m_try_jmp_buf[5];
#define M_CATCH_B(name, error_code) \
else if (m_catch( M_C(m_try_buf_, name), (error_code), &name))
// Macro to add once in one source file to define theses global:
#define M_TRY_DEF_ONCE_B() \
M_THREAD_ATTR struct m_try_s *m_global_error_list; \
M_THREAD_ATTR struct m_exception_s m_global_exception;
// Define the operator to define nested functions (GCC) or blocks (CLANG)
#if M_USE_TRY_MECHANISM == 2
# define M_TRY_FUNC_OPERATOR ^
@@ -309,10 +304,6 @@ typedef struct m_try_s {
m_throw( &(const struct m_exception_s) { error_code, __LINE__, M_NARGS(__VA_ARGS__), __FILE__, \
{ __VA_ARGS__ } } )
// The global thread attribute variables.
extern M_THREAD_ATTR struct m_try_s *m_global_error_list;
extern M_THREAD_ATTR struct m_exception_s m_global_exception;
// Copy an exception to another.
static inline void
m_exception_set(struct m_exception_s *out, const struct m_exception_s *in)
@@ -322,50 +313,47 @@ m_exception_set(struct m_exception_s *out, const struct m_exception_s *in)
}
}
// Initialize the state to a TRY state.
static inline void
m_try_init(m_try_t state)
{
state->kind = M_STATE_TRY;
state->next = m_global_error_list;
m_global_error_list = state;
// setjmp needs to be done in the MACRO.
}
#define m_try_init(s) \
M_LIKELY ((m_try_init(s), m_try_setjmp(((s)->data.buf)) != 1))
// The global thread attribute variables and functions.
extern M_THREAD_ATTR struct m_try_s *m_global_error_list;
extern M_THREAD_ATTR struct m_exception_s m_global_exception;
extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_exception_s *exception);
// Throw the given exception
// This function should be rarely called.
static inline M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void
m_throw(const struct m_exception_s *exception)
{
// Analyze the error list to see what has been registered
struct m_try_s *e = m_global_error_list;
while (e != NULL) {
// A CLEAR operator has been registered
// Call it
if (e->kind == M_STATE_CLEAR_CB) {
e->data.clear.func(e->data.clear.data);
}
else {
// A JUMP command has been registered.
// Either due to the M_TRY block
// or because of the jump to the CLEAR operator of the object to clear.
M_ASSERT(e->kind == M_STATE_TRY || e->kind == M_STATE_CLEAR_JMPBUF);
// If the exception is already m_global_exception, it won't be copied
m_exception_set(&m_global_exception, exception);
e->kind = M_STATE_EXCEPTION_IN_PROGRESS;
m_global_error_list = e;
m_try_longjmp(e->data.buf, 1);
}
// Next stack frame
e = e->next;
// Macro to add once in one source file to define theses global:
#define M_TRY_DEF_ONCE_B() \
M_THREAD_ATTR struct m_try_s *m_global_error_list; \
M_THREAD_ATTR struct m_exception_s m_global_exception; \
\
/* Throw the given exception \
This function should be rarely called. */ \
M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void \
m_throw(const struct m_exception_s *exception) \
{ \
/* Analyze the error list to see what has been registered */ \
struct m_try_s *e = m_global_error_list; \
while (e != NULL) { \
/* A CLEAR operator has been registered: call it */ \
if (e->kind == M_STATE_CLEAR_CB) { \
e->data.clear.func(e->data.clear.data); \
} \
else { \
/* A JUMP command has been registered. \
* Either due to the M_TRY block or \
* because of the jump to the CLEAR operator of the object to clear. */ \
M_ASSERT(e->kind == M_STATE_TRY || e->kind == M_STATE_CLEAR_JMPBUF); \
/* If the exception is already m_global_exception, it won't be copied */ \
m_exception_set(&m_global_exception, exception); \
e->kind = M_STATE_EXCEPTION_IN_PROGRESS; \
m_global_error_list = e; \
m_try_longjmp(e->data.buf, 1); \
} \
/* Next stack frame */ \
e = e->next; \
} \
/* No exception found. \
Display the information and halt program . */ \
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not catched. Program aborted.\n", \
exception->error_code, exception->filename, exception->line); \
}
// No exception found.
// Display the information.
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not catched. Program aborted.\n",
exception->error_code, exception->filename, exception->line);
}
// Rethrow the error
static inline void
@@ -393,6 +381,18 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
return true;
}
// Initialize the state to a TRY state.
static inline void
m_try_init(m_try_t state)
{
state->kind = M_STATE_TRY;
state->next = m_global_error_list;
m_global_error_list = state;
// setjmp needs to be done in the MACRO.
}
#define m_try_init(s) \
M_LIKELY ((m_try_init(s), m_try_setjmp(((s)->data.buf)) != 1))
// Disable the current TRY block.
static inline void
m_try_clear(m_try_t state)