[glib: 1/2] glib-genmarshal: Avoid a param ref for static param valist arguments



commit 3f411a36af8295e282740adddf4cfb9d50c6c9d8
Author: Philip Withnall <withnall endlessm com>
Date:   Tue Jun 18 11:59:11 2019 +0100

    glib-genmarshal: Avoid a param ref for static param valist arguments
    
    When building a valist marshaller, we can avoid reffing a GParamSpec
    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 | 133 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+)
---
diff --git a/gobject/glib-genmarshal.in b/gobject/glib-genmarshal.in
index 1ea2ad9e8..7380f24a8 100755
--- a/gobject/glib-genmarshal.in
+++ b/gobject/glib-genmarshal.in
@@ -337,6 +337,7 @@ IN_ARGS = {
         'ctype': 'gpointer',
         'getter': 'g_marshal_value_peek_param',
         'box': ['g_param_spec_ref', 'g_param_spec_unref'],
+        'static-check': True,
     },
     'BOXED': {
         'signal': 'BOXED',
diff --git a/gobject/tests/genmarshal.py b/gobject/tests/genmarshal.py
index 0da61f3a2..190a1a69a 100644
--- a/gobject/tests/genmarshal.py
+++ b/gobject/tests/genmarshal.py
@@ -594,6 +594,139 @@ class TestGenmarshal(unittest.TestCase):
             ''').strip().format(**body_result.subs),
             body_result.out.strip())
 
+    def test_void_param_nostdinc(self):
+        """Test running with a basic VOID:PARAM list, but without the
+        standard marshallers, and with valist support enabled. This checks that
+        the valist marshaller for PARAM correctly skips a param copy if the
+        argument is static.
+
+        See issue #1792.
+        """
+        self.maxDiff = None  # TODO
+        (header_result, body_result) = \
+            self.runGenmarshalWithList('VOID:PARAM', '--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:PARAM ({list_path}:1) */
+            extern
+            void g_cclosure_user_marshal_VOID__PARAM (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__PARAMv (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:PARAM ({list_path}:1) */
+            void
+            g_cclosure_user_marshal_VOID__PARAM (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__PARAM) (gpointer data1,
+                                                        gpointer arg1,
+                                                        gpointer data2);
+              GCClosure *cc = (GCClosure *) closure;
+              gpointer data1, data2;
+              GMarshalFunc_VOID__PARAM 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__PARAM) (marshal_data ? marshal_data : cc->callback);
+
+              callback (data1,
+                        g_marshal_value_peek_param (param_values + 1),
+                        data2);
+            }}
+
+            void
+            g_cclosure_user_marshal_VOID__PARAMv (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__PARAM) (gpointer data1,
+                                                        gpointer arg1,
+                                                        gpointer data2);
+              GCClosure *cc = (GCClosure *) closure;
+              gpointer data1, data2;
+              GMarshalFunc_VOID__PARAM 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_param_spec_ref (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__PARAM) (marshal_data ? marshal_data : cc->callback);
+
+              callback (data1,
+                        arg0,
+                        data2);
+              if ((param_types[0] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0 && arg0 != NULL)
+                g_param_spec_unref (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]