Bug 557383 - Virtual method support

Broadly speaking, this change adds the concept of <vfunc> to the .gir.
The typelib already had most of the infrastructure for virtual functions,
though there is one API addition.

The scanner assumes that any class callback slot that doesn't match
a signal name is a virtual.  In the .gir, we write out *both* the <method>
wrapper and a <vfunc>.  If we can determine an association between
them (based on the names matching, or a new Virtual: annotation),
then we notate that in the .gir.

The typelib gains an association from the vfunc to the function, if
it exists.  This will be useful for bindings since they already know
how to consume FunctionInfo.
This commit is contained in:
Colin Walters 2009-02-27 19:02:48 -05:00
parent cd845500a5
commit 7299c89fc9
6 changed files with 170 additions and 4 deletions

116
ginfo.c
View File

@ -1527,6 +1527,63 @@ g_object_info_get_vfunc (GIObjectInfo *info,
base->typelib, offset);
}
static GIVFuncInfo *
find_vfunc (GIBaseInfo *base,
guint32 offset,
gint n_vfuncs,
const gchar *name)
{
/* FIXME hash */
Header *header = (Header *)base->typelib->data;
gint i;
for (i = 0; i < n_vfuncs; i++)
{
VFuncBlob *fblob = (VFuncBlob *)&base->typelib->data[offset];
const gchar *fname = (const gchar *)&base->typelib->data[fblob->name];
if (strcmp (name, fname) == 0)
return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base,
base->typelib, offset);
offset += header->vfunc_blob_size;
}
return NULL;
}
/**
* g_object_info_find_vfunc:
* @info: An #GIObjectInfo
* @name: The name of a virtual function to find.
*
* Locate a virtual function slot with name @name. Note that the namespace
* for virtuals is distinct from that of methods; there may or may not be
* a concrete method associated for a virtual. If there is one, it may
* be retrieved using #g_vfunc_info_get_invoker. See the documentation for
* that function for more information on invoking virtuals.
*
* Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
*/
GIVFuncInfo *
g_object_info_find_vfunc (GIObjectInfo *info,
const gchar *name)
{
gint offset;
GIBaseInfo *base = (GIBaseInfo *)info;
Header *header = (Header *)base->typelib->data;
ObjectBlob *blob = (ObjectBlob *)&base->typelib->data[base->offset];
offset = base->offset + header->object_blob_size
+ (blob->n_interfaces + blob->n_interfaces % 2) * 2
+ blob->n_fields * header->field_blob_size
+ blob->n_properties * header->property_blob_size
+ blob->n_methods * header->function_blob_size
+ blob->n_signals * header->signal_blob_size;
return find_vfunc (base, offset, blob->n_vfuncs, name);
}
gint
g_object_info_get_n_constants (GIObjectInfo *info)
{
@ -1728,6 +1785,34 @@ g_interface_info_get_vfunc (GIInterfaceInfo *info,
base->typelib, offset);
}
/**
* g_interface_info_find_vfunc:
* @info: An #GIObjectInfo
* @name: The name of a virtual function to find.
*
* Locate a virtual function slot with name @name. See the documentation
* for #g_object_info_find_vfunc for more information on virtuals.
*
* Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
*/
GIVFuncInfo *
g_interface_info_find_vfunc (GIInterfaceInfo *info,
const gchar *name)
{
gint offset;
GIBaseInfo *base = (GIBaseInfo *)info;
Header *header = (Header *)base->typelib->data;
InterfaceBlob *blob = (InterfaceBlob *)&base->typelib->data[base->offset];
offset = base->offset + header->interface_blob_size
+ (blob->n_prerequisites + blob->n_prerequisites % 2) * 2
+ blob->n_properties * header->property_blob_size
+ blob->n_methods * header->function_blob_size
+ blob->n_signals * header->signal_blob_size;
return find_vfunc (base, offset, blob->n_vfuncs, name);
}
gint
g_interface_info_get_n_constants (GIInterfaceInfo *info)
{
@ -1913,6 +1998,37 @@ g_vfunc_info_get_signal (GIVFuncInfo *info)
return NULL;
}
/**
* g_vfunc_info_get_invoker:
* @info: A #GIVFuncInfo
*
* If this virtual function has an associated invoker method, this
* method will return it. An invoker method is a C entry point.
*
* Not all virtuals will have invokers.
*
* Return value: (transfer full): An invoker function, or %NULL if none known
*/
GIFunctionInfo *
g_vfunc_info_get_invoker (GIVFuncInfo *info)
{
GIBaseInfo *base = (GIBaseInfo *)info;
VFuncBlob *blob = (VFuncBlob *)&base->typelib->data[base->offset];
GIBaseInfo *container = base->container;
GIInfoType parent_type;
/* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */
if (blob->invoker == 1023)
return NULL;
parent_type = g_base_info_get_type (container);
if (parent_type == GI_INFO_TYPE_OBJECT)
return g_object_info_get_method ((GIObjectInfo*)container, blob->invoker);
else if (parent_type == GI_INFO_TYPE_INTERFACE)
return g_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker);
else
g_assert_not_reached ();
}
/* GIConstantInfo functions */
GITypeInfo *

View File

