From 428eadd9e015fc76010912d379ebf538c9430101 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 20 Feb 2018 15:48:43 -0500 Subject: [PATCH] qapi-visit: Simplify how we visit common union members For a simple union SU, gen_visit_union() generates a visit of its single tag member, like this: visit_type_SUKind(v, "type", &(*obj)->type, &err); For a flat union FU with base B, it generates a visit of its base fields: visit_type_B_fields(v, (B **)obj, &err); Instead, we can simply visit the common members using the same fields visit function we use for structs, generated with gen_visit_struct_fields(). This function visits the base if any, then the local members. For a simple union SU, visit_type_SU_fields() contains exactly the old tag member visit, because there is no base, and the tag member is the only member. For instance, the code generated for qapi-schema.json's KeyValue changes like this: +static void visit_type_KeyValue_fields(Visitor *v, KeyValue **obj, Error **errp) +{ + Error *err = NULL; + + visit_type_KeyValueKind(v, "type", &(*obj)->type, &err); + if (err) { + goto out; + } + +out: + error_propagate(errp, err); +} + void visit_type_KeyValue(Visitor *v, const char *name, KeyValue **obj, Error **errp) { Error *err = NULL; @@ -4863,7 +4911,7 @@ void visit_type_KeyValue(Visitor *v, con if (!*obj) { goto out_obj; } - visit_type_KeyValueKind(v, "type", &(*obj)->type, &err); + visit_type_KeyValue_fields(v, obj, &err); if (err) { goto out_obj; } For a flat union FU, visit_type_FU_fields() contains exactly the old base fields visit, because there is a base, but no members. For instance, the code generated for qapi-schema.json's CpuInfo changes like this: static void visit_type_CpuInfoBase_fields(Visitor *v, CpuInfoBase **obj, Error **errp); +static void visit_type_CpuInfo_fields(Visitor *v, CpuInfo **obj, Error **errp) +{ + Error *err = NULL; + + visit_type_CpuInfoBase_fields(v, (CpuInfoBase **)obj, &err); + if (err) { + goto out; + } + +out: + error_propagate(errp, err); +} + static void visit_type_CpuInfoX86_fields(Visitor *v, CpuInfoX86 **obj, Error **errp) ... @@ -3485,7 +3509,7 @@ void visit_type_CpuInfo(Visitor *v, cons if (!*obj) { goto out_obj; } - visit_type_CpuInfoBase_fields(v, (CpuInfoBase **)obj, &err); + visit_type_CpuInfo_fields(v, obj, &err); if (err) { goto out_obj; } As you see, the generated code grows a bit, but in practice, it's lost in the noise: qapi-schema.json's qapi-visit.c gains roughly 1%. This simplification became possible with commit 441cbac "qapi-visit: Convert to QAPISchemaVisitor, fixing bugs". It's a step towards unifying gen_struct() and gen_union(). Backports commit d7445b57f4342d50c25b5bc1746048fa3720511b from qemu --- qemu/scripts/qapi-visit.py | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/qemu/scripts/qapi-visit.py b/qemu/scripts/qapi-visit.py index 462327c9..4b8f50a8 100644 --- a/qemu/scripts/qapi-visit.py +++ b/qemu/scripts/qapi-visit.py @@ -239,11 +239,8 @@ out: return ret -def gen_visit_union(name, base, variants): - ret = '' - - if base: - ret += gen_visit_fields_decl(base) +def gen_visit_union(name, base, members, variants): + ret = gen_visit_struct_fields(name, base, members) for var in variants.variants: # Ugly special case for simple union TODO get rid of it @@ -263,21 +260,10 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error if (!*obj) { goto out_obj; } + visit_type_%(c_name)s_fields(v, obj, &err); ''', c_name=c_name(name)) - if base: - ret += mcgen(''' - visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err); -''', - c_name=base.c_name()) - else: - ret += mcgen(''' - visit_type_%(c_type)s(v, "%(name)s", &(*obj)->%(c_name)s, &err); -''', - c_type=variants.tag_member.type.c_name(), - c_name=c_name(variants.tag_member.name), - name=variants.tag_member.name) ret += gen_err_check(label='out_obj') ret += mcgen(''' if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) { @@ -380,11 +366,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): def visit_object_type(self, name, info, base, members, variants): self.decl += gen_visit_decl(name) if variants: - if members: - # Members other than variants.tag_member not implemented - assert len(members) == 1 - assert members[0] == variants.tag_member - self.defn += gen_visit_union(name, base, variants) + self.defn += gen_visit_union(name, base, members, variants) else: self.defn += gen_visit_struct(name, base, members)