[glib: 5/6] glib-genmarshal: Avoid a string copy for static string valist arguments



commit 1e10d6b6ddc40c170e9eb0af03232c7f22d51738
Author: Philip Withnall <withnall endlessm com>
Date:   Sat Jun 8 00:24:37 2019 +0100

    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

 gobject/glib-genmarshal.in  |   1 +
 gobject/tests/genmarshal.py | 132 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+)
---
diff --git a/gobject/glib-genmarshal.in b/gobject/glib-genmarshal.in
index f17e05532..1ea2ad9e8 100755
--- a/gobject/glib-genmarshal.in
+++ b/gobject/glib-genmarshal.in
@@ -330,6 +330,7 @@ IN_ARGS = {
         'ctype': 'gpointer',
         'getter': 'g_marshal_value_peek_string',
         'box': ['g_strdup', 'g_free'],
+        'static-check': True,
     },
     'PARAM': {
         'signal': 'PARAM',
diff --git a/gobject/tests/genmarshal.py b/gobject/tests/genmarshal.py
index 2df9a2b2e..0da61f3a2 100644
--- a/gobject/tests/genmarshal.py
+++ b/gobject/tests/genmarshal.py
@@ -462,6 +462,138 @@ class TestGenmarshal(unittest.TestCase):
             ''').strip().format(**body_result.subs),
             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__':
     unittest.main(testRunner=taptestrunner.TAPTestRunner())


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]