diff mbox

[2/3] qom: reimplement Interfaces

Message ID 1339620902-4481-3-git-send-email-aliguori@us.ibm.com
State New
Headers show

Commit Message

Anthony Liguori June 13, 2012, 8:55 p.m. UTC
The current implementation of Interfaces is poorly designed.  Each interface
that an object implements end up being an object that's tracked by the
implementing object.  There's all sorts of gymnastics to deal with casting
between these objects.

By an interface shouldn't be associated with an Object.  Interfaces are global
to a class.  This patch moves all Interface knowledge to ObjectClass eliminating
the relationship between Object and Interfaces.

Interfaces are now abstract (as they should be) but this is okay.  Interfaces
essentially act as additional parents for the classes and are treated as such.

With this new implementation, we should fully support derived interfaces
including reimplementing an inherited interface.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 include/qemu/object.h |   64 +++++++++++---
 qom/object.c          |  231 +++++++++++++++++++++++-------------------------
 2 files changed, 160 insertions(+), 135 deletions(-)

Comments

Peter A. G. Crosthwaite June 16, 2012, 10:47 a.m. UTC | #1
On Wed, 2012-06-13 at 15:55 -0500, Anthony Liguori wrote:
> The current implementation of Interfaces is poorly designed.  Each interface
> that an object implements end up being an object that's tracked by the

"ends"

> implementing object.  There's all sorts of gymnastics to deal with casting
> between these objects.
> 
> By an interface shouldn't be associated with an Object.  Interfaces are global

"But" ?

> to a class.  This patch moves all Interface knowledge to ObjectClass eliminating
> the relationship between Object and Interfaces.
> 
> Interfaces are now abstract (as they should be) but this is okay.  Interfaces
> essentially act as additional parents for the classes and are treated as such.
> 
> With this new implementation, we should fully support derived interfaces
> including reimplementing an inherited interface.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
>  include/qemu/object.h |   64 +++++++++++---
>  qom/object.c          |  231 +++++++++++++++++++++++-------------------------
>  2 files changed, 160 insertions(+), 135 deletions(-)
> 
> diff --git a/include/qemu/object.h b/include/qemu/object.h
> index d93b772..72cb290 100644
> --- a/include/qemu/object.h
> +++ b/include/qemu/object.h
> @@ -239,6 +239,7 @@ struct ObjectClass
>  {
>      /*< private >*/
>      Type type;
> +    GSList *interfaces;
>  };
>  
>  /**
> @@ -260,7 +261,6 @@ struct Object
>  {
>      /*< private >*/
>      ObjectClass *class;
> -    GSList *interfaces;
>      QTAILQ_HEAD(, ObjectProperty) properties;
>      uint32_t ref;
>      Object *parent;
> @@ -381,6 +381,17 @@ struct TypeInfo
>      OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
>  
>  /**
> + * InterfaceInfo:
> + * @type: The name of the interface.
> + *
> + * The information associated with an interface.
> + */
> +struct InterfaceInfo
> +{
> +    const char *type;
> +};
> +
> +/**
>   * InterfaceClass:
>   * @parent_class: the base class
>   *
> @@ -390,26 +401,31 @@ struct TypeInfo
>  struct InterfaceClass
>  {
>      ObjectClass parent_class;
> +    /*< private >*/
> +    ObjectClass *concrete_class;
>  };
>  
> +#define TYPE_INTERFACE "interface"
> +
>  /**
> - * InterfaceInfo:
> - * @type: The name of the interface.
> - * @interface_initfn: This method is called during class initialization and is
> - *   used to initialize an interface associated with a class.  This function
> - *   should initialize any default virtual functions for a class and/or override
> - *   virtual functions in a parent class.
> + * INTERFACE_CLASS:
> + * @klass: class to cast from
>   *
> - * The information associated with an interface.
> + * Returns: An #InterfaceClass or raise an error if cast is invalid
>   */
> -struct InterfaceInfo
> -{
> -    const char *type;
> +#define INTERFACE_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
>  
> -    void (*interface_initfn)(ObjectClass *class, void *data);
> -};
> -
> -#define TYPE_INTERFACE "interface"
> +/**
> + * INTERFACE_CHECK:
> + * @interface: the type to return
> + * @obj: the object to convert to an interface
> + * @name: the interface type name
> + *
> + * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
> + */
> +#define INTERFACE_CHECK(interface, obj, name) \
> +    ((interface *)interface_dynamic_cast_assert(OBJECT((obj)), (name)))
>  
>  /**
>   * object_new:
> @@ -548,6 +564,24 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
>                                         const char *typename);
>  
>  /**
> + * interface_dynamic_cast_assert:
> + * @obj: the object to cast to an interface type
> + * @typename: the type name of the interface
> + *
> + * Returns: @obj if @obj implements @typename, otherwise raise an error
> + */
> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename);
> +
> +/**
> + * interface_dynamic_cast_assert:
> + * @obj: the object to cast to an interface type
> + * @typename: the type name of the interface
> + *
> + * Returns: @obj if @obj implements @typename, otherwise %NULL
> + */
> +Object *interface_dynamic_cast(Object *obj, const char *typename);
> +

This is where bug was introduced for links. The link setter code uses
object_dynamic_cast() which shortcuts the logic here, that is needed for
casting interfaces. The new result is you can use interface with links
cos the cast pukes.

I have proposed a solution to this in my new revision (P3) of the
axi-stream series.

Regards,
Peter

