1. 19 2月, 2016 12 次提交
    • E
      qapi-visit: Use common idiom in gen_visit_fields_decl() · 2208d649
      Eric Blake 提交于
      We have several instances of methods that do an early exit if
      output is not needed, then log that output is being generated,
      and finally produce the output; see qapi-types.py:gen_object()
      and qapi-visit.py:gen_visit_implicit_struct().  The odd man
      out was gen_visit_fields_decl(); rearrange it to be more like
      the others.  No semantic change or difference to generated code.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-12-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      2208d649
    • 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
    • E
      qapi-visit: Less indirection in visit_type_Foo_fields() · 65551903
      Eric Blake 提交于
      We were passing 'Foo **obj' to the internal helper function, but
      all uses within the helper were via reads of '*obj'.  Refactor
      things to pass one less level of indirection, by having the
      callers dereference before calling.
      
      For an example of the generated code change:
      
      |-static void visit_type_BalloonInfo_fields(Visitor *v, BalloonInfo **obj, Error **errp)
      |+static void visit_type_BalloonInfo_fields(Visitor *v, BalloonInfo *obj, Error **errp)
      | {
      |     Error *err = NULL;
      |
      |-    visit_type_int(v, "actual", &(*obj)->actual, &err);
      |+    visit_type_int(v, "actual", &obj->actual, &err);
      |     error_propagate(errp, err);
      | }
      |
      |@@ -261,7 +261,7 @@ void visit_type_BalloonInfo(Visitor *v,
      |     if (!*obj) {
      |         goto out_obj;
      |     }
      |-    visit_type_BalloonInfo_fields(v, obj, &err);
      |+    visit_type_BalloonInfo_fields(v, *obj, &err);
      | out_obj:
      
      The refactoring will also make it easier to reuse the helpers in
      a future patch when implicit structs are stored directly in the
      parent struct rather than boxed through a pointer.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-9-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      65551903
    • M
      qapi-visit: Unify struct and union visit · 59d9e84c
      Markus Armbruster 提交于
      gen_visit_union() is now just like gen_visit_struct().  Rename
      it to gen_visit_object(), use it for structs, and drop
      gen_visit_struct().  Output is unchanged.
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      Message-Id: <1453902888-20457-4-git-send-email-armbru@redhat.com>
      [split out variant handling, rebase to earlier changes]
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-8-git-send-email-eblake@redhat.com>
      59d9e84c
    • E
      qapi: Visit variants in visit_type_FOO_fields() · 9a5cd424
      Eric Blake 提交于
      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,
      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: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-7-git-send-email-eblake@redhat.com>
      [gen_visit_struct_fields() parameter variants made mandatory]
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      9a5cd424
    • M
      qapi-visit: Simplify how we visit common union members · d7445b57
      Markus Armbruster 提交于
      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 441cbac0 "qapi-visit:
      Convert to QAPISchemaVisitor, fixing bugs".  It's a step towards
      unifying gen_struct() and gen_union().
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      Message-Id: <1453902888-20457-2-git-send-email-armbru@redhat.com>
      [improve commit message examples]
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-6-git-send-email-eblake@redhat.com>
      [Commit message tweaked]
      d7445b57
    • E
      qapi: Add tests of complex objects within alternate · 68d07839
      Eric Blake 提交于
      Upcoming patches will adjust how we visit an object branch of an
      alternate; but we were completely lacking testsuite coverage.
      Rectify this, so that the future patches will be able to highlight
      the changes and still prove that we avoided regressions.
      
      In particular, the use of a flat union UserDefFlatUnion rather
      than a simple struct UserDefA as the branch will give us coverage
      of an object with variants.  And visiting an alternate as both
      the top level and as a nested member gives confidence in correct
      memory allocation handling, especially if the test is run under
      valgrind.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-5-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      68d07839
    • E
      qapi: Forbid 'any' inside an alternate · 46534309
      Eric Blake 提交于
      The whole point of an alternate is to allow some type-safety while
      still accepting more than one JSON type.  Meanwhile, the 'any'
      type exists to bypass type-safety altogether.  The two are
      incompatible: you can't accept every type, and still tell which
      branch of the alternate to use for the parse; fix this to give a
      sane error instead of a Python stack trace.
      
      Note that other types that can't be alternate members are caught
      earlier, by check_type().
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-4-git-send-email-eblake@redhat.com>
      [Commit message tweaked]
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      46534309
    • E
      qapi: Forbid empty unions and useless alternates · 02a57ae3
      Eric Blake 提交于
      Empty unions serve no purpose, and while we compile with gcc
      which permits them, strict C99 forbids them.  We happen to inject
      a dummy 'void *data' member into the C unions that represent QAPI
      unions and alternates, but we want to get rid of that member (it
      pollutes the namespace for no good reason), which would leave us
      with an empty union if the user didn't provide any branches.  While
      empty structs make sense in QAPI, empty unions don't add any
      expressiveness to the QMP language.  So prohibit them at parse
      time.  Update the documentation and testsuite to match.
      
      Note that the documentation already mentioned that alternates
      should have "two or more JSON data types"; so this also fixes
      the code to enforce that.  However, we have existing uses of a
      union type with only one branch, so the 2-or-more strictness
      is intentionally limited to alternates.
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455778109-6278-3-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      02a57ae3
    • E
      qapi: Simplify excess input reporting in input visitors · f96493b1
      Eric Blake 提交于
      When reporting that an unvisited member remains at the end of an
      input visit for a struct, we were using g_hash_table_find()
      coupled with a callback function that always returns true, to
      locate an arbitrary member of the hash table.  But if all we
      need is an arbitrary entry, we can get that from a single-use
      iterator, without needing a tautological callback function.
      
      Technically, our cast of &(GQueue *) to (void **) is not strict
      C (while void * must be able to hold all other pointers, nothing
      says a void ** has to be the same width or representation as a
      GQueue **).  The kosher way to write it would be the verbose:
      
          void *tmp;
          GQueue *any;
          if (g_hash_table_iter_next(&iter, NULL, &tmp)) {
              any = tmp;
      
      But our code base (not to mention glib itself) already has other
      cases of assuming that ALL pointers have the same width and
      representation, where a compiler would have to go out of its way
      to mis-compile our borderline behavior.
      Suggested-by: NMarkus Armbruster <armbru@redhat.com>
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Reviewed-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
      Message-Id: <1455778109-6278-2-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      f96493b1
    • E
      qapi-visit: Honor prefix of discriminator enum · 9d3524b3
      Eric Blake 提交于
      When we added support for a user-specified prefix for an enum
      type (commit 351d36e4), we forgot to teach the qapi-visit code
      to honor that prefix in the case of using a prefixed enum as
      the discriminator for a flat union.  While there is still some
      on-list debate on whether we want to keep prefixes, we should
      at least make it work as long as it is still part of the code
      base.
      Reported-by: NDaniel P. Berrange <berrange@redhat.com>
      Signed-off-by: NEric Blake <eblake@redhat.com>
      Message-Id: <1455665965-27638-1-git-send-email-eblake@redhat.com>
      Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
      9d3524b3
  2. 18 2月, 2016 28 次提交