Eric Blake <ebl...@redhat.com> writes:

> When first introduced, neither branch of gen_visit_members_call()
> would output a goto.  But now that the implicit struct visit
> always ends with a goto, we should do the same for regular
> struct visits, so that callers don't have to worry about whether
> they are creating two identical goto's in a row.
>
> Generated code gets slightly larger; if desired, we could patch
> qapi.py:gen_visit_members() to have a mode where it skips the
> final goto and leave it up to the callers when to use that mode,
> but that adds more maintenance burden when the compiler should
> be smart enough to not bloat the .o file just because the .c
> file got larger.
>
> Signed-off-by: Eric Blake <ebl...@redhat.com>
>
> ---
> v2: rebase onto s/fields/members/ change
> ---
>  scripts/qapi-visit.py | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index e281d21..a17ecc1 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -48,6 +48,7 @@ def gen_visit_members_call(typ, direct_name, 
> implicit_name=None):
       assert isinstance(typ, QAPISchemaObjectType)
       if typ.is_empty():
           pass
       elif typ.is_implicit():
           assert implicit_name
           assert not typ.variants
           ret += gen_visit_members(typ.members, prefix=implicit_name)

This is the goto-generating part mentioned in the commit message.

       else:
           ret += mcgen('''
>      visit_type_%(c_type)s_members(v, %(c_name)s, &err);
>  ''',
>                       c_type=typ.c_name(), c_name=direct_name)
> +        ret += gen_err_check()
>      return ret

Emitting the gen_err_check() right after emitting the call it checks
makes for simpler and more robust code.

>
>
> @@ -63,7 +64,6 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s 
> *obj, Error **errp)
>
>      if base:
>          ret += gen_visit_members_call(base, '(%s *)obj' % base.c_name())
> -        ret += gen_err_check()
>
>      ret += gen_visit_members(members, prefix='obj->')
>

Adding more context to show the other use of gen_visit_members_call():

       if variants:
           ret += mcgen('''
       switch (obj->%(c_name)s) {
   ''',
                        c_name=c_name(variants.tag_member.name))

           for var in variants.variants:
               ret += mcgen('''
       case %(case)s:
   ''',
                            case=c_enum_const(variants.tag_member.type.name,
                                              var.name,
                                              variants.tag_member.type.prefix))
               push_indent()
               ret += gen_visit_members_call(var.type,
                                             '&obj->u.' + c_name(var.name),
                                             'obj->u.' + c_name(var.name) + '.')

This is where the generated code grows.  Before the patch, we sometimes
omit the goto on error, which works, because the label comes right after
the switch.

               pop_indent()
               ret += mcgen('''
           break;
   ''')

           ret += mcgen('''
       default:
           abort();
       }
   ''')

I wonder whether it would be simpler to make gen_visit_members_call()
add the goto from the start.

> @@ -95,9 +95,9 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s 
> *obj, Error **errp)
>      }
>  ''')
>
> -    # 'goto out' produced for base, by gen_visit_members() for each member,
> -    # and if variants were present
> -    if base or members or variants:
> +    # 'goto out' produced for non-empty base, by gen_visit_members() for
> +    # each member, and if variants were present
> +    if (base and not base.is_empty()) or members or variants:
>          ret += mcgen('''
>
>  out:

Uh, sure this hunk belongs to this patch?

Reply via email to