From e9666e4455365cd3cbe5a20c88c2e51be1776597 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 19 Feb 2018 21:45:54 -0500 Subject: [PATCH] qapi: Convert QType into QAPI built-in enum type 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 28770e0, 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. Backports commit 7264f5c50cc1be0f1406e3ebb45aedcca02f603a from qemu --- msvc/unicorn/qapi-types.c | 14 +++++++++++- msvc/unicorn/qapi-types.h | 39 +++++++++++++++++++++++---------- msvc/unicorn/qapi-visit.c | 9 ++++++-- msvc/unicorn/qapi-visit.h | 3 ++- qemu/include/qapi/qmp/qobject.h | 22 +++++-------------- qemu/include/qemu/typedefs.h | 1 + qemu/qobject/qobject.c | 4 ++-- qemu/scripts/qapi-types.py | 16 ++++++++++---- qemu/scripts/qapi-visit.py | 12 ++++++++-- qemu/scripts/qapi.py | 6 +++++ 10 files changed, 85 insertions(+), 41 deletions(-) diff --git a/msvc/unicorn/qapi-types.c b/msvc/unicorn/qapi-types.c index d6fb6547..8fd39252 100644 --- a/msvc/unicorn/qapi-types.c +++ b/msvc/unicorn/qapi-types.c @@ -18,7 +18,7 @@ #include "qapi-types.h" #include "qapi-visit.h" -const char *const ErrorClass_lookup[] = { +const char *const QapiErrorClass_lookup[] = { "GenericError", "CommandNotFound", "DeviceEncrypted", @@ -55,6 +55,18 @@ void qapi_free_DummyForceArrays(DummyForceArrays *obj) qapi_dealloc_visitor_cleanup(qdv); } +const char *const QType_lookup[] = { + "none", + "qnull", + "qint", + "qstring", + "qdict", + "qlist", + "qfloat", + "qbool", + NULL, +}; + void qapi_free_X86CPUFeatureWordInfo(X86CPUFeatureWordInfo *obj) { QapiDeallocVisitor *qdv; diff --git a/msvc/unicorn/qapi-types.h b/msvc/unicorn/qapi-types.h index 438ba7c8..008af453 100644 --- a/msvc/unicorn/qapi-types.h +++ b/msvc/unicorn/qapi-types.h @@ -16,13 +16,26 @@ #ifndef QAPI_TYPES_H #define QAPI_TYPES_H -#include "qapi/qmp/qobject.h" +#include "qemu/typedefs.h" #include "unicorn/platform.h" #ifndef QAPI_TYPES_BUILTIN #define QAPI_TYPES_BUILTIN +typedef enum QType { + QTYPE_NONE = 0, + QTYPE_QNULL = 1, + QTYPE_QINT = 2, + QTYPE_QSTRING = 3, + QTYPE_QDICT = 4, + QTYPE_QLIST = 5, + QTYPE_QFLOAT = 6, + QTYPE_QBOOL = 7, + QTYPE__MAX = 8, +} QType; +extern const char *const QType_lookup[]; + typedef struct anyList anyList; struct anyList { union { @@ -168,16 +181,16 @@ void qapi_free_uint8List(uint8List *obj); typedef struct DummyForceArrays DummyForceArrays; -typedef enum ErrorClass { - ERROR_CLASS_GENERIC_ERROR = 0, - ERROR_CLASS_COMMAND_NOT_FOUND = 1, - ERROR_CLASS_DEVICE_ENCRYPTED = 2, - ERROR_CLASS_DEVICE_NOT_ACTIVE = 3, - ERROR_CLASS_DEVICE_NOT_FOUND = 4, - ERROR_CLASS_KVM_MISSING_CAP = 5, - ERROR_CLASS_MAX = 6, -} ErrorClass; -extern const char *const ErrorClass_lookup[]; +typedef enum QapiErrorClass { + QAPI_ERROR_CLASS_GENERICERROR = 0, + QAPI_ERROR_CLASS_COMMANDNOTFOUND = 1, + QAPI_ERROR_CLASS_DEVICEENCRYPTED = 2, + QAPI_ERROR_CLASS_DEVICENOTACTIVE = 3, + QAPI_ERROR_CLASS_DEVICENOTFOUND = 4, + QAPI_ERROR_CLASS_KVMMISSINGCAP = 5, + QAPI_ERROR_CLASS__MAX = 6, +} QapiErrorClass; +extern const char *const QapiErrorClass_lookup[]; typedef struct X86CPUFeatureWordInfo X86CPUFeatureWordInfo; @@ -192,13 +205,15 @@ typedef enum X86CPURegister32 { X86_CPU_REGISTER32_EBP = 5, X86_CPU_REGISTER32_ESI = 6, X86_CPU_REGISTER32_EDI = 7, - X86_CPU_REGISTER32_MAX = 8, + X86_CPU_REGISTER32__MAX = 8, } X86CPURegister32; extern const char *const X86CPURegister32_lookup[]; + struct DummyForceArrays { X86CPUFeatureWordInfoList *unused; }; void qapi_free_DummyForceArrays(DummyForceArrays *obj); + struct X86CPUFeatureWordInfo { int64_t cpuid_input_eax; bool has_cpuid_input_ecx; diff --git a/msvc/unicorn/qapi-visit.c b/msvc/unicorn/qapi-visit.c index e0a9b043..3d15115c 100644 --- a/msvc/unicorn/qapi-visit.c +++ b/msvc/unicorn/qapi-visit.c @@ -44,9 +44,14 @@ void visit_type_DummyForceArrays(Visitor *v, DummyForceArrays **obj, const char error_propagate(errp, err); } -void visit_type_ErrorClass(Visitor *v, ErrorClass *obj, const char *name, Error **errp) +void visit_type_QType(Visitor *v, QType *obj, const char *name, Error **errp) { - visit_type_enum(v, (int *)obj, ErrorClass_lookup, "ErrorClass", name, errp); + visit_type_enum(v, (int *)obj, QType_lookup, "QType", name, errp); +} + +void visit_type_QapiErrorClass(Visitor *v, QapiErrorClass *obj, const char *name, Error **errp) +{ + visit_type_enum(v, (int *)obj, QapiErrorClass_lookup, "QapiErrorClass", name, errp); } static void visit_type_X86CPUFeatureWordInfo_fields(Visitor *v, X86CPUFeatureWordInfo **obj, Error **errp) diff --git a/msvc/unicorn/qapi-visit.h b/msvc/unicorn/qapi-visit.h index 8179e61e..f7bba48b 100644 --- a/msvc/unicorn/qapi-visit.h +++ b/msvc/unicorn/qapi-visit.h @@ -23,6 +23,7 @@ #ifndef QAPI_VISIT_BUILTIN #define QAPI_VISIT_BUILTIN +void visit_type_QType(Visitor *v, QType *obj, const char *name, Error **errp); void visit_type_anyList(Visitor *v, anyList **obj, const char *name, Error **errp); void visit_type_boolList(Visitor *v, boolList **obj, const char *name, Error **errp); void visit_type_int16List(Visitor *v, int16List **obj, const char *name, Error **errp); @@ -41,7 +42,7 @@ void visit_type_uint8List(Visitor *v, uint8List **obj, const char *name, Error * #endif /* QAPI_VISIT_BUILTIN */ void visit_type_DummyForceArrays(Visitor *v, DummyForceArrays **obj, const char *name, Error **errp); -void visit_type_ErrorClass(Visitor *v, ErrorClass *obj, const char *name, Error **errp); +void visit_type_QapiErrorClass(Visitor *v, QapiErrorClass *obj, const char *name, Error **errp); void visit_type_X86CPUFeatureWordInfo(Visitor *v, X86CPUFeatureWordInfo **obj, const char *name, Error **errp); void visit_type_X86CPUFeatureWordInfoList(Visitor *v, X86CPUFeatureWordInfoList **obj, const char *name, Error **errp); void visit_type_X86CPURegister32(Visitor *v, X86CPURegister32 *obj, const char *name, Error **errp); diff --git a/qemu/include/qapi/qmp/qobject.h b/qemu/include/qapi/qmp/qobject.h index ce85c906..2b0bd995 100644 --- a/qemu/include/qapi/qmp/qobject.h +++ b/qemu/include/qapi/qmp/qobject.h @@ -34,24 +34,12 @@ #include #include +#include "qapi-types.h" -typedef enum { - QTYPE_NONE, - QTYPE_QNULL, - QTYPE_QINT, - QTYPE_QSTRING, - QTYPE_QDICT, - QTYPE_QLIST, - QTYPE_QFLOAT, - QTYPE_QBOOL, - QTYPE_QERROR, - QTYPE_MAX, -} QType; - -typedef struct QObject { +struct QObject { QType type; size_t refcnt; -} QObject; +}; /* Objects definitions must include this */ #define QObject_HEAD \ @@ -71,7 +59,7 @@ typedef struct QObject { /* Initialize an object to default values */ static inline void qobject_init(QObject *obj, QType type) { - assert(QTYPE_NONE < type && type < QTYPE_MAX); + assert(QTYPE_NONE < type && type < QTYPE__MAX); obj->refcnt = 1; obj->type = type; } @@ -107,7 +95,7 @@ static inline void qobject_decref(QObject *obj) */ static inline QType qobject_type(const QObject *obj) { - assert(QTYPE_NONE < obj->type && obj->type < QTYPE_MAX); + assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX); return obj->type; } diff --git a/qemu/include/qemu/typedefs.h b/qemu/include/qemu/typedefs.h index c9cad003..aa1b70a7 100644 --- a/qemu/include/qemu/typedefs.h +++ b/qemu/include/qemu/typedefs.h @@ -66,6 +66,7 @@ typedef struct QEMUSizedBuffer QEMUSizedBuffer; typedef struct QEMUTimer QEMUTimer; typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QemuConsole QemuConsole; +typedef struct QObject QObject; typedef struct RAMBlock RAMBlock; typedef struct Range Range; typedef struct SHPCDevice SHPCDevice; diff --git a/qemu/qobject/qobject.c b/qemu/qobject/qobject.c index 1a6845e3..8e1c3ec4 100644 --- a/qemu/qobject/qobject.c +++ b/qemu/qobject/qobject.c @@ -15,7 +15,7 @@ #include "qapi/qmp/qlist.h" #include "qapi/qmp/qstring.h" -static void (*qdestroy[QTYPE_MAX])(QObject *) = { +static void (*qdestroy[QTYPE__MAX])(QObject *) = { NULL, /* No such object exists */ NULL, /* qnull_ is indestructible */ qint_destroy_obj, @@ -29,6 +29,6 @@ static void (*qdestroy[QTYPE_MAX])(QObject *) = { void qobject_destroy(QObject *obj) { assert(!obj->refcnt); - assert(QTYPE_QNULL < obj->type && obj->type < QTYPE_MAX); + assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX); qdestroy[obj->type](obj); } diff --git a/qemu/scripts/qapi-types.py b/qemu/scripts/qapi-types.py index 0fe34e20..81977630 100644 --- a/qemu/scripts/qapi-types.py +++ b/qemu/scripts/qapi-types.py @@ -111,7 +111,7 @@ extern const int %(c_name)s_qtypes[]; def gen_alternate_qtypes(name, variants): ret = mcgen(''' -const int %(c_name)s_qtypes[QTYPE_MAX] = { +const int %(c_name)s_qtypes[QTYPE__MAX] = { ''', c_name=c_name(name)) @@ -232,8 +232,15 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self.defn += gen_type_cleanup(name) def visit_enum_type(self, name, info, values, prefix): - self._fwdecl += gen_enum(name, values, prefix) - self._fwdefn += gen_enum_lookup(name, values, prefix) + # Special case for our lone builtin enum type + # TODO use something cleaner than existence of info + if not info: + self._btin += gen_enum(name, values, prefix) + if do_builtins: + self.defn += gen_enum_lookup(name, values, prefix) + else: + self._fwdecl += gen_enum(name, values, prefix) + self._fwdefn += gen_enum_lookup(name, values, prefix) def visit_array_type(self, name, info, element_type): if isinstance(element_type, QAPISchemaBuiltinType): @@ -314,8 +321,9 @@ fdef.write(mcgen(''' ''', prefix=prefix)) +# To avoid circular headers, use only typedefs.h here, not qobject.h fdecl.write(mcgen(''' -#include "qapi/qmp/qobject.h" +#include "qemu/typedefs.h" #include "unicorn/platform.h" ''')) diff --git a/qemu/scripts/qapi-visit.py b/qemu/scripts/qapi-visit.py index 16026e78..233c9fcb 100644 --- a/qemu/scripts/qapi-visit.py +++ b/qemu/scripts/qapi-visit.py @@ -345,8 +345,16 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): isinstance(entity, QAPISchemaObjectType)) def visit_enum_type(self, name, info, values, prefix): - self.decl += gen_visit_decl(name, scalar=True) - self.defn += gen_visit_enum(name) + # Special case for our lone builtin enum type + # TODO use something cleaner than existence of info + if not info: + self._btin += gen_visit_decl(name, scalar=True) + if do_builtins: + self.defn += gen_visit_enum(name) + else: + self.decl += gen_visit_decl(name, scalar=True) + self.defn += gen_visit_enum(name) + def visit_array_type(self, name, info, element_type): decl = gen_visit_decl(name) diff --git a/qemu/scripts/qapi.py b/qemu/scripts/qapi.py index a2acf89a..9b3fdef0 100644 --- a/qemu/scripts/qapi.py +++ b/qemu/scripts/qapi.py @@ -34,6 +34,7 @@ builtin_types = { 'uint64': 'QTYPE_QINT', 'size': 'QTYPE_QINT', 'any': None, # any QType possible, actually + 'QType': 'QTYPE_QSTRING', } # Whitelist of commands allowed to return a non-dictionary @@ -1245,6 +1246,11 @@ class QAPISchema(object): self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None, [], None) self._def_entity(self.the_empty_object_type) + self._def_entity(QAPISchemaEnumType('QType', None, + ['none', 'qnull', 'qint', + 'qstring', 'qdict', 'qlist', + 'qfloat', 'qbool'], + 'QTYPE')) def _make_implicit_enum_type(self, name, info, values): name = name + 'Kind' # Use namespace reserved by add_name()