gtype: improve get_type fast path

The -fstack-protector-strong used in many distributions by default has a
rather drastic slowdown of the fast path in generated _get_type()
functions using G_DEFINE_* macros. The amount can vary by architecture,
GCC version, and compiler flags.

To work around this, and ensure a higher probability that our fast-path
will match what we had previously, we need to break out the slow-path
(registering the type) into a secondary function that is not a candidate
for inlining.

This ensures that the common case (type registered, return the GType id)
is the hot path and handled in the prologue of the generated assembly even
when -fstack-protector-strong is enabled.

https://bugzilla.gnome.org/show_bug.cgi?id=795180
This commit is contained in:
Christian Hergert 2018-05-04 15:41:08 -07:00 committed by Philip Withnall
parent ede5c3f8d9
commit e924f77736

View File

@ -1948,6 +1948,7 @@ static void type_name##_class_intern_init (gpointer klass) \
\ \
static void type_name##_init (TypeName *self); \ static void type_name##_init (TypeName *self); \
static void type_name##_class_init (TypeName##Class *klass); \ static void type_name##_class_init (TypeName##Class *klass); \
static GType type_name##_get_type_once (void); \
static gpointer type_name##_parent_class = NULL; \ static gpointer type_name##_parent_class = NULL; \
static gint TypeName##_private_offset; \ static gint TypeName##_private_offset; \
\ \
@ -1969,6 +1970,16 @@ type_name##_get_type (void) \
/* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */ /* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */
#define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \ #define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \
if (g_once_init_enter (&g_define_type_id__volatile)) \ if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \
GType g_define_type_id = type_name##_get_type_once (); \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
} \
return g_define_type_id__volatile; \
} /* closes type_name##_get_type() */ \
\
G_GNUC_NO_INLINE \
static GType \
type_name##_get_type_once (void) \
{ \ { \
GType g_define_type_id = \ GType g_define_type_id = \
g_type_register_static_simple (TYPE_PARENT, \ g_type_register_static_simple (TYPE_PARENT, \
@ -1982,10 +1993,8 @@ type_name##_get_type (void) \
#define _G_DEFINE_TYPE_EXTENDED_END() \ #define _G_DEFINE_TYPE_EXTENDED_END() \
/* following custom code */ \ /* following custom code */ \
} \ } \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \ return g_define_type_id; \
} \ } /* closes type_name##_get_type_once() */
return g_define_type_id__volatile; \
} /* closes type_name##_get_type() */
/* This was defined before we had G_DEFINE_TYPE_WITH_CODE_AND_PRELUDE, it's simplest /* This was defined before we had G_DEFINE_TYPE_WITH_CODE_AND_PRELUDE, it's simplest
* to keep it. * to keep it.
@ -2070,11 +2079,23 @@ type_name##_get_type (void) \
*/ */
#if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) && !(defined (__APPLE__) && defined (__ppc64__)) #if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) && !(defined (__APPLE__) && defined (__ppc64__))
#define _G_DEFINE_BOXED_TYPE_BEGIN(TypeName, type_name, copy_func, free_func) \ #define _G_DEFINE_BOXED_TYPE_BEGIN(TypeName, type_name, copy_func, free_func) \
static GType type_name##_get_type_once (void); \
\
GType \ GType \
type_name##_get_type (void) \ type_name##_get_type (void) \
{ \ { \
static volatile gsize g_define_type_id__volatile = 0; \ static volatile gsize g_define_type_id__volatile = 0; \
if (g_once_init_enter (&g_define_type_id__volatile)) \ if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \
GType g_define_type_id = type_name##_get_type_once (); \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
} \
return g_define_type_id__volatile; \
} \
\
G_GNUC_NO_INLINE \
static GType \
type_name##_get_type_once (void) \
{ \ { \
GType (* _g_register_boxed) \ GType (* _g_register_boxed) \
(const gchar *, \ (const gchar *, \
@ -2095,11 +2116,23 @@ type_name##_get_type (void) \
{ /* custom code follows */ { /* custom code follows */
#else #else
#define _G_DEFINE_BOXED_TYPE_BEGIN(TypeName, type_name, copy_func, free_func) \ #define _G_DEFINE_BOXED_TYPE_BEGIN(TypeName, type_name, copy_func, free_func) \
static GType type_name##_get_type_once (void); \
\
GType \ GType \
type_name##_get_type (void) \ type_name##_get_type (void) \
{ \ { \
static volatile gsize g_define_type_id__volatile = 0; \ static volatile gsize g_define_type_id__volatile = 0; \
if (g_once_init_enter (&g_define_type_id__volatile)) \ if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \
GType g_define_type_id = type_name##_get_type_once (); \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
} \
return g_define_type_id__volatile; \
} \
\
G_GNUC_NO_INLINE \
static GType \
type_name##_get_type_once (void) \
{ \ { \
GType g_define_type_id = \ GType g_define_type_id = \
g_boxed_type_register_static (g_intern_static_string (#TypeName), \ g_boxed_type_register_static (g_intern_static_string (#TypeName), \
@ -2136,11 +2169,23 @@ type_name##_get_type (void) \
#define G_DEFINE_POINTER_TYPE_WITH_CODE(TypeName, type_name, _C_) _G_DEFINE_POINTER_TYPE_BEGIN (TypeName, type_name) {_C_;} _G_DEFINE_TYPE_EXTENDED_END() #define G_DEFINE_POINTER_TYPE_WITH_CODE(TypeName, type_name, _C_) _G_DEFINE_POINTER_TYPE_BEGIN (TypeName, type_name) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()
#define _G_DEFINE_POINTER_TYPE_BEGIN(TypeName, type_name) \ #define _G_DEFINE_POINTER_TYPE_BEGIN(TypeName, type_name) \
static GType type_name##_get_type_once (void); \
\
GType \ GType \
type_name##_get_type (void) \ type_name##_get_type (void) \
{ \ { \
static volatile gsize g_define_type_id__volatile = 0; \ static volatile gsize g_define_type_id__volatile = 0; \
if (g_once_init_enter (&g_define_type_id__volatile)) \ if (g_once_init_enter (&g_define_type_id__volatile)) \
{ \
GType g_define_type_id = type_name##_get_type_once (); \
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \
} \
return g_define_type_id__volatile; \
} \
\
G_GNUC_NO_INLINE \
static GType \
type_name##_get_type_once (void) \
{ \ { \
GType g_define_type_id = \ GType g_define_type_id = \
g_pointer_type_register_static (g_intern_static_string (#TypeName)); \ g_pointer_type_register_static (g_intern_static_string (#TypeName)); \