> +/**
>   * object_class_get_name:
>   * @klass: The class to obtain the QOM typename for.
>   *
> diff --git a/qom/object.c b/qom/object.c
> index 6f839ad..aa26693 100644
> --- a/qom/object.c
> +++ b/qom/object.c
> @@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
>  
>  struct InterfaceImpl
>  {
> -    const char *parent;
> -    void (*interface_initfn)(ObjectClass *class, void *data);
> -    TypeImpl *type;
> +    const char *typename;
>  };
>  
>  struct TypeImpl
> @@ -63,14 +61,6 @@ struct TypeImpl
>      InterfaceImpl interfaces[MAX_INTERFACES];
>  };
>  
> -typedef struct Interface
> -{
> -    Object parent;
> -    Object *obj;
> -} Interface;
> -
> -#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
> -
>  static Type type_interface;
>  
>  static GHashTable *type_table_get(void)
> @@ -97,6 +87,7 @@ static TypeImpl *type_table_lookup(const char *name)
>  TypeImpl *type_register(const TypeInfo *info)
>  {
>      TypeImpl *ti = g_malloc0(sizeof(*ti));
> +    int i;
>  
>      g_assert(info->name != NULL);
>  
> @@ -120,15 +111,10 @@ TypeImpl *type_register(const TypeInfo *info)
>  
>      ti->abstract = info->abstract;
>  
> -    if (info->interfaces) {
> -        int i;
> -
> -        for (i = 0; info->interfaces[i].type; i++) {
> -            ti->interfaces[i].parent = info->interfaces[i].type;
> -            ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
> -            ti->num_interfaces++;
> -        }
> +    for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
> +        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
>      }
> +    ti->num_interfaces = i;
>  
>      type_table_add(ti);
>  
> @@ -190,26 +176,48 @@ static size_t type_object_get_size(TypeImpl *ti)
>      return 0;
>  }
>  
> -static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
> +static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
>  {
> -    TypeInfo info = {
> -        .instance_size = sizeof(Interface),
> -        .parent = iface->parent,
> -        .class_size = sizeof(InterfaceClass),
> -        .class_init = iface->interface_initfn,
> -        .abstract = true,
> -    };
> -    char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
> +    assert(target_type);
> +
> +    /* Check if typename is a direct ancestor of type */
> +    while (type) {
> +        if (type == target_type) {
> +            return true;
> +        }
> +
> +        type = type_get_parent(type);
> +    }
> +
> +    return false;
> +}
> +
> +static void type_initialize(TypeImpl *ti);
> +
> +static void type_initialize_interface(TypeImpl *ti, const char *parent)
> +{
> +    InterfaceClass *new_iface;
> +    TypeInfo info = { };
> +    TypeImpl *iface_impl;
>  
> -    info.name = name;
> -    iface->type = type_register(&info);
> -    g_free(name);
> +    info.parent = parent;
> +    info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
> +    info.abstract = true;
> +
> +    iface_impl = type_register(&info);
> +    type_initialize(iface_impl);
> +    g_free((char *)info.name);
> +
> +    new_iface = (InterfaceClass *)iface_impl->class;
> +    new_iface->concrete_class = ti->class;
> +
> +    ti->class->interfaces = g_slist_append(ti->class->interfaces,
> +                                           iface_impl->class);
>  }
>  
>  static void type_initialize(TypeImpl *ti)
>  {
>      size_t class_size = sizeof(ObjectClass);
> -    int i;
>  
>      if (ti->class) {
>          return;
> @@ -221,8 +229,12 @@ static void type_initialize(TypeImpl *ti)
>      ti->class = g_malloc0(ti->class_size);
>      ti->class->type = ti;
>  
> +    ti->class->interfaces = NULL;
> +
>      if (type_has_parent(ti)) {
>          TypeImpl *parent = type_get_parent(ti);
> +        GSList *e;
> +        int i;
>  
>          type_initialize(parent);
>  
> @@ -232,42 +244,46 @@ static void type_initialize(TypeImpl *ti)
>          memcpy((void *)ti->class + sizeof(ObjectClass),
>                 (void *)parent->class + sizeof(ObjectClass),
>                 parent->class_size - sizeof(ObjectClass));
> -    }
>  
> -    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
> +        for (e = parent->class->interfaces; e; e = e->next) {
> +            ObjectClass *iface = e->data;
> +            type_initialize_interface(ti, object_class_get_name(iface));
> +        }
>  
> -    for (i = 0; i < ti->num_interfaces; i++) {
> -        type_class_interface_init(ti, &ti->interfaces[i]);
> -    }
> +        for (i = 0; i < ti->num_interfaces; i++) {
> +            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
>  
> -    if (ti->class_init) {
> -        ti->class_init(ti->class, ti->class_data);
> +            for (e = ti->class->interfaces; e; e = e->next) {
> +                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
> +
> +                if (type_is_ancestor(target_type, t)) {
> +                    break;
> +                }
> +            }
> +
> +            if (e) {
> +                continue;
> +            }
> +                
> +            type_initialize_interface(ti, ti->interfaces[i].typename);
> +        }
>      }
> -}
>  
> -static void object_interface_init(Object *obj, InterfaceImpl *iface)
> -{
> -    TypeImpl *ti = iface->type;
> -    Interface *iface_obj;
> +    /* If this type is an interface and num_interfaces, bugger out */
>  
> -    iface_obj = INTERFACE(object_new(ti->name));
> -    iface_obj->obj = obj;
> +    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
>  
> -    obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
> +    if (ti->class_init) {
> +        ti->class_init(ti->class, ti->class_data);
> +    }
>  }
>  
>  static void object_init_with_type(Object *obj, TypeImpl *ti)
>  {
> -    int i;
> -
>      if (type_has_parent(ti)) {
>          object_init_with_type(obj, type_get_parent(ti));
>      }
>  
> -    for (i = 0; i < ti->num_interfaces; i++) {
> -        object_interface_init(obj, &ti->interfaces[i]);
> -    }
> -
>      if (ti->instance_init) {
>          ti->instance_init(obj);
>      }
> @@ -338,12 +354,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
>          type->instance_finalize(obj);
>      }
>  
> -    while (obj->interfaces) {
> -        Interface *iface_obj = obj->interfaces->data;
> -        obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
> -        object_delete(OBJECT(iface_obj));
> -    }
> -
>      if (type_has_parent(type)) {
>          object_deinit(obj, type_get_parent(type));
>      }
> @@ -390,22 +400,6 @@ void object_delete(Object *obj)
>      g_free(obj);
>  }
>  
> -static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
> -{
> -    assert(target_type);
> -
> -    /* Check if typename is a direct ancestor of type */
> -    while (type) {
> -        if (type == target_type) {
> -            return true;
> -        }
> -
> -        type = type_get_parent(type);
> -    }
> -
> -    return false;
> -}
> -
>  static bool object_is_type(Object *obj, TypeImpl *target_type)
>  {
>      return !target_type || type_is_ancestor(obj->class->type, target_type);
> @@ -414,7 +408,6 @@ static bool object_is_type(Object *obj, TypeImpl *target_type)
>  Object *object_dynamic_cast(Object *obj, const char *typename)
>  {
>      TypeImpl *target_type = type_get_by_name(typename);
> -    GSList *i;
>  
>      /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
>       * we want to go back from interfaces to the parent.
> @@ -423,46 +416,18 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
>          return obj;
>      }
>  
> -    /* Check if obj is an interface and its containing object is a direct
> -     * ancestor of typename.  In principle we could do this test at the very
> -     * beginning of object_dynamic_cast, avoiding a second call to
> -     * object_is_type.  However, casting between interfaces is relatively
> -     * rare, and object_is_type(obj, type_interface) would fail almost always.
> -     *
> -     * Perhaps we could add a magic value to the object header for increased
> -     * (run-time) type safety and to speed up tests like this one.  If we ever
> -     * do that we can revisit the order here.
> -     */
> -    if (object_is_type(obj, type_interface)) {
> -        assert(!obj->interfaces);
> -        obj = INTERFACE(obj)->obj;
> -        if (object_is_type(obj, target_type)) {
> -            return obj;
> -        }
> -    }
> -
>      if (!target_type) {
>          return obj;
>      }
>  
> -    /* Check if obj has an interface of typename */
> -    for (i = obj->interfaces; i; i = i->next) {
> -        Interface *iface = i->data;
> -
> -        if (object_is_type(OBJECT(iface), target_type)) {
> -            return OBJECT(iface);
> -        }
> -    }
> -
>      return NULL;
>  }
>  
> -
>  static void register_types(void)
>  {
>      static TypeInfo interface_info = {
>          .name = TYPE_INTERFACE,
> -        .instance_size = sizeof(Interface),
> +        .class_size = sizeof(InterfaceClass),
>          .abstract = true,
>      };
>  
> @@ -491,16 +456,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
>  {
>      TypeImpl *target_type = type_get_by_name(typename);
>      TypeImpl *type = class->type;
> +    ObjectClass *ret = NULL;
>  
> -    while (type) {
> -        if (type == target_type) {
> -            return class;
> +    if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
> +        int found = 0;
> +        GSList *i;
> +
> +        for (i = class->interfaces; i; i = i->next) {
> +            ObjectClass *target_class = i->data;
> +
> +            if (type_is_ancestor(target_class->type, target_type)) {
> +                ret = target_class;
> +                found++;
> +            }
>          }
>  
> -        type = type_get_parent(type);
> +        /* The match was ambiguous, don't allow a cast */
> +        if (found > 1) {
> +            ret = NULL;
> +        }
> +    } else if (type_is_ancestor(type, target_type)) {
> +        ret = class;
>      }
>  
> -    return NULL;
> +    return ret;
>  }
>  
>  ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
> @@ -517,6 +496,28 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
>      return ret;
>  }
>  
> +Object *interface_dynamic_cast(Object *obj, const char *typename)
> +{
> +    if (object_class_dynamic_cast(object_get_class(obj), typename)) {
> +        return obj;
> +    }
> +
> +    return NULL;
> +}
> +
> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename)
> +{
> +    Object *ret = interface_dynamic_cast(obj, typename);
> +
> +    if (!ret) {
> +        fprintf(stderr, "Object %p is not an instance of type %s\n",
> +                obj, typename);
> +        abort();
> +    }
> +
> +    return ret;
> +}
> +
>  const char *object_get_typename(Object *obj)
>  {
>      return obj->class->type->name;
> @@ -883,12 +884,6 @@ void object_property_add_child(Object *obj, const char *name,
>  {
>      gchar *type;
>  
> -    /* Registering an interface object in the composition tree will mightily
> -     * confuse object_get_canonical_path (which, on the other hand, knows how
> -     * to get the canonical path of an interface object).
> -     */
> -    assert(!object_is_type(obj, type_interface));
> -
>      type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
>  
>      object_property_add(obj, name, type, object_get_child_property,
> @@ -985,10 +980,6 @@ gchar *object_get_canonical_path(Object *obj)
>      Object *root = object_get_root();
>      char *newpath = NULL, *path = NULL;
>  
> -    if (object_is_type(obj, type_interface)) {
> -        obj = INTERFACE(obj)->obj;
> -    }
> -
>      while (obj != root) {
>          ObjectProperty *prop = NULL;
>
Peter A. G. Crosthwaite June 22, 2012, 11:29 a.m. UTC | #2
Hi Anthony,

With the latest qom-next merge, this fails to rebase with non-trivial
conflicts. Do you have a rebased version of this floating around in
one of your trees somewhere? We are trying to get our machine models
as QOMified as we can, especially the axi-stream stuff. I will also be
able to put some --tested-by to this stuff with the microblaze machine
model. Let me know if/how I can help.

Regards,
Peter

On Sat, Jun 16, 2012 at 8:47 PM, Peter Crosthwaite
<peter.crosthwaite@petalogix.com> wrote:
> On Wed, 2012-06-13 at 15:55 -0500, Anthony Liguori wrote:
>> The current implementation of Interfaces is poorly designed.  Each interface
>> that an object implements end up being an object that's tracked by the
>
> "ends"
>
>> implementing object.  There's all sorts of gymnastics to deal with casting
>> between these objects.
>>
>> By an interface shouldn't be associated with an Object.  Interfaces are global
>
> "But" ?
>
>> to a class.  This patch moves all Interface knowledge to ObjectClass eliminating
>> the relationship between Object and Interfaces.
>>
>> Interfaces are now abstract (as they should be) but this is okay.  Interfaces
>> essentially act as additional parents for the classes and are treated as such.
>>
>> With this new implementation, we should fully support derived interfaces
>> including reimplementing an inherited interface.
>>
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> ---
>>  include/qemu/object.h |   64 +++++++++++---
>>  qom/object.c          |  231 +++++++++++++++++++++++-------------------------
>>  2 files changed, 160 insertions(+), 135 deletions(-)
>>
>> diff --git a/include/qemu/object.h b/include/qemu/object.h
>> index d93b772..72cb290 100644
>> --- a/include/qemu/object.h
>> +++ b/include/qemu/object.h
>> @@ -239,6 +239,7 @@ struct ObjectClass
>>  {
>>      /*< private >*/
>>      Type type;
>> +    GSList *interfaces;
>>  };
>>
>>  /**
>> @@ -260,7 +261,6 @@ struct Object
>>  {
>>      /*< private >*/
>>      ObjectClass *class;
>> -    GSList *interfaces;
>>      QTAILQ_HEAD(, ObjectProperty) properties;
>>      uint32_t ref;
>>      Object *parent;
>> @@ -381,6 +381,17 @@ struct TypeInfo
>>      OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
>>
>>  /**
>> + * InterfaceInfo:
>> + * @type: The name of the interface.
>> + *
>> + * The information associated with an interface.
>> + */
>> +struct InterfaceInfo
>> +{
>> +    const char *type;
>> +};
>> +
>> +/**
>>   * InterfaceClass:
>>   * @parent_class: the base class
>>   *
>> @@ -390,26 +401,31 @@ struct TypeInfo
>>  struct InterfaceClass
>>  {
>>      ObjectClass parent_class;
>> +    /*< private >*/
>> +    ObjectClass *concrete_class;
>>  };
>>
>> +#define TYPE_INTERFACE "interface"
>> +
>>  /**
>> - * InterfaceInfo:
>> - * @type: The name of the interface.
>> - * @interface_initfn: This method is called during class initialization and is
>> - *   used to initialize an interface associated with a class.  This function
>> - *   should initialize any default virtual functions for a class and/or override
>> - *   virtual functions in a parent class.
>> + * INTERFACE_CLASS:
>> + * @klass: class to cast from
>>   *
>> - * The information associated with an interface.
>> + * Returns: An #InterfaceClass or raise an error if cast is invalid
>>   */
>> -struct InterfaceInfo
>> -{
>> -    const char *type;
>> +#define INTERFACE_CLASS(klass) \
>> +    OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
>>
>> -    void (*interface_initfn)(ObjectClass *class, void *data);
>> -};
>> -
>> -#define TYPE_INTERFACE "interface"
>> +/**
>> + * INTERFACE_CHECK:
>> + * @interface: the type to return
>> + * @obj: the object to convert to an interface
>> + * @name: the interface type name
>> + *
>> + * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
>> + */
>> +#define INTERFACE_CHECK(interface, obj, name) \
>> +    ((interface *)interface_dynamic_cast_assert(OBJECT((obj)), (name)))
>>
>>  /**
>>   * object_new:
>> @@ -548,6 +564,24 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
>>                                         const char *typename);
>>
>>  /**
>> + * interface_dynamic_cast_assert:
>> + * @obj: the object to cast to an interface type
>> + * @typename: the type name of the interface
>> + *
>> + * Returns: @obj if @obj implements @typename, otherwise raise an error
>> + */
>> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename);
>> +
>> +/**
>> + * interface_dynamic_cast_assert:
>> + * @obj: the object to cast to an interface type
>> + * @typename: the type name of the interface
>> + *
>> + * Returns: @obj if @obj implements @typename, otherwise %NULL
>> + */
>> +Object *interface_dynamic_cast(Object *obj, const char *typename);
>> +
>
> This is where bug was introduced for links. The link setter code uses
> object_dynamic_cast() which shortcuts the logic here, that is needed for
> casting interfaces. The new result is you can use interface with links
> cos the cast pukes.
>
> I have proposed a solution to this in my new revision (P3) of the
> axi-stream series.
>
> Regards,
> Peter
>
>> +/**
>>   * object_class_get_name:
>>   * @klass: The class to obtain the QOM typename for.
>>   *
>> diff --git a/qom/object.c b/qom/object.c
>> index 6f839ad..aa26693 100644
>> --- a/qom/object.c
>> +++ b/qom/object.c
>> @@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
>>
>>  struct InterfaceImpl
>>  {
>> -    const char *parent;
>> -    void (*interface_initfn)(ObjectClass *class, void *data);
>> -    TypeImpl *type;
>> +    const char *typename;
>>  };
>>
>>  struct TypeImpl
>> @@ -63,14 +61,6 @@ struct TypeImpl
>>      InterfaceImpl interfaces[MAX_INTERFACES];
>>  };
>>
>> -typedef struct Interface
>> -{
>> -    Object parent;
>> -    Object *obj;
>> -} Interface;
>> -
>> -#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
>> -
>>  static Type type_interface;
>>
>>  static GHashTable *type_table_get(void)
>> @@ -97,6 +87,7 @@ static TypeImpl *type_table_lookup(const char *name)
>>  TypeImpl *type_register(const TypeInfo *info)
>>  {
>>      TypeImpl *ti = g_malloc0(sizeof(*ti));
>> +    int i;
>>
>>      g_assert(info->name != NULL);
>>
>> @@ -120,15 +111,10 @@ TypeImpl *type_register(const TypeInfo *info)
>>
>>      ti->abstract = info->abstract;
>>
>> -    if (info->interfaces) {
>> -        int i;
>> -
>> -        for (i = 0; info->interfaces[i].type; i++) {
>> -            ti->interfaces[i].parent = info->interfaces[i].type;
>> -            ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
>> -            ti->num_interfaces++;
>> -        }
>> +    for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
>> +        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
>>      }
>> +    ti->num_interfaces = i;
>>
>>      type_table_add(ti);
>>
>> @@ -190,26 +176,48 @@ static size_t type_object_get_size(TypeImpl *ti)
>>      return 0;
>>  }
>>
>> -static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
>> +static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
>>  {
>> -    TypeInfo info = {
>> -        .instance_size = sizeof(Interface),
>> -        .parent = iface->parent,
>> -        .class_size = sizeof(InterfaceClass),
>> -        .class_init = iface->interface_initfn,
>> -        .abstract = true,
>> -    };
>> -    char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
>> +    assert(target_type);
>> +
>> +    /* Check if typename is a direct ancestor of type */
>> +    while (type) {
>> +        if (type == target_type) {
>> +            return true;
>> +        }
>> +
>> +        type = type_get_parent(type);
>> +    }
>> +
>> +    return false;
>> +}
>> +
>> +static void type_initialize(TypeImpl *ti);
>> +
>> +static void type_initialize_interface(TypeImpl *ti, const char *parent)
>> +{
>> +    InterfaceClass *new_iface;
>> +    TypeInfo info = { };
>> +    TypeImpl *iface_impl;
>>
>> -    info.name = name;
>> -    iface->type = type_register(&info);
>> -    g_free(name);
>> +    info.parent = parent;
>> +    info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
>> +    info.abstract = true;
>> +
>> +    iface_impl = type_register(&info);
>> +    type_initialize(iface_impl);
>> +    g_free((char *)info.name);
>> +
>> +    new_iface = (InterfaceClass *)iface_impl->class;
>> +    new_iface->concrete_class = ti->class;
>> +
>> +    ti->class->interfaces = g_slist_append(ti->class->interfaces,
>> +                                           iface_impl->class);
>>  }
>>
>>  static void type_initialize(TypeImpl *ti)
>>  {
>>      size_t class_size = sizeof(ObjectClass);
>> -    int i;
>>
>>      if (ti->class) {
>>          return;
>> @@ -221,8 +229,12 @@ static void type_initialize(TypeImpl *ti)
>>      ti->class = g_malloc0(ti->class_size);
>>      ti->class->type = ti;
>>
>> +    ti->class->interfaces = NULL;
>> +
>>      if (type_has_parent(ti)) {
>>          TypeImpl *parent = type_get_parent(ti);
>> +        GSList *e;
>> +        int i;
>>
>>          type_initialize(parent);
>>
>> @@ -232,42 +244,46 @@ static void type_initialize(TypeImpl *ti)
>>          memcpy((void *)ti->class + sizeof(ObjectClass),
>>                 (void *)parent->class + sizeof(ObjectClass),
>>                 parent->class_size - sizeof(ObjectClass));
>> -    }
>>
>> -    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
>> +        for (e = parent->class->interfaces; e; e = e->next) {
>> +            ObjectClass *iface = e->data;
>> +            type_initialize_interface(ti, object_class_get_name(iface));
>> +        }
>>
>> -    for (i = 0; i < ti->num_interfaces; i++) {
>> -        type_class_interface_init(ti, &ti->interfaces[i]);
>> -    }
>> +        for (i = 0; i < ti->num_interfaces; i++) {
>> +            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
>>
>> -    if (ti->class_init) {
>> -        ti->class_init(ti->class, ti->class_data);
>> +            for (e = ti->class->interfaces; e; e = e->next) {
>> +                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
>> +
>> +                if (type_is_ancestor(target_type, t)) {
>> +                    break;
>> +                }
>> +            }
>> +
>> +            if (e) {
>> +                continue;
>> +            }
>> +
>> +            type_initialize_interface(ti, ti->interfaces[i].typename);
>> +        }
>>      }
>> -}
>>
>> -static void object_interface_init(Object *obj, InterfaceImpl *iface)
>> -{
>> -    TypeImpl *ti = iface->type;
>> -    Interface *iface_obj;
>> +    /* If this type is an interface and num_interfaces, bugger out */
>>
>> -    iface_obj = INTERFACE(object_new(ti->name));
>> -    iface_obj->obj = obj;
>> +    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
>>
>> -    obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
>> +    if (ti->class_init) {
>> +        ti->class_init(ti->class, ti->class_data);
>> +    }
>>  }
>>
>>  static void object_init_with_type(Object *obj, TypeImpl *ti)
>>  {
>> -    int i;
>> -
>>      if (type_has_parent(ti)) {
>>          object_init_with_type(obj, type_get_parent(ti));
>>      }
>>
>> -    for (i = 0; i < ti->num_interfaces; i++) {
>> -        object_interface_init(obj, &ti->interfaces[i]);
>> -    }
>> -
>>      if (ti->instance_init) {
>>          ti->instance_init(obj);
>>      }
>> @@ -338,12 +354,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
>>          type->instance_finalize(obj);
>>      }
>>
>> -    while (obj->interfaces) {
>> -        Interface *iface_obj = obj->interfaces->data;
>> -        obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
>> -        object_delete(OBJECT(iface_obj));
>> -    }
>> -
>>      if (type_has_parent(type)) {
>>          object_deinit(obj, type_get_parent(type));
>>      }
>> @@ -390,22 +400,6 @@ void object_delete(Object *obj)
>>      g_free(obj);
>>  }
>>
>> -static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
>> -{
>> -    assert(target_type);
>> -
>> -    /* Check if typename is a direct ancestor of type */
>> -    while (type) {
>> -        if (type == target_type) {
>> -            return true;
>> -        }
>> -
>> -        type = type_get_parent(type);
>> -    }
>> -
>> -    return false;
>> -}
>> -
>>  static bool object_is_type(Object *obj, TypeImpl *target_type)
>>  {
>>      return !target_type || type_is_ancestor(obj->class->type, target_type);
>> @@ -414,7 +408,6 @@ static bool object_is_type(Object *obj, TypeImpl *target_type)
>>  Object *object_dynamic_cast(Object *obj, const char *typename)
>>  {
>>      TypeImpl *target_type = type_get_by_name(typename);
>> -    GSList *i;
>>
>>      /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
>>       * we want to go back from interfaces to the parent.
>> @@ -423,46 +416,18 @@ Object *object_dynamic_cast(Object *obj, const char *typename)
>>          return obj;
>>      }
>>
>> -    /* Check if obj is an interface and its containing object is a direct
>> -     * ancestor of typename.  In principle we could do this test at the very
>> -     * beginning of object_dynamic_cast, avoiding a second call to
>> -     * object_is_type.  However, casting between interfaces is relatively
>> -     * rare, and object_is_type(obj, type_interface) would fail almost always.
>> -     *
>> -     * Perhaps we could add a magic value to the object header for increased
>> -     * (run-time) type safety and to speed up tests like this one.  If we ever
>> -     * do that we can revisit the order here.
>> -     */
>> -    if (object_is_type(obj, type_interface)) {
>> -        assert(!obj->interfaces);
>> -        obj = INTERFACE(obj)->obj;
>> -        if (object_is_type(obj, target_type)) {
>> -            return obj;
>> -        }
>> -    }
>> -
>>      if (!target_type) {
>>          return obj;
>>      }
>>
>> -    /* Check if obj has an interface of typename */
>> -    for (i = obj->interfaces; i; i = i->next) {
>> -        Interface *iface = i->data;
>> -
>> -        if (object_is_type(OBJECT(iface), target_type)) {
>> -            return OBJECT(iface);
>> -        }
>> -    }
>> -
>>      return NULL;
>>  }
>>
>> -
>>  static void register_types(void)
>>  {
>>      static TypeInfo interface_info = {
>>          .name = TYPE_INTERFACE,
>> -        .instance_size = sizeof(Interface),
>> +        .class_size = sizeof(InterfaceClass),
>>          .abstract = true,
>>      };
>>
>> @@ -491,16 +456,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
>>  {
>>      TypeImpl *target_type = type_get_by_name(typename);
>>      TypeImpl *type = class->type;
>> +    ObjectClass *ret = NULL;
>>
>> -    while (type) {
>> -        if (type == target_type) {
>> -            return class;
>> +    if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
>> +        int found = 0;
>> +        GSList *i;
>> +
>> +        for (i = class->interfaces; i; i = i->next) {
>> +            ObjectClass *target_class = i->data;
>> +
>> +            if (type_is_ancestor(target_class->type, target_type)) {
>> +                ret = target_class;
>> +                found++;
>> +            }
>>          }
>>
>> -        type = type_get_parent(type);
>> +        /* The match was ambiguous, don't allow a cast */
>> +        if (found > 1) {
>> +            ret = NULL;
>> +        }
>> +    } else if (type_is_ancestor(type, target_type)) {
>> +        ret = class;
>>      }
>>
>> -    return NULL;
>> +    return ret;
>>  }
>>
>>  ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
>> @@ -517,6 +496,28 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
>>      return ret;
>>  }
>>
>> +Object *interface_dynamic_cast(Object *obj, const char *typename)
>> +{
>> +    if (object_class_dynamic_cast(object_get_class(obj), typename)) {
>> +        return obj;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +Object *interface_dynamic_cast_assert(Object *obj, const char *typename)
>> +{
>> +    Object *ret = interface_dynamic_cast(obj, typename);
>> +
>> +    if (!ret) {
>> +        fprintf(stderr, "Object %p is not an instance of type %s\n",
>> +                obj, typename);
>> +        abort();
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>>  const char *object_get_typename(Object *obj)
>>  {
>>      return obj->class->type->name;
>> @@ -883,12 +884,6 @@ void object_property_add_child(Object *obj, const char *name,
>>  {
>>      gchar *type;
>>
>> -    /* Registering an interface object in the composition tree will mightily
>> -     * confuse object_get_canonical_path (which, on the other hand, knows how
>> -     * to get the canonical path of an interface object).
>> -     */
>> -    assert(!object_is_type(obj, type_interface));
>> -
>>      type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
>>
>>      object_property_add(obj, name, type, object_get_child_property,
>> @@ -985,10 +980,6 @@ gchar *object_get_canonical_path(Object *obj)
>>      Object *root = object_get_root();
>>      char *newpath = NULL, *path = NULL;
>>
>> -    if (object_is_type(obj, type_interface)) {
>> -        obj = INTERFACE(obj)->obj;
>> -    }
>> -
>>      while (obj != root) {
>>          ObjectProperty *prop = NULL;
>>
>
>
diff mbox

Patch

diff --git a/include/qemu/object.h b/include/qemu/object.h
index d93b772..72cb290 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -239,6 +239,7 @@  struct ObjectClass
 {
     /*< private >*/
     Type type;
+    GSList *interfaces;
 };
 
 /**
@@ -260,7 +261,6 @@  struct Object
 {
     /*< private >*/
     ObjectClass *class;
-    GSList *interfaces;
     QTAILQ_HEAD(, ObjectProperty) properties;
     uint32_t ref;
     Object *parent;
@@ -381,6 +381,17 @@  struct TypeInfo
     OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
 
 /**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+    const char *type;
+};
+
+/**
  * InterfaceClass:
  * @parent_class: the base class
  *
@@ -390,26 +401,31 @@  struct TypeInfo
 struct InterfaceClass
 {
     ObjectClass parent_class;
+    /*< private >*/
+    ObjectClass *concrete_class;
 };
 
+#define TYPE_INTERFACE "interface"
+
 /**
- * InterfaceInfo:
- * @type: The name of the interface.
- * @interface_initfn: This method is called during class initialization and is
- *   used to initialize an interface associated with a class.  This function
- *   should initialize any default virtual functions for a class and/or override
- *   virtual functions in a parent class.
+ * INTERFACE_CLASS:
+ * @klass: class to cast from
  *
- * The information associated with an interface.
+ * Returns: An #InterfaceClass or raise an error if cast is invalid
  */
-struct InterfaceInfo
-{
-    const char *type;
+#define INTERFACE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
 
-    void (*interface_initfn)(ObjectClass *class, void *data);
-};
-
-#define TYPE_INTERFACE "interface"
+/**
+ * INTERFACE_CHECK:
+ * @interface: the type to return
+ * @obj: the object to convert to an interface
+ * @name: the interface type name
+ *
+ * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
+ */
+#define INTERFACE_CHECK(interface, obj, name) \
+    ((interface *)interface_dynamic_cast_assert(OBJECT((obj)), (name)))
 
 /**
  * object_new:
@@ -548,6 +564,24 @@  ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
                                        const char *typename);
 
 /**
+ * interface_dynamic_cast_assert:
+ * @obj: the object to cast to an interface type
+ * @typename: the type name of the interface
+ *
+ * Returns: @obj if @obj implements @typename, otherwise raise an error
+ */
+Object *interface_dynamic_cast_assert(Object *obj, const char *typename);
+
+/**
+ * interface_dynamic_cast_assert:
+ * @obj: the object to cast to an interface type
+ * @typename: the type name of the interface
+ *
+ * Returns: @obj if @obj implements @typename, otherwise %NULL
+ */
+Object *interface_dynamic_cast(Object *obj, const char *typename);
+
+/**
  * object_class_get_name:
  * @klass: The class to obtain the QOM typename for.
  *
diff --git a/qom/object.c b/qom/object.c
index 6f839ad..aa26693 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -31,9 +31,7 @@  typedef struct TypeImpl TypeImpl;
 
 struct InterfaceImpl
 {
-    const char *parent;
-    void (*interface_initfn)(ObjectClass *class, void *data);
-    TypeImpl *type;
+    const char *typename;
 };
 
 struct TypeImpl
@@ -63,14 +61,6 @@  struct TypeImpl
     InterfaceImpl interfaces[MAX_INTERFACES];
 };
 
-typedef struct Interface
-{
-    Object parent;
-    Object *obj;
-} Interface;
-
-#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
-
 static Type type_interface;
 
 static GHashTable *type_table_get(void)
@@ -97,6 +87,7 @@  static TypeImpl *type_table_lookup(const char *name)
 TypeImpl *type_register(const TypeInfo *info)
 {
     TypeImpl *ti = g_malloc0(sizeof(*ti));
+    int i;
 
     g_assert(info->name != NULL);
 
@@ -120,15 +111,10 @@  TypeImpl *type_register(const TypeInfo *info)
 
     ti->abstract = info->abstract;
 
-    if (info->interfaces) {
-        int i;
-
-        for (i = 0; info->interfaces[i].type; i++) {
-            ti->interfaces[i].parent = info->interfaces[i].type;
-            ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
-            ti->num_interfaces++;
-        }
+    for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
+        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
     }
+    ti->num_interfaces = i;
 
     type_table_add(ti);
 
@@ -190,26 +176,48 @@  static size_t type_object_get_size(TypeImpl *ti)
     return 0;
 }
 
-static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
 {
-    TypeInfo info = {
-        .instance_size = sizeof(Interface),
-        .parent = iface->parent,
-        .class_size = sizeof(InterfaceClass),
-        .class_init = iface->interface_initfn,
-        .abstract = true,
-    };
-    char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+    assert(target_type);
+
+    /* Check if typename is a direct ancestor of type */
+    while (type) {
+        if (type == target_type) {
+            return true;
+        }
+
+        type = type_get_parent(type);
+    }
+
+    return false;
+}
+
+static void type_initialize(TypeImpl *ti);
+
+static void type_initialize_interface(TypeImpl *ti, const char *parent)
+{
+    InterfaceClass *new_iface;
+    TypeInfo info = { };
+    TypeImpl *iface_impl;
 
-    info.name = name;
-    iface->type = type_register(&info);
-    g_free(name);
+    info.parent = parent;
+    info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
+    info.abstract = true;
+
+    iface_impl = type_register(&info);
+    type_initialize(iface_impl);
+    g_free((char *)info.name);
+
+    new_iface = (InterfaceClass *)iface_impl->class;
+    new_iface->concrete_class = ti->class;
+
+    ti->class->interfaces = g_slist_append(ti->class->interfaces,
+                                           iface_impl->class);
 }
 
 static void type_initialize(TypeImpl *ti)
 {
     size_t class_size = sizeof(ObjectClass);
-    int i;
 
     if (ti->class) {
         return;
@@ -221,8 +229,12 @@  static void type_initialize(TypeImpl *ti)
     ti->class = g_malloc0(ti->class_size);
     ti->class->type = ti;
 
+    ti->class->interfaces = NULL;
+
     if (type_has_parent(ti)) {
         TypeImpl *parent = type_get_parent(ti);
+        GSList *e;
+        int i;
 
         type_initialize(parent);
 
@@ -232,42 +244,46 @@  static void type_initialize(TypeImpl *ti)
         memcpy((void *)ti->class + sizeof(ObjectClass),
                (void *)parent->class + sizeof(ObjectClass),
                parent->class_size - sizeof(ObjectClass));
-    }
 
-    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
+        for (e = parent->class->interfaces; e; e = e->next) {
+            ObjectClass *iface = e->data;
+            type_initialize_interface(ti, object_class_get_name(iface));
+        }
 
-    for (i = 0; i < ti->num_interfaces; i++) {
-        type_class_interface_init(ti, &ti->interfaces[i]);
-    }
+        for (i = 0; i < ti->num_interfaces; i++) {
+            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
 
-    if (ti->class_init) {
-        ti->class_init(ti->class, ti->class_data);
+            for (e = ti->class->interfaces; e; e = e->next) {
+                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
+
+                if (type_is_ancestor(target_type, t)) {
+                    break;
+                }
+            }
+
+            if (e) {
+                continue;
+            }
+                
+            type_initialize_interface(ti, ti->interfaces[i].typename);
+        }
     }
-}
 
-static void object_interface_init(Object *obj, InterfaceImpl *iface)
-{
-    TypeImpl *ti = iface->type;
-    Interface *iface_obj;
+    /* If this type is an interface and num_interfaces, bugger out */
 
-    iface_obj = INTERFACE(object_new(ti->name));
-    iface_obj->obj = obj;
+    memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
 
-    obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+    if (ti->class_init) {
+        ti->class_init(ti->class, ti->class_data);
+    }
 }
 
 static void object_init_with_type(Object *obj, TypeImpl *ti)
 {
-    int i;
-
     if (type_has_parent(ti)) {
         object_init_with_type(obj, type_get_parent(ti));
     }
 
-    for (i = 0; i < ti->num_interfaces; i++) {
-        object_interface_init(obj, &ti->interfaces[i]);
-    }
-
     if (ti->instance_init) {
         ti->instance_init(obj);
     }
@@ -338,12 +354,6 @@  static void object_deinit(Object *obj, TypeImpl *type)
         type->instance_finalize(obj);
     }
 
-    while (obj->interfaces) {
-        Interface *iface_obj = obj->interfaces->data;
-        obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
-        object_delete(OBJECT(iface_obj));
-    }
-
     if (type_has_parent(type)) {
         object_deinit(obj, type_get_parent(type));
     }
@@ -390,22 +400,6 @@  void object_delete(Object *obj)
     g_free(obj);
 }
 
-static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
-{
-    assert(target_type);
-
-    /* Check if typename is a direct ancestor of type */
-    while (type) {
-        if (type == target_type) {
-            return true;
-        }
-
-        type = type_get_parent(type);
-    }
-
-    return false;
-}
-
 static bool object_is_type(Object *obj, TypeImpl *target_type)
 {
     return !target_type || type_is_ancestor(obj->class->type, target_type);
@@ -414,7 +408,6 @@  static bool object_is_type(Object *obj, TypeImpl *target_type)
 Object *object_dynamic_cast(Object *obj, const char *typename)
 {
     TypeImpl *target_type = type_get_by_name(typename);
-    GSList *i;
 
     /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
      * we want to go back from interfaces to the parent.
@@ -423,46 +416,18 @@  Object *object_dynamic_cast(Object *obj, const char *typename)
         return obj;
     }
 
-    /* Check if obj is an interface and its containing object is a direct
-     * ancestor of typename.  In principle we could do this test at the very
-     * beginning of object_dynamic_cast, avoiding a second call to
-     * object_is_type.  However, casting between interfaces is relatively
-     * rare, and object_is_type(obj, type_interface) would fail almost always.
-     *
-     * Perhaps we could add a magic value to the object header for increased
-     * (run-time) type safety and to speed up tests like this one.  If we ever
-     * do that we can revisit the order here.
-     */
-    if (object_is_type(obj, type_interface)) {
-        assert(!obj->interfaces);
-        obj = INTERFACE(obj)->obj;
-        if (object_is_type(obj, target_type)) {
-            return obj;
-        }
-    }
-
     if (!target_type) {
         return obj;
     }
 
-    /* Check if obj has an interface of typename */
-    for (i = obj->interfaces; i; i = i->next) {
-        Interface *iface = i->data;
-
-        if (object_is_type(OBJECT(iface), target_type)) {
-            return OBJECT(iface);
-        }
-    }
-
     return NULL;
 }
 
-
 static void register_types(void)
 {
     static TypeInfo interface_info = {
         .name = TYPE_INTERFACE,
-        .instance_size = sizeof(Interface),
+        .class_size = sizeof(InterfaceClass),
         .abstract = true,
     };
 
@@ -491,16 +456,30 @@  ObjectClass *object_class_dynamic_cast(ObjectClass *class,
 {
     TypeImpl *target_type = type_get_by_name(typename);
     TypeImpl *type = class->type;
+    ObjectClass *ret = NULL;
 
-    while (type) {
-        if (type == target_type) {
-            return class;
+    if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+        int found = 0;
+        GSList *i;
+
+        for (i = class->interfaces; i; i = i->next) {
+            ObjectClass *target_class = i->data;
+
+            if (type_is_ancestor(target_class->type, target_type)) {
+                ret = target_class;
+                found++;
+            }
         }
 
-        type = type_get_parent(type);
+        /* The match was ambiguous, don't allow a cast */
+        if (found > 1) {
+            ret = NULL;
+        }
+    } else if (type_is_ancestor(type, target_type)) {
+        ret = class;
     }
 
-    return NULL;
+    return ret;
 }
 
 ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
@@ -517,6 +496,28 @@  ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
     return ret;
 }
 
+Object *interface_dynamic_cast(Object *obj, const char *typename)
+{
+    if (object_class_dynamic_cast(object_get_class(obj), typename)) {
+        return obj;
+    }
+
+    return NULL;
+}
+
+Object *interface_dynamic_cast_assert(Object *obj, const char *typename)
+{
+    Object *ret = interface_dynamic_cast(obj, typename);
+
+    if (!ret) {
+        fprintf(stderr, "Object %p is not an instance of type %s\n",
+                obj, typename);
+        abort();
+    }
+
+    return ret;
+}
+
 const char *object_get_typename(Object *obj)
 {
     return obj->class->type->name;
@@ -883,12 +884,6 @@  void object_property_add_child(Object *obj, const char *name,
 {
     gchar *type;
 
-    /* Registering an interface object in the composition tree will mightily
-     * confuse object_get_canonical_path (which, on the other hand, knows how
-     * to get the canonical path of an interface object).
-     */
-    assert(!object_is_type(obj, type_interface));
-
     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
     object_property_add(obj, name, type, object_get_child_property,
@@ -985,10 +980,6 @@  gchar *object_get_canonical_path(Object *obj)
     Object *root = object_get_root();
     char *newpath = NULL, *path = NULL;
 
-    if (object_is_type(obj, type_interface)) {
-        obj = INTERFACE(obj)->obj;
-    }
-
     while (obj != root) {
         ObjectProperty *prop = NULL;