gdbus-codegen: Define only one marshaller per signature reusing across interfaces

Avoid generating more code than needed, so other than continuing using
the generic glib marshallers when possible, define once the custom ones
we need for each file we generate.

The marshallers are then re-used across all the interfaces defined
without duplicating the code size.
This commit is contained in:
Marco Trevisan (Treviño) 2023-06-30 22:35:20 +02:00
parent 23180d433e
commit 27b7559c91
3 changed files with 102 additions and 15 deletions

View File

@ -1462,6 +1462,7 @@ class CodeGenerator:
self.glib_min_required = glib_min_required
self.symbol_decoration_define = symbol_decoration_define
self.outfile = outfile
self.marshallers = set()
# ----------------------------------------------------------------------------------------------------
@ -2669,25 +2670,53 @@ class CodeGenerator:
"\n" f" {ret_arg.gvalue_set} (return_value, v_return);\n"
)
def generic_marshaller_name(self, args=[], ret=None):
name = "_g_dbus_codegen_marshal_"
name += f"{ret.gvalue_type.upper() if ret else 'VOID'}__"
if args:
name += "_".join(f"{a.gvalue_type.upper()}" for a in args)
else:
name += "VOID"
return name
def generic_marshaller_name_for_type(self, t):
assert isinstance(t, (dbustypes.Signal, dbustypes.Method))
if not t.marshaller_ret_arg:
if not t.marshaller_in_args:
return "g_cclosure_marshal_VOID__VOID"
elif (
len(t.marshaller_in_args) == 1
and t.marshaller_in_args[0].gclosure_marshaller
):
return t.marshaller_in_args[0].gclosure_marshaller
return self.generic_marshaller_name(t.marshaller_in_args, t.marshaller_ret_arg)
def generate_generic_marshallers(self, i):
for t in i.signals + i.methods:
marshaller_name = self.generic_marshaller_name_for_type(t)
if marshaller_name.startswith("g_cclosure_"):
self.marshallers.add(marshaller_name)
continue
if marshaller_name in self.marshallers:
continue
self.generate_marshaller(
marshaller_name, t.marshaller_in_args, t.marshaller_ret_arg
)
self.marshallers.add(marshaller_name)
def generate_marshaller_for_type(self, i, t):
assert isinstance(t, (dbustypes.Signal, dbustypes.Method))
kind_uscore = utils.camel_case_to_uscore(t.__class__.__name__.lower())
func_name = f"{i.name_lower}_{kind_uscore}_marshal_{t.name_lower}"
marshaller_name = self.generic_marshaller_name_for_type(t)
assert marshaller_name in self.marshallers
if not t.marshaller_ret_arg:
if not t.marshaller_in_args:
self.generate_marshaller_wrapper(
func_name, "g_cclosure_marshal_VOID__VOID"
)
return
elif len(t.marshaller_in_args) == 1 and t.args[0].gclosure_marshaller:
self.generate_marshaller_wrapper(
func_name, t.args[0].gclosure_marshaller
)
return
self.generate_marshaller(func_name, t.marshaller_in_args, t.marshaller_ret_arg)
self.generate_marshaller_wrapper(func_name, marshaller_name)
def generate_signal_marshallers(self, i):
for s in i.signals:
@ -5419,6 +5448,8 @@ class CodeGenerator:
def generate(self):
self.generate_body_preamble()
for i in self.ifaces:
self.generate_generic_marshallers(i)
for i in self.ifaces:
self.generate_interface_intro(i)
self.generate_signals_enum_for_interface(i)

View File

