gobject/gtype: Avoid duplicate GType to TypeNode lookups

There are some cases where we perform the same lookup_type_node_I() twice.
Additionally, if we stash the parent TypeNode pointer in our TypeNode
rather than just the GType in supers[], then we can avoid that parent
type lookup as well in g_type_class_ref().
This commit is contained in:
Christian Hergert 2024-10-02 14:55:08 -07:00
parent 17124abc7e
commit 436f4c9c7b

View File

@ -170,6 +170,8 @@ static void type_iface_vtable_iface_init_Wm (TypeNod
TypeNode *node); TypeNode *node);
static gboolean type_node_is_a_L (TypeNode *node, static gboolean type_node_is_a_L (TypeNode *node,
TypeNode *iface_node); TypeNode *iface_node);
static gpointer type_class_ref_with_node (GType type,
TypeNode *node);
/* --- enumeration --- */ /* --- enumeration --- */
@ -207,6 +209,9 @@ struct _TypeNode
guint is_final : 1; guint is_final : 1;
guint mutatable_check_cache : 1; /* combines some common path checks */ guint mutatable_check_cache : 1; /* combines some common path checks */
/* up-pointer to parent */
struct _TypeNode *pnode;
GType *children; /* writable with lock */ GType *children; /* writable with lock */
TypeData *data; TypeData *data;
GQuark qname; GQuark qname;
@ -226,6 +231,7 @@ struct _TypeNode
#define MAX_N_PREREQUISITES (511) #define MAX_N_PREREQUISITES (511)
#define NODE_TYPE(node) (node->supers[0]) #define NODE_TYPE(node) (node->supers[0])
#define NODE_PARENT_TYPE(node) (node->supers[1]) #define NODE_PARENT_TYPE(node) (node->supers[1])
#define NODE_PARENT(node) (node->pnode)
#define NODE_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers]) #define NODE_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers])
#define NODE_NAME(node) (g_quark_to_string (node->qname)) #define NODE_NAME(node) (g_quark_to_string (node->qname))
#define NODE_REFCOUNT(node) ((guint) g_atomic_int_get ((int *) &(node)->ref_count)) #define NODE_REFCOUNT(node) ((guint) g_atomic_int_get ((int *) &(node)->ref_count))
@ -492,6 +498,7 @@ type_node_any_new_W (TypeNode *pnode,
node->plugin = plugin; node->plugin = plugin;
node->n_children = 0; node->n_children = 0;
node->children = NULL; node->children = NULL;
node->pnode = pnode;
node->data = NULL; node->data = NULL;
node->qname = g_quark_from_string (name); node->qname = g_quark_from_string (name);
node->global_gdata = NULL; node->global_gdata = NULL;
@ -1892,7 +1899,7 @@ g_type_create_instance (GType type)
maybe_issue_deprecation_warning (type); maybe_issue_deprecation_warning (type);
} }
class = g_type_class_ref (type); class = type_class_ref_with_node (type, node);
/* We allocate the 'private' areas before the normal instance data, in /* We allocate the 'private' areas before the normal instance data, in
* reverse order. This allows the private area of a particular class * reverse order. This allows the private area of a particular class
@ -2976,28 +2983,15 @@ g_type_add_interface_dynamic (GType instance_type,
} }
/* --- public API functions --- */ static gpointer
/** type_class_ref_with_node (GType type,
* g_type_class_ref: TypeNode *node)
* @type: type ID of a classed type
*
* Increments the reference count of the class structure belonging to
* @type. This function will demand-create the class if it doesn't
* exist already.
*
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
* structure for the given type ID
*/
gpointer
g_type_class_ref (GType type)
{ {
TypeNode *node;
GType ptype; GType ptype;
gboolean holds_ref; gboolean holds_ref;
GTypeClass *pclass; GTypeClass *pclass;
/* optimize for common code path */ /* optimize for common code path */
node = lookup_type_node_I (type);
if (!node || !node->is_classed) if (!node || !node->is_classed)
{ {
g_critical ("cannot retrieve class for invalid (unclassed) type '%s'", g_critical ("cannot retrieve class for invalid (unclassed) type '%s'",
@ -3013,7 +3007,7 @@ g_type_class_ref (GType type)
} }
else else
holds_ref = FALSE; holds_ref = FALSE;
/* here, we either have node->data->class.class == NULL, or a recursive /* here, we either have node->data->class.class == NULL, or a recursive
* call to g_type_class_ref() with a partly initialized class, or * call to g_type_class_ref() with a partly initialized class, or
* node->data->class.init_state == INITIALIZED, because any * node->data->class.init_state == INITIALIZED, because any
@ -3023,7 +3017,7 @@ g_type_class_ref (GType type)
/* we need an initialized parent class for initializing derived classes */ /* we need an initialized parent class for initializing derived classes */
ptype = NODE_PARENT_TYPE (node); ptype = NODE_PARENT_TYPE (node);
pclass = ptype ? g_type_class_ref (ptype) : NULL; pclass = ptype ? type_class_ref_with_node (ptype, NODE_PARENT (node)) : NULL;
G_WRITE_LOCK (&type_rw_lock); G_WRITE_LOCK (&type_rw_lock);
@ -3043,6 +3037,24 @@ g_type_class_ref (GType type)
return node->data->class.class; return node->data->class.class;
} }
/* --- public API functions --- */
/**
* g_type_class_ref:
* @type: type ID of a classed type
*
* Increments the reference count of the class structure belonging to
* @type. This function will demand-create the class if it doesn't
* exist already.
*
* Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass
* structure for the given type ID
*/
gpointer
g_type_class_ref (GType type)
{
return type_class_ref_with_node (type, lookup_type_node_I (type));
}
/** /**
* g_type_class_unref: * g_type_class_unref:
* @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref * @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref
@ -4055,8 +4067,8 @@ g_type_interface_get_plugin (GType instance_type,
TypeNode *iface; TypeNode *iface;
g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL); /* G_TYPE_IS_INTERFACE() is an external call: _U */ g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL); /* G_TYPE_IS_INTERFACE() is an external call: _U */
node = lookup_type_node_I (instance_type); node = lookup_type_node_I (instance_type);
iface = lookup_type_node_I (interface_type); iface = lookup_type_node_I (interface_type);
if (node && iface) if (node && iface)
{ {