[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v11 06/15] qapi: Visit variants in visit_type_FO
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH v11 06/15] qapi: Visit variants in visit_type_FOO_fields() |
Date: |
Thu, 18 Feb 2016 14:58:56 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) |
Eric Blake <address@hidden> writes:
> We initially created the static visit_type_FOO_fields() helper
> function for reuse of code - we have cases where the initial
> setup for a visit has different allocation (depending on whether
> the fields represent a stand-alone type or are embedded as part
> of a larger type), but where the actual field visits are
> identical once a pointer is available.
>
> Up until the previous patch, visit_type_FOO_fields() was only
> used for structs (no variants), so it was covering every field
> for each type where it was emitted.
>
> Meanwhile, the code for visiting unions looks like:
>
> static visit_type_U_fields() {
> visit base;
> visit local_members;
> }
> visit_type_U() {
> visit_start_struct();
> visit_type_U_fields();
> visit variants;
> visit_end_struct();
> }
>
> which splits the fields of the union visit across two functions.
> Move the code to visit variants to live inside visit_type_U_fields(),
> while making it conditional on having variants so that all other
> instances of the helper function remain unchanged. This is also
> a step closer towards unifying struct and union visits, and towards
> allowing one union type to be the branch of another flat union.
>
> The resulting diff to the generated code is a bit hard to read,
Mostly because a few visit_type_T_fields() get generated in a different
place. If I move them back manually for a diff, the patch's effect
becomes clear enough: the switch to visit the variants and the
visit_start_union() guarding it moves from visit_type_T() to
visit_type_T_fields(). That's what the commit message promises.
> but it can be verified that it touches only union types, and that
> the end result is the following general structure:
>
> static visit_type_U_fields() {
> visit base;
> visit local_members;
> visit variants;
> }
> visit_type_U() {
> visit_start_struct();
> visit_type_U_fields();
> visit_end_struct();
> }
>
> Signed-off-by: Eric Blake <address@hidden>
>
> ---
> v11: new patch
> ---
> scripts/qapi-visit.py | 104
> +++++++++++++++++++++++++-------------------------
> 1 file changed, 53 insertions(+), 51 deletions(-)
>
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 1051710..6cea7d6 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -71,11 +71,16 @@ static void visit_type_implicit_%(c_type)s(Visitor *v,
> %(c_type)s **obj, Error *
> return ret
>
>
> -def gen_visit_struct_fields(name, base, members):
> +def gen_visit_struct_fields(name, base, members, variants=None):
Two callers:
* gen_visit_union(): the new code here comes from there, except it's now
completely guarded by if variants. Effect: generated code motion.
* gen_visit_struct(): passes no variants, guard false, thus no change.
I think the patch becomes slightly clearer if you make the variants
parameter mandatory. It'll probably become mandatory anyway when we
unify gen_visit_struct() and gen_visit_union().
> ret = ''
>
> if base:
> ret += gen_visit_fields_decl(base)
> + if variants:
> + for var in variants.variants:
> + # Ugly special case for simple union TODO get rid of it
> + if not var.simple_union_type():
> + ret += gen_visit_implicit_struct(var.type)
>
> struct_fields_seen.add(name)
> ret += mcgen('''
> @@ -96,8 +101,49 @@ static void visit_type_%(c_name)s_fields(Visitor *v,
> %(c_name)s **obj, Error **e
>
> ret += gen_visit_fields(members, prefix='(*obj)->')
>
> - # 'goto out' produced for base, and by gen_visit_fields() for each member
> - if base or members:
> + if variants:
> + ret += mcgen('''
> + if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
> + goto out;
> + }
> + switch ((*obj)->%(c_name)s) {
> +''',
> + c_name=c_name(variants.tag_member.name))
> +
> + for var in variants.variants:
> + # TODO ugly special case for simple union
> + simple_union_type = var.simple_union_type()
> + ret += mcgen('''
> + case %(case)s:
> +''',
> + case=c_enum_const(variants.tag_member.type.name,
> + var.name,
> + variants.tag_member.type.prefix))
> + if simple_union_type:
> + ret += mcgen('''
> + visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err);
> +''',
> + c_type=simple_union_type.c_name(),
> + c_name=c_name(var.name))
> + else:
> + ret += mcgen('''
> + visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
> +''',
> + c_type=var.type.c_name(),
> + c_name=c_name(var.name))
> + ret += mcgen('''
> + break;
> +''')
> +
> + ret += mcgen('''
> + default:
> + abort();
> + }
> +''')
> +
> + # 'goto out' produced for base, by gen_visit_fields() for each member,
> + # and if variants were present
> + if base or members or variants:
> ret += mcgen('''
>
> out:
> @@ -239,12 +285,7 @@ out:
>
>
> 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
> - if not var.simple_union_type():
> - ret += gen_visit_implicit_struct(var.type)
> + ret = gen_visit_struct_fields(name, base, members, variants)
>
> ret += mcgen('''
>
> @@ -260,54 +301,15 @@ void visit_type_%(c_name)s(Visitor *v, const char
> *name, %(c_name)s **obj, Error
> goto out_obj;
> }
> visit_type_%(c_name)s_fields(v, obj, &err);
> -''',
> - c_name=c_name(name))
> - ret += gen_err_check(label='out_obj')
> - ret += mcgen('''
> - if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
> - goto out_obj;
> - }
> - switch ((*obj)->%(c_name)s) {
> -''',
> - c_name=c_name(variants.tag_member.name))
> -
> - for var in variants.variants:
> - # TODO ugly special case for simple union
> - simple_union_type = var.simple_union_type()
> - ret += mcgen('''
> - case %(case)s:
> -''',
> - case=c_enum_const(variants.tag_member.type.name,
> - var.name,
> - variants.tag_member.type.prefix))
> - if simple_union_type:
> - ret += mcgen('''
> - visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err);
> -''',
> - c_type=simple_union_type.c_name(),
> - c_name=c_name(var.name))
> - else:
> - ret += mcgen('''
> - visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
> -''',
> - c_type=var.type.c_name(),
> - c_name=c_name(var.name))
> - ret += mcgen('''
> - break;
> -''')
> -
> - ret += mcgen('''
> - default:
> - abort();
> - }
> -out_obj:
> error_propagate(errp, err);
> err = NULL;
> +out_obj:
> visit_end_struct(v, &err);
> out:
> error_propagate(errp, err);
> }
> -''')
> +''',
> + c_name=c_name(name))
>
> return ret
[Qemu-devel] [PATCH v11 10/15] qapi: Emit structs used as variants in topological order, Eric Blake, 2016/02/18
[Qemu-devel] [PATCH v11 09/15] qapi: Adjust layout of FooList types, Eric Blake, 2016/02/18
[Qemu-devel] [PATCH v11 14/15] qapi: Delete visit_start_union(), gen_visit_implicit_struct(), Eric Blake, 2016/02/18