@ -83,6 +83,7 @@ class Arg:
self.format_in = "@" + self.signature
self.format_out = "@" + self.signature
self.gvariant_get = "XXX"
self.gvalue_type = "variant"
self.gvalue_get = "g_marshal_value_peek_variant"
self.gvalue_set = "g_value_take_variant"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__VARIANT"
@ -101,6 +102,7 @@ class Arg:
self.format_in = "b"
self.format_out = "b"
self.gvariant_get = "g_variant_get_boolean"
self.gvalue_type = "boolean"
self.gvalue_get = "g_marshal_value_peek_boolean"
self.gvalue_set = "g_value_set_boolean"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOOLEAN"
@ -114,6 +116,7 @@ class Arg:
self.format_in = "y"
self.format_out = "y"
self.gvariant_get = "g_variant_get_byte"
self.gvalue_type = "uchar"
self.gvalue_get = "g_marshal_value_peek_uchar"
self.gvalue_set = "g_value_set_uchar"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__UCHAR"
@ -127,6 +130,7 @@ class Arg:
self.format_in = "n"
self.format_out = "n"
self.gvariant_get = "g_variant_get_int16"
self.gvalue_type = "int"
self.gvalue_get = "g_marshal_value_peek_int"
self.gvalue_set = "g_value_set_int"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__INT"
@ -140,6 +144,7 @@ class Arg:
self.format_in = "q"
self.format_out = "q"
self.gvariant_get = "g_variant_get_uint16"
self.gvalue_type = "uint"
self.gvalue_get = "g_marshal_value_peek_uint"
self.gvalue_set = "g_value_set_uint"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__UINT"
@ -153,6 +158,7 @@ class Arg:
self.format_in = "i"
self.format_out = "i"
self.gvariant_get = "g_variant_get_int32"
self.gvalue_type = "int"
self.gvalue_get = "g_marshal_value_peek_int"
self.gvalue_set = "g_value_set_int"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__INT"
@ -166,6 +172,7 @@ class Arg:
self.format_in = "u"
self.format_out = "u"
self.gvariant_get = "g_variant_get_uint32"
self.gvalue_type = "uint"
self.gvalue_get = "g_marshal_value_peek_uint"
self.gvalue_set = "g_value_set_uint"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__UINT"
@ -179,6 +186,7 @@ class Arg:
self.format_in = "x"
self.format_out = "x"
self.gvariant_get = "g_variant_get_int64"
self.gvalue_type = "int64"
self.gvalue_get = "g_marshal_value_peek_int64"
self.gvalue_set = "g_value_set_int64"
self.gclosure_marshaller = None
@ -192,6 +200,7 @@ class Arg:
self.format_in = "t"
self.format_out = "t"
self.gvariant_get = "g_variant_get_uint64"
self.gvalue_type = "uint64"
self.gvalue_get = "g_marshal_value_peek_uint64"
self.gvalue_set = "g_value_set_uint64"
self.gclosure_marshaller = None
@ -205,6 +214,7 @@ class Arg:
self.format_in = "d"
self.format_out = "d"
self.gvariant_get = "g_variant_get_double"
self.gvalue_type = "double"
self.gvalue_get = "g_marshal_value_peek_double"
self.gvalue_set = "g_value_set_double"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__DOUBLE"
@ -219,6 +229,7 @@ class Arg:
self.format_in = "s"
self.format_out = "s"
self.gvariant_get = "g_variant_get_string"
self.gvalue_type = "string"
self.gvalue_get = "g_marshal_value_peek_string"
self.gvalue_set = "g_value_set_string"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
@ -233,6 +244,7 @@ class Arg:
self.format_in = "o"
self.format_out = "o"
self.gvariant_get = "g_variant_get_string"
self.gvalue_type = "string"
self.gvalue_get = "g_marshal_value_peek_string"
self.gvalue_set = "g_value_set_string"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
@ -247,6 +259,7 @@ class Arg:
self.format_in = "g"
self.format_out = "g"
self.gvariant_get = "g_variant_get_string"
self.gvalue_type = "string"
self.gvalue_get = "g_marshal_value_peek_string"
self.gvalue_set = "g_value_set_string"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
@ -261,6 +274,7 @@ class Arg:
self.format_in = "^ay"
self.format_out = "^ay"
self.gvariant_get = "g_variant_get_bytestring"
self.gvalue_type = "string"
self.gvalue_get = "g_marshal_value_peek_string"
self.gvalue_set = "g_value_set_string"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
@ -275,6 +289,7 @@ class Arg:
self.format_in = "^as"
self.format_out = "^as"
self.gvariant_get = "g_variant_get_strv"
self.gvalue_type = "boxed"
self.gvalue_get = "g_marshal_value_peek_boxed"
self.gvalue_set = "g_value_take_boxed"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
@ -290,6 +305,7 @@ class Arg:
self.format_in = "^ao"
self.format_out = "^ao"
self.gvariant_get = "g_variant_get_objv"
self.gvalue_type = "boxed"
self.gvalue_get = "g_marshal_value_peek_boxed"
self.gvalue_set = "g_value_take_boxed"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
@ -305,6 +321,7 @@ class Arg:
self.format_in = "^aay"
self.format_out = "^aay"
self.gvariant_get = "g_variant_get_bytestring_array"
self.gvalue_type = "boxed"
self.gvalue_get = "g_marshal_value_peek_boxed"
self.gvalue_set = "g_value_take_boxed"
self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
@ -375,13 +392,17 @@ class Method:
method_invocation_arg = Arg("method_invocation", None)
method_invocation_arg.ctype_in = "GDBusMethodInvocation *"
method_invocation_arg.gvalue_type = "object"
method_invocation_arg.gvalue_get = "g_marshal_value_peek_object"
method_invocation_arg.gclosure_marshaller = None
self.marshaller_in_args = [method_invocation_arg] + self.in_args
if self.unix_fd:
fd_list_arg = Arg("fd_list", None)
fd_list_arg.ctype_in = "GUnixFDList *"
fd_list_arg.gvalue_type = "object"
fd_list_arg.gvalue_get = "g_marshal_value_peek_object"
fd_list_arg.gclosure_marshaller = None
self.marshaller_in_args.insert(0, fd_list_arg)
for a in self.annotations:

