From 1a9a507b2e3e90aa719c96b4c092e7fad7215f21 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Sep 2015 13:06:29 +0200 Subject: [PATCH] qapi-introspect: Hide type names To eliminate the temptation for clients to look up types by name (which are not ABI), replace all type names by meaningless strings. Reduces output of query-schema by 13 out of 85KiB. As a debugging aid, provide option -u to suppress the hiding. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1442401589-24189-27-git-send-email-armbru@redhat.com> --- docs/qapi-code-gen.txt | 36 +++++++++++++++++------------------- qapi/introspect.json | 12 ++++-------- scripts/qapi-introspect.py | 41 +++++++++++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index f321d4b949..b1c8361d22 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -530,13 +530,16 @@ additional variant members depending on the value of meta-type. Each SchemaInfo object describes a wire ABI entity of a certain meta-type: a command, event or one of several kinds of type. -SchemaInfo for entities defined in the QAPI schema have the same name -as in the schema. This is the case for all commands and events, and -most types. +SchemaInfo for commands and events have the same name as in the QAPI +schema. Command and event names are part of the wire ABI, but type names are -not. Therefore, looking up a type by its name in the QAPI schema is -wrong. Look up the command or event, then follow references by name. +not. Therefore, the SchemaInfo for types have auto-generated +meaningless names. For readability, the examples in this section use +meaningful type names instead. + +To examine a type, start with a command or event using it, then follow +references by name. QAPI schema definitions not reachable that way are omitted. @@ -567,8 +570,7 @@ object type without members. The event may not have a data member on the wire then. Each command or event defined with dictionary-valued 'data' in the -QAPI schema implicitly defines an object type called ":obj-NAME-arg", -where NAME is the command or event's name. +QAPI schema implicitly defines an object type. Example: the SchemaInfo for EVENT_C from section Events @@ -623,12 +625,9 @@ Note that base types are "flattened": its members are included in the A simple union implicitly defines an enumeration type for its implicit discriminator (called "type" on the wire, see section Union types). -Such a type's name is made by appending "Kind" to the simple union's -name. A simple union implicitly defines an object type for each of its -variants. The type's name is ":obj-NAME-wrapper", where NAME is the -name of the name of the variant's type. +variants. Example: the SchemaInfo for simple union BlockdevOptions from section Union types @@ -659,8 +658,7 @@ Example: the SchemaInfo for BlockRef from section Alternate types The SchemaInfo for an array type has meta-type "array", and variant member "element-type", which names the array's element type. Array -types are implicitly defined. An array type's name is made by -appending "List" to its element type's name. +types are implicitly defined. Example: the SchemaInfo for ['str'] @@ -1067,13 +1065,13 @@ Example: [Uninteresting stuff omitted...] const char example_qmp_schema_json[] = "[" - "{\"arg-type\": \":empty\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, " + "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, " + "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, " + "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, " + "{\"members\": [{\"name\": \"arg1\", \"type\": \"2\"}], \"meta-type\": \"object\", \"name\": \"1\"}, " + "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, " "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, " - "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}, " - "{\"members\": [], \"meta-type\": \"object\", \"name\": \":empty\"}, " - "{\"members\": [{\"name\": \"arg1\", \"type\": \"UserDefOne\"}], \"meta-type\": \"object\", \"name\": \":obj-my-command-arg\"}, " - "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"UserDefOne\"}, " - "{\"arg-type\": \":obj-my-command-arg\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"UserDefOne\"}]"; + "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]"; $ cat qapi-generated/example-qmp-introspect.h [Uninteresting stuff omitted...] diff --git a/qapi/introspect.json b/qapi/introspect.json index 9c8ad53d7a..cc50dc6bcb 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -75,17 +75,13 @@ # @SchemaInfo # # @name: the entity's name, inherited from @base. -# Entities defined in the QAPI schema have the name defined in -# the schema. Implicitly defined entities have generated -# names. See docs/qapi-code-gen.txt section "Client JSON -# Protocol introspection" for details. +# Commands and events have the name defined in the QAPI schema. +# Unlike command and event names, type names are not part of +# the wire ABI. Consequently, type names are meaningless +# strings here. # # All references to other SchemaInfo are by name. # -# Command and event names are part of the wire ABI, but type names are -# not. Therefore, looking up a type by "well-known" name is wrong. -# Look up the command or event, then follow the references. -# # @meta-type: the entity's meta type, inherited from @base. # # Additional members depend on the value of @meta-type. diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py index 831d6d5944..7d39320174 100644 --- a/scripts/qapi-introspect.py +++ b/scripts/qapi-introspect.py @@ -40,32 +40,37 @@ def to_c_string(string): class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor): - def __init__(self): + def __init__(self, unmask): + self._unmask = unmask self.defn = None self.decl = None self._schema = None self._jsons = None self._used_types = None + self._name_map = None def visit_begin(self, schema): self._schema = schema self._jsons = [] self._used_types = [] + self._name_map = {} return QAPISchemaType # don't visit types for now def visit_end(self): # visit the types that are actually used + jsons = self._jsons + self._jsons = [] for typ in self._used_types: typ.visit(self) - self._jsons.sort() # generate C # TODO can generate awfully long lines + jsons.extend(self._jsons) name = prefix + 'qmp_schema_json' self.decl = mcgen(''' extern const char %(c_name)s[]; ''', c_name=c_name(name)) - lines = to_json(self._jsons).split('\n') + lines = to_json(jsons).split('\n') c_string = '\n '.join([to_c_string(line) for line in lines]) self.defn = mcgen(''' const char %(c_name)s[] = %(c_string)s; @@ -75,6 +80,14 @@ const char %(c_name)s[] = %(c_string)s; self._schema = None self._jsons = None self._used_types = None + self._name_map = None + + def _name(self, name): + if self._unmask: + return name + if name not in self._name_map: + self._name_map[name] = '%d' % len(self._name_map) + return self._name_map[name] def _use_type(self, typ): # Map the various integer types to plain int @@ -86,9 +99,16 @@ const char %(c_name)s[] = %(c_string)s; # Add type to work queue if new if typ not in self._used_types: self._used_types.append(typ) - return typ.name + # Clients should examine commands and events, not types. Hide + # type names to reduce the temptation. Also saves a few + # characters. + if isinstance(typ, QAPISchemaBuiltinType): + return typ.name + return self._name(typ.name) def _gen_json(self, name, mtype, obj): + if mtype != 'command' and mtype != 'event' and mtype != 'builtin': + name = self._name(name) obj['name'] = name obj['meta-type'] = mtype self._jsons.append(obj) @@ -140,7 +160,16 @@ const char %(c_name)s[] = %(c_string)s; arg_type = arg_type or self._schema.the_empty_object_type self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)}) -(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() +# Debugging aid: unmask QAPI schema's type names +# We normally mask them, because they're not QMP wire ABI +opt_unmask = False + +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("u", ["unmask-non-abi-names"]) + +for o, a in opts: + if o in ("-u", "--unmask-non-abi-names"): + opt_unmask = True c_comment = ''' /* @@ -176,7 +205,7 @@ fdef.write(mcgen(''' prefix=prefix)) schema = QAPISchema(input_file) -gen = QAPISchemaGenIntrospectVisitor() +gen = QAPISchemaGenIntrospectVisitor(opt_unmask) schema.visit(gen) fdef.write(gen.defn) fdecl.write(gen.decl) -- 2.11.4.GIT