mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-24 13:06:14 +01:00
glib-genmarshal: Avoid a string copy for static string valist arguments
When building a valist marshaller, we can avoid a string copy if the argument is known to always be static. The marshaller we ship in `gmarshal.c` got this right, but marshallers generated by glib-genmarshal were missing the optimisation. Fix that, and add a unit test. Signed-off-by: Philip Withnall <withnall@endlessm.com> Fixes: #1792
This commit is contained in:
parent
f044ddc1ee
commit
1e10d6b6dd
@ -330,6 +330,7 @@ IN_ARGS = {
|
|||||||
'ctype': 'gpointer',
|
'ctype': 'gpointer',
|
||||||
'getter': 'g_marshal_value_peek_string',
|
'getter': 'g_marshal_value_peek_string',
|
||||||
'box': ['g_strdup', 'g_free'],
|
'box': ['g_strdup', 'g_free'],
|
||||||
|
'static-check': True,
|
||||||
},
|
},
|
||||||
'PARAM': {
|
'PARAM': {
|
||||||
'signal': 'PARAM',
|
'signal': 'PARAM',
|
||||||
|
@ -462,6 +462,138 @@ class TestGenmarshal(unittest.TestCase):
|
|||||||
''').strip().format(**body_result.subs),
|
''').strip().format(**body_result.subs),
|
||||||
body_result.out.strip())
|
body_result.out.strip())
|
||||||
|
|
||||||
|
def test_void_string_nostdinc(self):
|
||||||
|
"""Test running with a basic VOID:STRING list, but without the
|
||||||
|
standard marshallers, and with valist support enabled. This checks that
|
||||||
|
the valist marshaller for STRING correctly skips a string copy if the
|
||||||
|
argument is static.
|
||||||
|
|
||||||
|
See issue #1792.
|
||||||
|
"""
|
||||||
|
(header_result, body_result) = \
|
||||||
|
self.runGenmarshalWithList('VOID:STRING', '--quiet', '--nostdinc',
|
||||||
|
'--valist-marshaller')
|
||||||
|
|
||||||
|
self.assertEqual('', header_result.err)
|
||||||
|
self.assertEqual('', body_result.err)
|
||||||
|
|
||||||
|
self.assertEqual(dedent(
|
||||||
|
'''
|
||||||
|
/* {standard_top_comment} */
|
||||||
|
{standard_top_pragma}
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* VOID:STRING ({list_path}:1) */
|
||||||
|
extern
|
||||||
|
void g_cclosure_user_marshal_VOID__STRING (GClosure *closure,
|
||||||
|
GValue *return_value,
|
||||||
|
guint n_param_values,
|
||||||
|
const GValue *param_values,
|
||||||
|
gpointer invocation_hint,
|
||||||
|
gpointer marshal_data);
|
||||||
|
extern
|
||||||
|
void g_cclosure_user_marshal_VOID__STRINGv (GClosure *closure,
|
||||||
|
GValue *return_value,
|
||||||
|
gpointer instance,
|
||||||
|
va_list args,
|
||||||
|
gpointer marshal_data,
|
||||||
|
int n_params,
|
||||||
|
GType *param_types);
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
{standard_bottom_pragma}
|
||||||
|
''').strip().format(**header_result.subs),
|
||||||
|
header_result.out.strip())
|
||||||
|
|
||||||
|
self.assertEqual(dedent(
|
||||||
|
'''
|
||||||
|
/* {standard_top_comment} */
|
||||||
|
{standard_marshal_peek_defines}
|
||||||
|
|
||||||
|
/* VOID:STRING ({list_path}:1) */
|
||||||
|
void
|
||||||
|
g_cclosure_user_marshal_VOID__STRING (GClosure *closure,
|
||||||
|
GValue *return_value G_GNUC_UNUSED,
|
||||||
|
guint n_param_values,
|
||||||
|
const GValue *param_values,
|
||||||
|
gpointer invocation_hint G_GNUC_UNUSED,
|
||||||
|
gpointer marshal_data)
|
||||||
|
{{
|
||||||
|
typedef void (*GMarshalFunc_VOID__STRING) (gpointer data1,
|
||||||
|
gpointer arg1,
|
||||||
|
gpointer data2);
|
||||||
|
GCClosure *cc = (GCClosure *) closure;
|
||||||
|
gpointer data1, data2;
|
||||||
|
GMarshalFunc_VOID__STRING callback;
|
||||||
|
|
||||||
|
g_return_if_fail (n_param_values == 2);
|
||||||
|
|
||||||
|
if (G_CCLOSURE_SWAP_DATA (closure))
|
||||||
|
{{
|
||||||
|
data1 = closure->data;
|
||||||
|
data2 = g_value_peek_pointer (param_values + 0);
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
{{
|
||||||
|
data1 = g_value_peek_pointer (param_values + 0);
|
||||||
|
data2 = closure->data;
|
||||||
|
}}
|
||||||
|
callback = (GMarshalFunc_VOID__STRING) (marshal_data ? marshal_data : cc->callback);
|
||||||
|
|
||||||
|
callback (data1,
|
||||||
|
g_marshal_value_peek_string (param_values + 1),
|
||||||
|
data2);
|
||||||
|
}}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_cclosure_user_marshal_VOID__STRINGv (GClosure *closure,
|
||||||
|
GValue *return_value G_GNUC_UNUSED,
|
||||||
|
gpointer instance,
|
||||||
|
va_list args,
|
||||||
|
gpointer marshal_data,
|
||||||
|
int n_params,
|
||||||
|
GType *param_types)
|
||||||
|
{{
|
||||||
|
typedef void (*GMarshalFunc_VOID__STRING) (gpointer data1,
|
||||||
|
gpointer arg1,
|
||||||
|
gpointer data2);
|
||||||
|
GCClosure *cc = (GCClosure *) closure;
|
||||||
|
gpointer data1, data2;
|
||||||
|
GMarshalFunc_VOID__STRING callback;
|
||||||
|
gpointer arg0;
|
||||||
|
va_list args_copy;
|
||||||
|
|
||||||
|
G_VA_COPY (args_copy, args);
|
||||||
|
arg0 = (gpointer) va_arg (args_copy, gpointer);
|
||||||
|
if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
|
||||||
|
arg0 = g_strdup (arg0);
|
||||||
|
va_end (args_copy);
|
||||||
|
|
||||||
|
|
||||||
|
if (G_CCLOSURE_SWAP_DATA (closure))
|
||||||
|
{{
|
||||||
|
data1 = closure->data;
|
||||||
|
data2 = instance;
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
{{
|
||||||
|
data1 = instance;
|
||||||
|
data2 = closure->data;
|
||||||
|
}}
|
||||||
|
callback = (GMarshalFunc_VOID__STRING) (marshal_data ? marshal_data : cc->callback);
|
||||||
|
|
||||||
|
callback (data1,
|
||||||
|
arg0,
|
||||||
|
data2);
|
||||||
|
if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
|
||||||
|
g_free (arg0);
|
||||||
|
}}
|
||||||
|
''').strip().format(**body_result.subs),
|
||||||
|
body_result.out.strip())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(testRunner=taptestrunner.TAPTestRunner())
|
unittest.main(testRunner=taptestrunner.TAPTestRunner())
|
||||||
|
Loading…
Reference in New Issue
Block a user