type_table maps each name to a TypeBucket of TypeImpl variants and
the union of their target masks. Registration aborts when the new
mask overlaps a variant already in the bucket, so same-name types
for disjoint targets can coexist.

Bare-name lookup, class enumeration, and parent, interface, and
dynamic cast resolution walk that bucket. Enumeration and bare-name
lookup keep a variant when target_mask_filter() of its mask is
non-empty. With no target selected, bare-name lookup returns the
variant only when the bucket holds one.

type_list_lookup() returns those variants. need == 0 does not
require any architecture bits. Any other need keeps the variant
whose mask contains every bit of need, which is at most one.
type_lookup_current() passes 0 and returns that variant only when
one remains. type_table_lookup() passes the class mask for parent,
interface, and dynamic cast resolution.

Signed-off-by: Yonggang Luo <[email protected]>
---
 qom/object.c | 107 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 85 insertions(+), 22 deletions(-)

diff --git a/qom/object.c b/qom/object.c
index c224263112..265cf19041 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -19,6 +19,7 @@
 #include "qemu/base-arch-defs.h"
 #include "qemu/target-info.h"
 #include "qemu/memalign.h"
+#include "qemu/queue.h"
 #include "qapi/visitor.h"
 #include "qapi/string-input-visitor.h"
 #include "qapi/string-output-visitor.h"
@@ -74,6 +75,7 @@ struct TypeImpl
     bool secure;
 
     uint64_t targets;
+    QSLIST_ENTRY(TypeImpl) next;
 
     const char *parent;
     TypeImpl *parent_type;
@@ -84,6 +86,11 @@ struct TypeImpl
     InterfaceImpl interfaces[MAX_INTERFACES];
 };
 
+typedef struct TypeBucket {
+    uint64_t targets;
+    QSLIST_HEAD(, TypeImpl) variants;
+} TypeBucket;
+
 static Type type_interface;
 
 static GHashTable *type_table;
@@ -113,15 +120,56 @@ static uint64_t target_mask_filter(uint64_t mask)
     return mask & target_mask_selected();
 }
 
-static void type_table_add(TypeImpl *ti)
+static void type_table_add(TypeBucket *bucket, TypeImpl *ti)
 {
     assert(!enumerating_types);
-    g_hash_table_insert(type_table, (void *)ti->name, ti);
+    if (!bucket) {
+        bucket = g_new0(TypeBucket, 1);
+        g_hash_table_insert(type_table, (void *)ti->name, bucket);
+    }
+    bucket->targets |= ti->targets;
+    QSLIST_INSERT_HEAD(&bucket->variants, ti, next);
+}
+
+static GSList *type_list_lookup(const char *name, uint64_t need)
+{
+    TypeBucket *bucket;
+    TypeImpl *ti;
+    GSList *list = NULL;
+
+    if (!name) {
+        return NULL;
+    }
+    bucket = g_hash_table_lookup(type_table, name);
+    if (!bucket) {
+        return NULL;
+    }
+    QSLIST_FOREACH(ti, &bucket->variants, next) {
+        if (!target_mask_filter(ti->targets)) {
+            continue;
+        }
+        /* need == 0 keeps all variants; any other need matches at most one 
mask. */
+        if ((ti->targets & need) != need) {
+            continue;
+        }
+        list = g_slist_append(list, ti);
+    }
+    return list;
+}
+
+static TypeImpl *type_table_lookup(const char *name, uint64_t need)
+{
+    g_autoptr(GSList) list;
+
+    g_assert(need != 0);
+    list = type_list_lookup(name, need);
+    return list ? list->data : NULL;
 }
 
-static TypeImpl *type_table_lookup(const char *name)
+static TypeImpl *type_lookup_current(const char *name)
 {
-    return g_hash_table_lookup(type_table, name);
+    g_autoptr(GSList) list = type_list_lookup(name, 0);
+    return g_slist_length(list) == 1 ? list->data : NULL;
 }
 
 static TypeImpl *type_new(const TypeInfo *info, uint64_t targets)
@@ -131,11 +179,6 @@ static TypeImpl *type_new(const TypeInfo *info, uint64_t 
targets)
 
     g_assert(info->name != NULL);
 
-    if (type_table_lookup(info->name) != NULL) {
-        fprintf(stderr, "Registering `%s' which already exists\n", info->name);
-        abort();
-    }
-
     ti->name = g_strdup(info->name);
     ti->parent = g_strdup(info->parent);
 
