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) \ #define M_CATCH_B(name, error_code) \
else if (m_catch( M_C(m_try_buf_, name), (error_code), &name)) 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) // Define the operator to define nested functions (GCC) or blocks (CLANG)
#if M_USE_TRY_MECHANISM == 2 #if M_USE_TRY_MECHANISM == 2
# define M_TRY_FUNC_OPERATOR ^ # 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__, \ m_throw( &(const struct m_exception_s) { error_code, __LINE__, M_NARGS(__VA_ARGS__), __FILE__, \
{ __VA_ARGS__ } } ) { __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. // Copy an exception to another.
static inline void static inline void
m_exception_set(struct m_exception_s *out, const struct m_exception_s *in) 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. // The global thread attribute variables and functions.
static inline void extern M_THREAD_ATTR struct m_try_s *m_global_error_list;
m_try_init(m_try_t state) 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);
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))
// Throw the given exception // Macro to add once in one source file to define theses global:
// This function should be rarely called. #define M_TRY_DEF_ONCE_B() \
static inline M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void M_THREAD_ATTR struct m_try_s *m_global_error_list; \
m_throw(const struct m_exception_s *exception) M_THREAD_ATTR struct m_exception_s m_global_exception; \
{ \
// Analyze the error list to see what has been registered /* Throw the given exception \
struct m_try_s *e = m_global_error_list; This function should be rarely called. */ \
while (e != NULL) { M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void \
// A CLEAR operator has been registered m_throw(const struct m_exception_s *exception) \
// Call it { \
if (e->kind == M_STATE_CLEAR_CB) { /* Analyze the error list to see what has been registered */ \
e->data.clear.func(e->data.clear.data); struct m_try_s *e = m_global_error_list; \
} while (e != NULL) { \
else { /* A CLEAR operator has been registered: call it */ \
// A JUMP command has been registered. if (e->kind == M_STATE_CLEAR_CB) { \
// Either due to the M_TRY block e->data.clear.func(e->data.clear.data); \
// 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); else { \
// If the exception is already m_global_exception, it won't be copied /* A JUMP command has been registered. \
m_exception_set(&m_global_exception, exception); * Either due to the M_TRY block or \
e->kind = M_STATE_EXCEPTION_IN_PROGRESS; * because of the jump to the CLEAR operator of the object to clear. */ \
m_global_error_list = e; M_ASSERT(e->kind == M_STATE_TRY || e->kind == M_STATE_CLEAR_JMPBUF); \
m_try_longjmp(e->data.buf, 1); /* If the exception is already m_global_exception, it won't be copied */ \
} m_exception_set(&m_global_exception, exception); \
// Next stack frame e->kind = M_STATE_EXCEPTION_IN_PROGRESS; \
e = e->next; 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 // Rethrow the error
static inline void static inline void
@@ -393,6 +381,18 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
return true; 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. // Disable the current TRY block.
static inline void static inline void
m_try_clear(m_try_t state) m_try_clear(m_try_t state)