@ -470,6 +470,8 @@ GISignalInfo * g_object_info_get_signal (GIObjectInfo *in
gint g_object_info_get_n_vfuncs (GIObjectInfo *info);
GIVFuncInfo * g_object_info_get_vfunc (GIObjectInfo *info,
gint n);
GIVFuncInfo * g_object_info_find_vfunc (GIObjectInfo *info,
const gchar *name);
gint g_object_info_get_n_constants (GIObjectInfo *info);
GIConstantInfo * g_object_info_get_constant (GIObjectInfo *info,
gint n);
@ -495,6 +497,8 @@ GISignalInfo * g_interface_info_get_signal (GIInterfaceInfo *in
gint g_interface_info_get_n_vfuncs (GIInterfaceInfo *info);
GIVFuncInfo * g_interface_info_get_vfunc (GIInterfaceInfo *info,
gint n);
GIVFuncInfo * g_interface_info_find_vfunc (GIInterfaceInfo *info,
const gchar *name);
gint g_interface_info_get_n_constants (GIInterfaceInfo *info);
GIConstantInfo * g_interface_info_get_constant (GIInterfaceInfo *info,
gint n);
@ -527,6 +531,7 @@ typedef enum
GIVFuncInfoFlags g_vfunc_info_get_flags (GIVFuncInfo *info);
gint g_vfunc_info_get_offset (GIVFuncInfo *info);
GISignalInfo * g_vfunc_info_get_signal (GIVFuncInfo *info);
GIFunctionInfo * g_vfunc_info_get_invoker (GIVFuncInfo *info);
/* GIConstantInfo */

View File

@ -265,6 +265,7 @@ g_ir_node_free (GIrNode *node)
GIrNodeVFunc *vfunc = (GIrNodeVFunc *)node;
g_free (node->name);
g_free (vfunc->invoker);
for (l = vfunc->parameters; l; l = l->next)
g_ir_node_free ((GIrNode *)l->data);
g_list_free (vfunc->parameters);
@ -1186,6 +1187,30 @@ g_ir_find_node (GIrModule *module,
return node != NULL;
}
static int
get_index_of_member_type (GIrNodeInterface *node,
GIrNodeTypeId type,
const char *name)
{
guint index = -1;
GList *l;
for (l = node->members; l; l = l->next)
{
GIrNode *node = l->data;
if (node->type != type)
continue;
index++;
if (strcmp (node->name, name) == 0)
break;
}
return index;
}
static void
serialize_type (GIrModule *module,
GList *modules,
@ -1759,6 +1784,18 @@ g_ir_node_build_typelib (GIrNode *node,
blob->class_closure = 0; /* FIXME */
blob->reserved = 0;
if (vfunc->invoker)
{
int index = get_index_of_member_type ((GIrNodeInterface*)parent, G_IR_NODE_FUNCTION, vfunc->invoker);
if (index == -1)
{
g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name);
}
blob->invoker = (guint) index;
}
else
blob->invoker = 0x3ff; /* max of 10 bits */
blob->struct_offset = vfunc->offset;
blob->reserved2 = 0;
blob->signature = signature;

View File

@ -214,6 +214,8 @@ struct _GIrNodeVFunc
gboolean must_not_be_implemented;
gboolean is_class_closure;
char *invoker;
GList *parameters;
GIrNodeParam *result;

View File

@ -2080,7 +2080,7 @@ start_vfunc (GMarkupParseContext *context,
ParseContext *ctx,
GError **error)
{
if (strcmp (element_name, "vfunc") == 0 &&
if (strcmp (element_name, "virtual-method") == 0 &&
(ctx->state == STATE_CLASS ||
ctx->state == STATE_INTERFACE))
{
@ -2089,12 +2089,14 @@ start_vfunc (GMarkupParseContext *context,
const gchar *override;
const gchar *is_class_closure;
const gchar *offset;
const gchar *invoker;
name = find_attribute ("name", attribute_names, attribute_values);
must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
override = find_attribute ("override", attribute_names, attribute_values);
is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
offset = find_attribute ("offset", attribute_names, attribute_values);
invoker = find_attribute ("invoker", attribute_names, attribute_values);
if (name == NULL)
MISSING_ATTRIBUTE (context, error, element_name, "name");
@ -2138,6 +2140,8 @@ start_vfunc (GMarkupParseContext *context,
else
vfunc->offset = 0;
vfunc->invoker = g_strdup (invoker);
iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
iface->members = g_list_append (iface->members, vfunc);

View File

@ -843,9 +843,10 @@ typedef struct {
* @class_closure: Set if this virtual function is the class closure of a signal.
* @signal: The index of the signal in the list of signals of the object or
* interface to which this virtual function belongs.
* @struct_offset:
* The offset of the function pointer in the class struct. The value
* @struct_offset: The offset of the function pointer in the class struct. The value
* 0xFFFF indicates that the struct offset is unknown.
* @invoker: If a method invoker for this virtual exists, this is the offset in the
* class structure of the method. If no method is known, this value will be 0x3ff.
* @signature:
* Offset of the SignatureBlob describing the parameter types and the
* return value type.
@ -861,7 +862,8 @@ typedef struct {
guint16 signal;
guint16 struct_offset;
guint16 reserved2;
guint16 invoker : 10; /* Number of bits matches @index in FunctionBlob */
guint16 reserved2 : 6;
guint32 reserved3;
guint32 signature;