@@ -188,6 +231,7 @@ static bool type_name_is_valid(const char *name)
 
 static TypeImpl *type_register_internal(const TypeInfo *info, uint64_t targets)
 {
+    TypeBucket *bucket;
     TypeImpl *ti;
 
     if (!type_name_is_valid(info->name)) {
@@ -212,9 +256,15 @@ static TypeImpl *type_register_internal(const TypeInfo 
*info, uint64_t targets)
         return NULL;
     }
 
+    bucket = g_hash_table_lookup(type_table, info->name);
+    if (bucket && (bucket->targets & targets)) {
+        fprintf(stderr, "Registering '%s' which already exists\n", info->name);
+        abort();
+    }
+
     ti = type_new(info, targets);
 
-    type_table_add(ti);
+    type_table_add(bucket, ti);
     return ti;
 }
 
@@ -233,24 +283,24 @@ void type_register_static_array(const TypeInfo *infos, 
int nr_infos)
     }
 }
 
-static TypeImpl *type_get_by_name_noload(const char *name)
+static TypeImpl *type_get_by_name_noload(const char *name, uint64_t need)
 {
     if (name == NULL) {
         return NULL;
     }
 
-    return type_table_lookup(name);
+    return type_table_lookup(name, need);
 }
 
 static TypeImpl *type_get_or_load_by_name(const char *name, Error **errp)
 {
-    TypeImpl *type = type_get_by_name_noload(name);
+    TypeImpl *type = type_lookup_current(name);
 
 #ifdef CONFIG_MODULES
     if (!type) {
         int rv = module_load_qom(name, errp);
         if (rv > 0) {
-            type = type_get_by_name_noload(name);
+            type = type_lookup_current(name);
         } else {
             error_prepend(errp, "could not load a module for type '%s'", name);
             return NULL;
@@ -267,7 +317,7 @@ static TypeImpl *type_get_or_load_by_name(const char *name, 
Error **errp)
 static TypeImpl *type_get_parent(TypeImpl *type)
 {
     if (!type->parent_type && type->parent) {
-        type->parent_type = type_get_by_name_noload(type->parent);
+        type->parent_type = type_get_by_name_noload(type->parent, 
type->targets);
         if (!type->parent_type) {
             fprintf(stderr, "Type '%s' is missing its parent '%s'\n",
                     type->name, type->parent);
@@ -422,7 +472,7 @@ static void type_initialize(TypeImpl *ti)
         }
 
         for (i = 0; i < ti->num_interfaces; i++) {
-            TypeImpl *t = type_get_by_name_noload(ti->interfaces[i].typename);
+            TypeImpl *t = type_get_by_name_noload(ti->interfaces[i].typename, 
ti->targets);
             if (!t) {
                 error_report("missing interface '%s' for object '%s'",
                              ti->interfaces[i].typename, parent->name);
@@ -1097,7 +1147,7 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
         return class;
     }
 
-    target_type = type_get_by_name_noload(typename);
+    target_type = type_get_by_name_noload(typename, type->targets);
     if (!target_type) {
         /* target class type unknown, so fail the cast */
         return NULL;
@@ -1201,7 +1251,7 @@ const char *object_class_get_name(ObjectClass *klass)
 
 ObjectClass *object_class_by_name(const char *typename)
 {
-    TypeImpl *type = type_get_by_name_noload(typename);
+    TypeImpl *type = type_lookup_current(typename);
 
     if (!type) {
         return NULL;
@@ -1246,13 +1296,14 @@ typedef struct OCFData
     void *opaque;
 } OCFData;
 
-static void object_class_foreach_tramp(gpointer key, gpointer value,
-                                       gpointer opaque)
+static void object_class_foreach_type(TypeImpl *type, OCFData *data)
 {
-    OCFData *data = opaque;
-    TypeImpl *type = value;
     ObjectClass *k;
 
+    if (!target_mask_filter(type->targets)) {
+        return;
+    }
+
     type_initialize(type);
     k = type->class;
 
@@ -1268,6 +1319,18 @@ static void object_class_foreach_tramp(gpointer key, 
gpointer value,
     data->fn(k, data->opaque);
 }
 
+static void object_class_foreach_tramp(gpointer key, gpointer value,
+                                       gpointer opaque)
+{
+    OCFData *data = opaque;
+    TypeBucket *bucket = value;
+    TypeImpl *type;
+
+    QSLIST_FOREACH(type, &bucket->variants, next) {
+        object_class_foreach_type(type, data);
+    }
+}
+
 void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
                           const char *implements_type, bool include_abstract,
                           void *opaque)
-- 
2.55.0.windows.3


Reply via email to