View File

@ -994,10 +994,20 @@ G_END_DECLS
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
self.assertIs(
stripped_out.count("g_marshal_value_peek_object (param_values + 1)"), 2
stripped_out.count("g_marshal_value_peek_object (param_values + 1)"), 1
)
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 2
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
self.assertIs(
stripped_out.count(
"_g_dbus_codegen_marshal_BOOLEAN__OBJECT (\n GClosure"
),
1,
)
self.assertIs(
stripped_out.count("_g_dbus_codegen_marshal_BOOLEAN__OBJECT (closure"), 2
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
@ -1087,6 +1097,14 @@ G_END_DECLS
<method name="MethodWithManyArgs">
{''.join(generated_args)}
</method>
<method name="SameMethodWithManyArgs">
{''.join(generated_args)}
</method>
</interface>
<interface name="org.project.OtherCallableIface">
<method name="MethodWithManyArgs">
{''.join(generated_args)}
</method>
</interface>
</node>"""
@ -1121,6 +1139,18 @@ G_END_DECLS
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
func_types = "_".join(
[p["value_type"].upper() for p in self.ARGUMENTS_TYPES.values()]
)
func_name = f"_g_dbus_codegen_marshal_BOOLEAN__OBJECT_{func_types}"
self.assertIs(stripped_out.count(f"{func_name} (\n GClosure"), 1)
self.assertIs(stripped_out.count(f"{func_name} (closure"), 3)
func_name = (
f"org_project_other_callable_iface_method_marshal_method_with_many_args"
)
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshallers_multiple_out_args(self):
@ -1165,6 +1195,11 @@ G_END_DECLS
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
self.assertIs(
stripped_out.count("_g_dbus_codegen_marshal_BOOLEAN__OBJECT (closure"),
1,
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshallers_with_unix_fds(self):
"""Test an interface with `h` arguments"""