From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: armbru@redhat.com, Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PATCH v6 05/16] qapi: Emit implicit structs in generated C
Date: Thu, 17 Mar 2016 16:48:30 -0600 [thread overview]
Message-ID: <1458254921-17042-6-git-send-email-eblake@redhat.com> (raw)
In-Reply-To: <1458254921-17042-1-git-send-email-eblake@redhat.com>
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: Eric Blake <eblake@redhat.com>
---
v6: tweak commit message, drop visit_needed() altogether
v5: rebase onto different naming scheme, document future improvements
v4: new patch
---
scripts/qapi.py | 2 --
scripts/qapi-types.py | 19 +++++++++++--------
scripts/qapi-visit.py | 23 +++++++++++------------
3 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index f6701f5..96fb216 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1000,7 +1000,6 @@ class QAPISchemaObjectType(QAPISchemaType):
return self.name.startswith('q_')
def c_name(self):
- assert not self.is_implicit()
return QAPISchemaType.c_name(self)
def c_type(self):
@@ -1008,7 +1007,6 @@ class QAPISchemaObjectType(QAPISchemaType):
return c_name(self.name) + pointer_suffix
def c_unboxed_type(self):
- assert not self.is_implicit()
return c_name(self.name)
def json_type(self):
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index f194bea..79416b2 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -61,8 +61,7 @@ def gen_object(name, base, members, variants):
ret = ''
if variants:
for v in variants.variants:
- if (isinstance(v.type, QAPISchemaObjectType) and
- not v.type.is_implicit()):
+ if isinstance(v.type, QAPISchemaObjectType):
ret += gen_object(v.type.name, v.type.base,
v.type.local_members, v.type.variants)
@@ -180,6 +179,8 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self._btin = None
def visit_begin(self, schema):
+ # gen_object() is recursive, ensure it doesn't visit the empty type
+ objects_seen.add(schema.the_empty_object_type.name)
self.decl = ''
self.defn = ''
self._fwdecl = ''
@@ -196,11 +197,6 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.decl = self._btin + self.decl
self._btin = None
- def visit_needed(self, entity):
- # Visit everything except implicit objects
- return not (entity.is_implicit() and
- isinstance(entity, QAPISchemaObjectType))
-
def _gen_type_cleanup(self, name):
self.decl += gen_type_cleanup_decl(name)
self.defn += gen_type_cleanup(name)
@@ -229,11 +225,18 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self._gen_type_cleanup(name)
def visit_object_type(self, name, info, base, members, variants):
+ # Nothing to do for the special empty builtin
+ if name == 'q_empty':
+ return
self._fwdecl += gen_fwd_object_or_array(name)
self.decl += gen_object(name, base, members, variants)
if base:
self.decl += gen_upcast(name, base)
- self._gen_type_cleanup(name)
+ # TODO Worth changing the visitor signature, so we could
+ # directly use rather than repeat type.is_implicit()?
+ if not name.startswith('q_'):
+ # implicit types won't be directly allocated/freed
+ self._gen_type_cleanup(name)
def visit_alternate_type(self, name, info, variants):
self._fwdecl += gen_fwd_object_or_array(name)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index a712e9a..4923b2e 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -215,13 +215,11 @@ out:
def gen_visit_object(name, base, members, variants):
- ret = gen_visit_object_members(name, base, members, variants)
-
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
# *obj, but then visit_type_FOO_members() fails, we should clean up *obj
# rather than leaving it non-NULL. As currently written, the caller must
# call qapi_free_FOO() to avoid a memory leak of the partial FOO.
- ret += mcgen('''
+ return mcgen('''
void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
{
@@ -245,8 +243,6 @@ out:
''',
c_name=c_name(name))
- return ret
-
class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def __init__(self):
@@ -268,11 +264,6 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
self.decl = self._btin + self.decl
self._btin = None
- def visit_needed(self, entity):
- # Visit everything except implicit objects
- return not (entity.is_implicit() and
- isinstance(entity, QAPISchemaObjectType))
-
def visit_enum_type(self, name, info, values, prefix):
# Special case for our lone builtin enum type
# TODO use something cleaner than existence of info
@@ -296,9 +287,17 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
self.defn += defn
def visit_object_type(self, name, info, base, members, variants):
+ # Nothing to do for the special empty builtin
+ if name == 'q_empty':
+ return
self.decl += gen_visit_members_decl(name)
- self.decl += gen_visit_decl(name)
- self.defn += gen_visit_object(name, base, members, variants)
+ self.defn += gen_visit_object_members(name, base, members, variants)
+ # TODO Worth changing the visitor signature, so we could
+ # directly use rather than repeat type.is_implicit()?
+ if not name.startswith('q_'):
+ # only explicit types need an allocating visit
+ self.decl += gen_visit_decl(name)
+ self.defn += gen_visit_object(name, base, members, variants)
def visit_alternate_type(self, name, info, variants):
self.decl += gen_visit_decl(name)
--
2.5.0
next prev parent reply other threads:[~2016-03-17 22:48 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-17 22:48 [Qemu-devel] [PATCH v6 00/16] easier unboxed visits/qapi implicit types Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 01/16] qapi: Assert in places where variants are not handled Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 02/16] qapi: Fix command with named empty argument type Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 03/16] qapi: Make c_type() more OO-like Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 04/16] qapi: Adjust names of implicit types Eric Blake
2016-03-17 22:48 ` Eric Blake [this message]
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 06/16] qapi-event: Drop qmp_output_get_qobject() null check Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 07/16] qapi-event: Utilize implicit struct visits Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 08/16] qapi-commands: " Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 09/16] qapi-commands: Inline single-use helpers of gen_marshal() Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 10/16] qapi: Inline gen_visit_members() into lone caller Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 11/16] qapi: Drop unused c_null() Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 12/16] qapi: Don't special-case simple union wrappers Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 13/16] qapi: Make BlockdevOptions doc example closer to reality Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 14/16] qapi: Allow anonymous base for flat union Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 15/16] qapi: Use anonymous bases in QMP flat unions Eric Blake
2016-03-17 22:48 ` [Qemu-devel] [PATCH v6 16/16] qapi: Consolidate object visitors Eric Blake
2016-03-18 7:47 ` Markus Armbruster
2016-03-18 10:01 ` [Qemu-devel] [PATCH v6 00/16] easier unboxed visits/qapi implicit types Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1458254921-17042-6-git-send-email-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=armbru@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).