1. 18 2月, 2019 2 次提交
    • M
      qapi: Prepare for system modules other than 'builtin' · c2e196a9
      Markus Armbruster 提交于
      The next commit wants to generate qapi-emit-events.{c.h}.  To enable
      that, extend QAPISchemaModularCVisitor to support additional "system
      modules", i.e. modules that don't correspond to a (user-defined) QAPI
      schema module.
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      Reviewed-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
      Message-Id: <20190214152251.2073-5-armbru@redhat.com>
      c2e196a9
    • M
      qapi: Clean up modular built-in code generation a bit · dcac6471
      Markus Armbruster 提交于
      We neglect to call .visit_module() for the special module we use for
      built-ins.  Harmless, but clean it up anyway.  The
      tests/qapi-schema/*.out now show the built-in module as 'module None'.
      
      Subclasses of QAPISchemaModularCVisitor need to ._add_module() this
      special module to enable code generation for built-ins.  When this
      hasn't been done, QAPISchemaModularCVisitor.visit_module() does
      nothing for the special module.  That looks like built-ins could
      accidentally be generated into the wrong module when a subclass
      neglects to call ._add_module().  Can't happen, because built-ins are
      all visited before any other module.  But that's non-obvious.  Switch
      off code generation explicitly.
      
      Rename QAPISchemaModularCVisitor._begin_module() to
      ._begin_user_module().
      
      New QAPISchemaModularCVisitor._is_builtin_module(), for clarity.
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      Reviewed-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
      Message-Id: <20190214152251.2073-4-armbru@redhat.com>
      dcac6471
  2. 14 12月, 2018 2 次提交
  3. 04 7月, 2018 2 次提交
  4. 22 6月, 2018 1 次提交
    • A
      qapi: allow empty branches in flat unions · 800877bb
      Anton Nefedov 提交于
      It often happens that just a few discriminator values imply extra data in
      a flat union. Existing checks did not make possible to leave other values
      uncovered. Such cases had to be worked around by either stating a dummy
      (empty) type or introducing another (subset) discriminator enumeration.
      
      Both options create redundant entities in qapi files for little profit.
      
      With this patch it is not necessary anymore to add designated union
      fields for every possible value of a discriminator enumeration.
      Signed-off-by: NAnton Nefedov <anton.nefedov@virtuozzo.com>
      Message-Id: <1529311206-76847-2-git-send-email-anton.nefedov@virtuozzo.com>
      Reviewed-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      800877bb
  5. 03 3月, 2018 11 次提交
  6. 04 9月, 2017 1 次提交
  7. 16 3月, 2017 1 次提交
    • M
      qapi: Prefer single-quoted strings more consistently · ef801a9b
      Markus Armbruster 提交于
      PEP 8 advises:
      
          In Python, single-quoted strings and double-quoted strings are the
          same.  This PEP does not make a recommendation for this.  Pick a
          rule and stick to it.  When a string contains single or double
          quote characters, however, use the other one to avoid backslashes
          in the string.  It improves readability.
      
      The QAPI generators succeed at picking a rule, but fail at sticking to
      it.  Convert a bunch of double-quoted strings to single-quoted ones.
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      Reviewed-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1489582656-31133-20-git-send-email-armbru@redhat.com>
      ef801a9b
  8. 19 7月, 2016 1 次提交
    • E
      qapi: Add type.is_empty() helper · b6167706
      Eric Blake 提交于
      In the near future, we want to lift our artificial restriction of
      no variants at the top level of an event, at which point the
      currently open-coded check for empty members will become
      insufficient.  Factor it out into a new helper method is_empty()
      now, and future-proof it by checking variants, too, along with an
      assert that it is not used prior to the completion of .check().
      Update places that were checking for (non-)empty .members to use
      the new helper.
      
      All of the current callers assert that there are no variants (either
      directly, or by qapi.py asserting that base types have no variants),
      so this is not a semantic change.
      
      No change to generated code.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1468468228-27827-6-git-send-email-eblake@redhat.com>
      Reviewed-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      b6167706
  9. 06 7月, 2016 1 次提交
    • E
      qapi: Add new visit_free() function · 2c0ef9f4
      Eric Blake 提交于
      Making each visitor provide its own (awkwardly-named) FOO_cleanup()
      is unusual, when we can instead have a polymorphic visit_free()
      interface.  Over the next few patches, we can use the polymorphic
      functions to eliminate the need for a FOO_get_visitor() function
      for accessing specific visitor functionality, once everything can
      be accessed directly through the Visitor* interfaces.
      
      The dealloc visitor is the first one converted to completely use
      the new entry point, since qapi_dealloc_visitor_cleanup() was the
      only reason that qapi_dealloc_get_visitor() existed, and only
      generated and testsuite code was even using it.  With the new
      visit_free() entry point in place, we no longer need to expose
      the QapiDeallocVisitor subtype through qapi_dealloc_visitor_new(),
      and can get by with less generated code, with diffs that look like:
      
      | void qapi_free_ACPIOSTInfo(ACPIOSTInfo *obj)
      | {
      |-    QapiDeallocVisitor *qdv;
      |     Visitor *v;
      |
      |     if (!obj) {
      |         return;
      |     }
      |
      |-    qdv = qapi_dealloc_visitor_new();
      |-    v = qapi_dealloc_get_visitor(qdv);
      |+    v = qapi_dealloc_visitor_new();
      |     visit_type_ACPIOSTInfo(v, NULL, &obj, NULL);
      |-    qapi_dealloc_visitor_cleanup(qdv);
      |+    visit_free(v);
      |}
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1465490926-28625-5-git-send-email-eblake@redhat.com>
      Reviewed-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      2c0ef9f4
  10. 23 3月, 2016 1 次提交
  11. 18 3月, 2016 4 次提交
    • E
      qapi: Allow anonymous base for flat union · ac4338f8
      Eric Blake 提交于
      Rather than requiring all flat unions to explicitly create
      a separate base struct, we can allow the qapi schema to specify
      the common members via an inline dictionary. This is similar to
      how commands can specify an inline anonymous type for its 'data'.
      We already have several struct types that only exist to serve as
      a single flat union's base; the next commit will clean them up.
      In particular, this patch's change to the BlockdevOptions example
      in qapi-code-gen.txt will actually be done in the real QAPI schema.
      
      Now that anonymous bases are legal, we need to rework the
      flat-union-bad-base negative test (as previously written, it
      forms what is now valid QAPI; tweak it to now provide coverage
      of a new error message path), and add a positive test in
      qapi-schema-test to use an anonymous base (making the integer
      argument optional, for even more coverage).
      
      Note that this patch only allows anonymous bases for flat unions;
      simple unions are already enough syntactic sugar that we do not
      want to burden them further.  Meanwhile, while it would be easy
      to also allow an anonymous base for structs, that would be quite
      redundant, as the members can be put right into the struct
      instead.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1458254921-17042-15-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      ac4338f8
    • E
      qapi: Don't special-case simple union wrappers · 32bafa8f
      Eric Blake 提交于
      Simple unions were carrying a special case that hid their 'data'
      QMP member from the resulting C struct, via the hack method
      QAPISchemaObjectTypeVariant.simple_union_type().  But by using
      the work we started by unboxing flat union and alternate
      branches, coupled with the ability to visit the members of an
      implicit type, we can now expose the simple union's implicit
      type in qapi-types.h:
      
      | struct q_obj_ImageInfoSpecificQCow2_wrapper {
      |     ImageInfoSpecificQCow2 *data;
      | };
      |
      | struct q_obj_ImageInfoSpecificVmdk_wrapper {
      |     ImageInfoSpecificVmdk *data;
      | };
      ...
      | struct ImageInfoSpecific {
      |     ImageInfoSpecificKind type;
      |     union { /* union tag is @type */
      |         void *data;
      |-        ImageInfoSpecificQCow2 *qcow2;
      |-        ImageInfoSpecificVmdk *vmdk;
      |+        q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
      |+        q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
      |     } u;
      | };
      
      Doing this removes asymmetry between QAPI's QMP side and its
      C side (both sides now expose 'data'), and means that the
      treatment of a simple union as sugar for a flat union is now
      equivalent in both languages (previously the two approaches used
      a different layer of dereferencing, where the simple union could
      be converted to a flat union with equivalent C layout but
      different {} on the wire, or to an equivalent QMP wire form
      but with different C representation).  Using the implicit type
      also lets us get rid of the simple_union_type() hack.
      
      Of course, now all clients of simple unions have to adjust from
      using su->u.member to using su->u.member.data; while this touches
      a number of files in the tree, some earlier cleanup patches
      helped minimize the change to the initialization of a temporary
      variable rather than every single member access.  The generated
      qapi-visit.c code is also affected by the layout change:
      
      |@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
      |     }
      |     switch (obj->type) {
      |     case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
      |-        visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
      |+        visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
      |         break;
      |     case IMAGE_INFO_SPECIFIC_KIND_VMDK:
      |-        visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
      |+        visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
      |         break;
      |     default:
      |         abort();
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      32bafa8f
    • E
      qapi: Emit implicit structs in generated C · 7ce106a9
      Eric Blake 提交于
      We already have several places that want to visit all the members
      of an implicit object within a larger context (simple union variant,
      event with anonymous data, command with anonymous arguments struct);
      and will be adding another one soon (the ability to declare an
      anonymous base for a flat union).  Having a C struct declared for
      these implicit types, along with a visit_type_FOO_members() helper
      function, will make for fewer special cases in our generator.
      
      We do not, however, need qapi_free_FOO() or visit_type_FOO()
      functions for implicit types, because they should not be used
      directly outside of the generated code.  This is done by adding a
      conditional in visit_object_type() for both qapi-types.py and
      qapi-visit.py based on the object name.  The comparison of
      "name.startswith('q_')" is a bit hacky (it's basically duplicating
      what .is_implicit() already uses), but beats changing the signature
      of the visit_object_type() callback to pass a new 'implicit' flag.
      The hack should be temporary: we are considering adding a future
      patch that consolidates the narrow visit_object_type(..., base,
      local_members, variants) and visit_object_type_flat(...,
      all_members, variants) [where different sets of information are
      already broken out, and the QAPISchemaObjectType is no longer
      available] into a broader visit_object_type(obj_type) [where the
      visitor can query the needed fields from obj_type directly].
      
      Also, now that we WANT to output C code for implicits, we no longer
      need the visit_needed() filter, leaving 'q_empty' as the only object
      still needing a special case.  Remember, 'q_empty' is the only
      built-in generated object, which means that without a special case
      it would be emitted in multiple files (the main qapi-types.h and in
      qga-qapi-types.h) causing compilation failure due to redefinition.
      But since it has no members, it's easier to just avoid an attempt to
      visit that particular type; since gen_object() is called recursively,
      we also prime the objects_seen set to cover any recursion into the
      empty type.
      
      The patch relies on the changed naming of implicit types in the
      previous patch.  It is a bit unfortunate that the generated struct
      names and visit_type_FOO_members() don't match normal naming
      conventions, but it's not too bad, since they will only be used in
      generated code.
      
      The generated code grows substantially in size: the implicit
      '-wrapper' types must be emitted in qapi-types.h before any union
      can include an unboxed member of that type.  Arguably, the '-args'
      types could be emitted in a private header for just qapi-visit.c
      and qmp-marshal.c, rather than polluting qapi-types.h; but adding
      complexity to the generator to split the output location according
      to role doesn't seem worth the maintenance costs.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1458254921-17042-6-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      7ce106a9
    • E
      qapi: Make c_type() more OO-like · 4040d995
      Eric Blake 提交于
      QAPISchemaType.c_type() is a bit awkward: it takes two optional
      boolean flags is_param and is_unboxed, and they should never both
      be True.
      
      Add a new method for each of the flags, and drop the flags from
      c_type().
      
      Most callers pass no flags; they remain unchanged.
      
      One caller passes is_param=True; call the new .c_param_type()
      instead.
      
      One caller passes is_unboxed=True, except for simple union types.
      This is actually an ugly special case that will go away soon, so
      until then, we now have to call either .c_type() or the new
      .c_unboxed_type().  Tolerable in the interim.
      
      It requires slightly more Python, but is arguably easier to read.
      Suggested-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1458254921-17042-4-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      4040d995
  12. 05 3月, 2016 3 次提交
  13. 19 2月, 2016 4 次提交
    • E
      qapi: Don't box branches of flat unions · 544a3731
      Eric Blake 提交于
      There's no reason to do two malloc's for a flat union; let's just
      inline the branch struct directly into the C union branch of the
      flat union.
      
      Surprisingly, fewer clients were actually using explicit references
      to the branch types in comparison to the number of flat unions
      thus modified.
      
      This lets us reduce the hack in qapi-types:gen_variants() added in
      the previous patch; we no longer need to distinguish between
      alternates and flat unions.
      
      The change to unboxed structs means that u.data (added in commit
      cee2dedb) is now coincident with random fields of each branch of
      the flat union, whereas beforehand it was only coincident with
      pointers (since all branches of a flat union have to be objects).
      Note that this was already the case for simple unions - but there
      we got lucky.  Remember, visit_start_union() blindly returns true
      for all visitors except for the dealloc visitor, where it returns
      the value !!obj->u.data, and that this result then controls
      whether to proceed with the visit to the variant.  Pre-patch,
      this meant that flat unions were testing whether the boxed pointer
      was still NULL, and thereby skipping visit_end_implicit_struct()
      and avoiding a NULL dereference if the pointer had not been
      allocated.  The same was true for simple unions where the current
      branch had pointer type, except there we bypassed visit_type_FOO().
      But for simple unions where the current branch had scalar type, the
      contents of that scalar meant that the decision to call
      visit_type_FOO() was data-dependent - the reason we got lucky there
      is that visit_type_FOO() for all scalar types in the dealloc visitor
      is a no-op (only the pointer variants had anything to free), so it
      did not matter whether the dealloc visit was skipped.  But with this
      patch, we would risk leaking memory if we could skip a call to
      visit_type_FOO_fields() based solely on a data-dependent decision.
      
      But notice: in the dealloc visitor, visit_type_FOO() already handles
      a NULL obj - it was only the visit_type_implicit_FOO() that was
      failing to check for NULL. And now that we have refactored things to
      have the branch be part of the parent struct, we no longer have a
      separate pointer that can be NULL in the first place.  So we can just
      delete the call to visit_start_union() altogether, and blindly visit
      the branch type; there is no change in behavior except to the dealloc
      visitor, where we now unconditionally visit the branch, but where that
      visit is now always safe (for a flat union, we can no longer
      dereference NULL, and for a simple union, visit_type_FOO() was already
      safely handling NULL on pointer types).
      
      Unfortunately, simple unions are not as easy to switch to unboxed
      layout; because we are special-casing the hidden implicit type with
      a single 'data' member, we really DO need to keep calling another
      layer of visit_start_struct(), with a second malloc; although there
      are some cleanups planned for simple unions in later patches.
      
      visit_start_union() and gen_visit_implicit_struct() are now unused.
      Drop them.
      
      Note that after this patch, the only remaining use of
      visit_start_implicit_struct() is for alternate types; the next patch
      will do further cleanup based on that fact.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-14-git-send-email-eblake@redhat.com>
      [Dead code deletion squashed in, commit message updated accordingly]
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      544a3731
    • E
      qapi: Don't box struct branch of alternate · becceedc
      Eric Blake 提交于
      There's no reason to do two malloc's for an alternate type visiting
      a QAPI struct; let's just inline the struct directly as the C union
      branch of the struct.
      
      Surprisingly, no clients were actually using the struct member prior
      to this patch outside of the testsuite; an earlier patch in the series
      added some testsuite coverage to make the effect of this patch more
      obvious.
      
      In qapi.py, c_type() gains a new is_unboxed flag to control when we
      are emitting a C struct unboxed within the context of an outer
      struct (different from our other two modes of usage with no flags
      for normal local variable declarations, and with is_param for adding
      'const' in a parameter list).  I don't know if there is any more
      pythonic way of collapsing the two flags into a single parameter,
      as we never have a caller setting both flags at once.
      
      Ultimately, we want to also unbox branches for QAPI unions, but as
      that touches a lot more client code, it is better as separate
      patches.  But since unions and alternates share gen_variants(), I
      had to hack in a way to test if we are visiting an alternate type
      for setting the is_unboxed flag: look for a non-object branch.
      This works because alternates have at least two branches, with at
      most one object branch, while unions have only object branches.
      The hack will go away in a later patch.
      
      The generated code difference to qapi-types.h is relatively small:
      
      | struct BlockdevRef {
      |     QType type;
      |     union { /* union tag is @type */
      |         void *data;
      |-        BlockdevOptions *definition;
      |+        BlockdevOptions definition;
      |         char *reference;
      |     } u;
      | };
      
      The corresponding spot in qapi-visit.c calls visit_type_FOO(), which
      first calls visit_start_struct() to allocate or deallocate the member
      and handle a layer of {} from the JSON stream, then visits the
      members.  To peel off the indirection and the memory management that
      comes with it, we inline this call, then suppress allocation /
      deallocation by passing NULL to visit_start_struct(), and adjust the
      member visit:
      
      |     switch ((*obj)->type) {
      |     case QTYPE_QDICT:
      |-        visit_type_BlockdevOptions(v, name, &(*obj)->u.definition, &err);
      |+        visit_start_struct(v, name, NULL, 0, &err);
      |+        if (err) {
      |+            break;
      |+        }
      |+        visit_type_BlockdevOptions_fields(v, &(*obj)->u.definition, &err);
      |+        error_propagate(errp, err);
      |+        err = NULL;
      |+        visit_end_struct(v, &err);
      |         break;
      |     case QTYPE_QSTRING:
      |         visit_type_str(v, name, &(*obj)->u.reference, &err);
      
      The visit of non-object fields is unchanged.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-13-git-send-email-eblake@redhat.com>
      [Commit message tweaked]
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      becceedc
    • E
      qapi: Emit structs used as variants in topological order · 1de5d4ca
      Eric Blake 提交于
      Right now, we emit the branches of union types as a boxed pointer,
      and it suffices to have a forward declaration of the type.  However,
      a future patch will swap things to directly use the branch type,
      instead of hiding it behind a pointer.  For this to work, the
      compiler needs the full definition of the type, not just a forward
      declaration, prior to the union that is including the branch type.
      This patch just adds topological sorting to hoist all types
      mentioned in a branch of a union to be fully declared before the
      union itself.  The sort is always possible, because we do not
      allow circular union types that include themselves as a direct
      branch (it is, however, still possible to include a branch type
      that itself has a pointer to the union, for a type that can
      indirectly recursively nest itself - that remains safe, because
      that the member of the branch type will remain a pointer, and the
      QMP representation of such a type adds another {} for each recurring
      layer of the union type).
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-11-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      1de5d4ca
    • E
      qapi: Adjust layout of FooList types · e65d89bf
      Eric Blake 提交于
      By sticking the next pointer first, we don't need a union with
      64-bit padding for smaller types.  On 32-bit platforms, this
      can reduce the size of uint8List from 16 bytes (or 12, depending
      on whether 64-bit ints can tolerate 4-byte alignment) down to 8.
      It has no effect on 64-bit platforms (where alignment still
      dictates a 16-byte struct); but fewer anonymous unions is still
      a win in my book.
      
      It requires visit_next_list() to gain a size parameter, to know
      what size element to allocate; comparable to the size parameter
      of visit_start_struct().
      
      I debated about going one step further, to allow for fewer casts,
      by doing:
          typedef GenericList GenericList;
          struct GenericList {
              GenericList *next;
          };
          struct FooList {
              GenericList base;
              Foo *value;
          };
      so that you convert to 'GenericList *' by '&foolist->base', and
      back by 'container_of(generic, GenericList, base)' (as opposed to
      the existing '(GenericList *)foolist' and '(FooList *)generic').
      But doing that would require hoisting the declaration of
      GenericList prior to inclusion of qapi-types.h, rather than its
      current spot in visitor.h; it also makes iteration a bit more
      verbose through 'foolist->base.next' instead of 'foolist->next'.
      
      Note that for lists of objects, the 'value' payload is still
      hidden behind a boxed pointer.  Someday, it would be nice to do:
      
      struct FooList {
          FooList *next;
          Foo value;
      };
      
      for one less level of malloc for each list element.  This patch
      is a step in that direction (now that 'next' is no longer at a
      fixed non-zero offset within the struct, we can store more than
      just a pointer's-worth of data as the value payload), but the
      actual conversion would be a task for another series, as it will
      touch a lot of code.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-10-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      e65d89bf
  14. 16 2月, 2016 1 次提交
  15. 09 2月, 2016 1 次提交
    • E
      qapi: Swap visit_* arguments for consistent 'name' placement · 51e72bc1
      Eric Blake 提交于
      JSON uses "name":value, but many of our visitor interfaces were
      called with visit_type_FOO(v, &value, name, errp).  This can be
      a bit confusing to have to mentally swap the parameter order to
      match JSON order.  It's particularly bad for visit_start_struct(),
      where the 'name' parameter is smack in the middle of the
      otherwise-related group of 'obj, kind, size' parameters! It's
      time to do a global swap of the parameter ordering, so that the
      'name' parameter is always immediately after the Visitor argument.
      
      Additional reason in favor of the swap: the existing include/qjson.h
      prefers listing 'name' first in json_prop_*(), and I have plans to
      unify that file with the qapi visitors; listing 'name' first in
      qapi will minimize churn to the (admittedly few) qjson.h clients.
      
      Later patches will then fix docs, object.h, visitor-impl.h, and
      those clients to match.
      
      Done by first patching scripts/qapi*.py by hand to make generated
      files do what I want, then by running the following Coccinelle
      script to affect the rest of the code base:
       $ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
      I then had to apply some touchups (Coccinelle insisted on TAB
      indentation in visitor.h, and botched the signature of
      visit_type_enum() by rewriting 'const char *const strings[]' to
      the syntactically invalid 'const char*const[] strings').  The
      movement of parameters is sufficient to provoke compiler errors
      if any callers were missed.
      
          // Part 1: Swap declaration order
          @@
          type TV, TErr, TObj, T1, T2;
          identifier OBJ, ARG1, ARG2;
          @@
           void visit_start_struct
          -(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
          +(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
           { ... }
      
          @@
          type bool, TV, T1;
          identifier ARG1;
          @@
           bool visit_optional
          -(TV v, T1 ARG1, const char *name)
          +(TV v, const char *name, T1 ARG1)
           { ... }
      
          @@
          type TV, TErr, TObj, T1;
          identifier OBJ, ARG1;
          @@
           void visit_get_next_type
          -(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
          +(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
           { ... }
      
          @@
          type TV, TErr, TObj, T1, T2;
          identifier OBJ, ARG1, ARG2;
          @@
           void visit_type_enum
          -(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
          +(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
           { ... }
      
          @@
          type TV, TErr, TObj;
          identifier OBJ;
          identifier VISIT_TYPE =~ "^visit_type_";
          @@
           void VISIT_TYPE
          -(TV v, TObj OBJ, const char *name, TErr errp)
          +(TV v, const char *name, TObj OBJ, TErr errp)
           { ... }
      
          // Part 2: swap caller order
          @@
          expression V, NAME, OBJ, ARG1, ARG2, ERR;
          identifier VISIT_TYPE =~ "^visit_type_";
          @@
          (
          -visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
          +visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
          |
          -visit_optional(V, ARG1, NAME)
          +visit_optional(V, NAME, ARG1)
          |
          -visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
          +visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
          |
          -visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
          +visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
          |
          -VISIT_TYPE(V, OBJ, NAME, ERR)
          +VISIT_TYPE(V, NAME, OBJ, ERR)
          )
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Reviewed-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
      Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      51e72bc1
  16. 17 12月, 2015 4 次提交
    • E
      qapi-types: Drop unnedeed ._fwdefn · 0b2e84ba
      Eric Blake 提交于
      Previously, the generated code in qapi-types.c initialized all
      enum lookup tables first, prior to any other definitions.  But
      there are no topological sorting requirements that mandate this
      layout, so we can drop the QAPISchemaGenTypeVisitor._fwdefn
      field and just generate all definitions in visitation order.
      
      The generated code shows some churn due to reordering, but it
      is still fairly straightforward to follow (all the deletions
      occur in one hunk, and all the deleted lines are re-inserted
      in the same order later in the same files, just spread across
      multiple insertion points).
      Suggested-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1449033659-25497-6-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      0b2e84ba
    • E
      qapi: Simplify visiting of alternate types · 0426d53c
      Eric Blake 提交于
      Previously, working with alternates required two lookup arrays
      and some indirection: for type Foo, we created Foo_qtypes[]
      which maps each qtype to a value of the generated FooKind enum,
      then look up that value in FooKind_lookup[] like we do for other
      union types.
      
      This has a couple of subtle bugs.  First, the generator was
      creating a call with a parameter '(int *) &(*obj)->type' where
      type is an enum type; this is unsafe if the compiler chooses
      to store the enum type in a different size than int, where
      assigning through the wrong size pointer can corrupt data or
      cause a SIGBUS.
      
      Related bug, not not fixed in this patch: qapi-visit.py's
      gen_visit_enum() generates a cast of its enum * argument to
      int *. Marked FIXME.
      
      Second, since the values of the FooKind enum start at zero, all
      entries of the Foo_qtypes[] array that were not explicitly
      initialized will map to the same branch of the union as the
      first member of the alternate, rather than triggering a desired
      failure in visit_get_next_type().  Fortunately, the bug seldom
      bites; the very next thing the input visitor does is try to
      parse the incoming JSON with the wrong parser, which normally
      fails; the output visitor is not used with a C struct in that
      state, and the dealloc visitor has nothing to clean up (so
      there is no leak).
      
      However, the second bug IS observable in one case: parsing an
      integer causes unusual behavior in an alternate that contains
      at least a 'number' member but no 'int' member, because the
      'number' parser accepts QTYPE_QINT in addition to the expected
      QTYPE_QFLOAT (that is, since 'int' is not a member, the type
      QTYPE_QINT accidentally maps to FooKind 0; if this enum value
      is the 'number' branch the integer parses successfully, but if
      the 'number' branch is not first, some other branch tries to
      parse the integer and rejects it).  A later patch will worry
      about fixing alternates to always parse all inputs that a
      non-alternate 'number' would accept, for now this is still
      marked FIXME in the updated test-qmp-input-visitor.c, to
      merely point out that new undesired behavior of 'ans' matches
      the existing undesired behavior of 'asn'.
      
      This patch fixes the default-initialization bug by deleting the
      indirection, and modifying get_next_type() to directly assign a
      QTypeCode parameter.  This in turn fixes the type-casting bug,
      as we are no longer casting a pointer to enum to a questionable
      size. There is no longer a need to generate an implicit FooKind
      enum associated with the alternate type (since the QMP wire
      format never uses the stringized counterparts of the C union
      member names).  Since the updated visit_get_next_type() does not
      know which qtypes are expected, the generated visitor is
      modified to generate an error statement if an unexpected type is
      encountered.
      
      Callers now have to know the QTYPE_* mapping when looking at the
      discriminator; but so far, only the testsuite was even using the
      C struct of an alternate types.  I considered the possibility of
      keeping the internal enum FooKind, but initialized differently
      than most generated arrays, as in:
        typedef enum FooKind {
            FOO_KIND_A = QTYPE_QDICT,
            FOO_KIND_B = QTYPE_QINT,
        } FooKind;
      to create nicer aliases for knowing when to use foo->a or foo->b
      when inspecting foo->type; but it turned out to add too much
      complexity, especially without a client.
      
      There is a user-visible side effect to this change, but I
      consider it to be an improvement. Previously,
      the invalid QMP command:
        {"execute":"blockdev-add", "arguments":{"options":
          {"driver":"raw", "id":"a", "file":true}}}
      failed with:
        {"error": {"class": "GenericError",
          "desc": "Invalid parameter type for 'file', expected: QDict"}}
      (visit_get_next_type() succeeded, and the error comes from the
      visit_type_BlockdevOptions() expecting {}; there is no mention of
      the fact that a string would also work).  Now it fails with:
        {"error": {"class": "GenericError",
          "desc": "Invalid parameter type for 'file', expected: BlockdevRef"}}
      (the error when the next type doesn't match any expected types for
      the overall alternate).
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1449033659-25497-5-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      0426d53c
    • E
      qapi: Convert QType into QAPI built-in enum type · 7264f5c5
      Eric Blake 提交于
      What's more meta than using qapi to define qapi? :)
      
      Convert QType into a full-fledged[*] builtin qapi enum type, so
      that a subsequent patch can then use it as the discriminator
      type of qapi alternate types.  Fortunately, the judicious use of
      'prefix' in the qapi definition avoids churn to the spelling of
      the enum constants.
      
      To avoid circular definitions, we have to flip the order of
      inclusion between "qobject.h" vs. "qapi-types.h".  Back in commit
      28770e05, we had the latter include the former, so that we could
      use 'QObject *' for our implementation of 'any'.  But that usage
      also works with only a forward declaration, whereas the
      definition of QObject requires QType to be a complete type.
      
      [*] The type has to be builtin, rather than declared in
      qapi/common.json, because we want to use it for alternates even
      when common.json is not included. But since it is the first
      builtin enum type, we have to add special cases to qapi-types
      and qapi-visit to only emit definitions once, even when two
      qapi files are being compiled into the same binary (the way we
      already handled builtin list types like 'intList').  We may
      need to revisit how multiple qapi files share common types,
      but that's a project for another day.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1449033659-25497-4-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      7264f5c5
    • E
      qapi-types: Simplify gen_struct_field[s] · 7d9586f9
      Eric Blake 提交于
      Simplify gen_struct_fields() back to a single iteration over a
      list of fields (like it was prior to commit f87ab7f9), by moving
      the generated comments to gen_object().  Then, inline
      gen_struct_field() into its only caller.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1447836791-369-4-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      7d9586f9