added optimizations to skip NOP signal emissions.

Tue Aug 19 01:31:28 2003  Tim Janik  <timj@gtk.org>

        * gsignal.c: added optimizations to skip NOP signal emissions.
This commit is contained in:
Tim Janik 2003-08-18 23:32:17 +00:00 committed by Tim Janik
parent b1b9636b73
commit 779c44cdfb
2 changed files with 92 additions and 1 deletions

View File

@ -1,3 +1,7 @@
Tue Aug 19 01:31:28 2003 Tim Janik <timj@gtk.org>
* gsignal.c: added optimizations to skip NOP signal emissions.
Wed Aug 6 09:57:14 2003 Owen Taylor <otaylor@redhat.com> Wed Aug 6 09:57:14 2003 Owen Taylor <otaylor@redhat.com>
* testgobject.c (test_signal_accumulator): Add check * testgobject.c (test_signal_accumulator): Add check

View File

@ -175,6 +175,7 @@ struct _SignalNode
guint destroyed : 1; guint destroyed : 1;
/* reinitializable portion */ /* reinitializable portion */
guint test_class_offset : 12;
guint flags : 8; guint flags : 8;
guint n_params : 8; guint n_params : 8;
GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */ GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
@ -184,6 +185,8 @@ struct _SignalNode
GSignalCMarshaller c_marshaller; GSignalCMarshaller c_marshaller;
GHookList *emission_hooks; GHookList *emission_hooks;
}; };
#define MAX_TEST_CLASS_OFFSET (4096) /* 2^12, 12 bits for test_class_offset */
#define TEST_CLASS_MAGIC (1) /* indicates NULL class closure, candidate for NOP optimization */
struct _SignalKey struct _SignalKey
{ {
@ -1124,6 +1127,18 @@ g_signal_new (const gchar *signal_name,
return_type, n_params, args); return_type, n_params, args);
va_end (args); va_end (args);
/* optimize NOP emissions with NULL class handlers */
if (signal_id && G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE &&
class_offset && class_offset < MAX_TEST_CLASS_OFFSET)
{
SignalNode *node;
SIGNAL_LOCK ();
node = LOOKUP_SIGNAL_NODE (signal_id);
node->test_class_offset = class_offset;
SIGNAL_UNLOCK ();
}
return signal_id; return signal_id;
} }
@ -1174,6 +1189,9 @@ signal_add_class_closure (SignalNode *node,
{ {
ClassClosure key; ClassClosure key;
/* can't optimize NOP emissions with overridden class closures */
node->test_class_offset = 0;
if (!node->class_closure_bsa) if (!node->class_closure_bsa)
node->class_closure_bsa = g_bsearch_array_new (&g_class_closure_bconfig); node->class_closure_bsa = g_bsearch_array_new (&g_class_closure_bconfig);
key.instance_type = itype; key.instance_type = itype;
@ -1288,7 +1306,8 @@ g_signal_newv (const gchar *signal_name,
g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key, FALSE); g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key, FALSE);
} }
node->destroyed = FALSE; node->destroyed = FALSE;
node->test_class_offset = 0;
/* setup reinitializable portion */ /* setup reinitializable portion */
node->flags = signal_flags & G_SIGNAL_FLAGS_MASK; node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
node->n_params = n_params; node->n_params = n_params;
@ -1307,6 +1326,11 @@ g_signal_newv (const gchar *signal_name,
node->emission_hooks = NULL; node->emission_hooks = NULL;
if (class_closure) if (class_closure)
signal_add_class_closure (node, 0, class_closure); signal_add_class_closure (node, 0, class_closure);
else if (G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE)
{
/* optimize NOP emissions */
node->test_class_offset = TEST_CLASS_MAGIC;
}
SIGNAL_UNLOCK (); SIGNAL_UNLOCK ();
return signal_id; return signal_id;
@ -1354,6 +1378,7 @@ signal_destroy_R (SignalNode *signal_node)
signal_node->destroyed = TRUE; signal_node->destroyed = TRUE;
/* reentrancy caution, zero out real contents first */ /* reentrancy caution, zero out real contents first */
signal_node->test_class_offset = 0;
signal_node->n_params = 0; signal_node->n_params = 0;
signal_node->param_types = NULL; signal_node->param_types = NULL;
signal_node->return_type = 0; signal_node->return_type = 0;
@ -1947,6 +1972,50 @@ g_signal_has_handler_pending (gpointer instance,
return has_pending; return has_pending;
} }
static inline gboolean
signal_check_skip_emission (SignalNode *node,
gpointer instance,
GQuark detail)
{
HandlerList *hlist;
/* are we able to check for NULL class handlers? */
if (!node->test_class_offset)
return FALSE;
/* are there emission hooks pending? */
if (node->emission_hooks && node->emission_hooks->hooks)
return FALSE;
/* is there a non-NULL class handler? */
if (node->test_class_offset != TEST_CLASS_MAGIC)
{
GTypeClass *class = G_TYPE_INSTANCE_GET_CLASS (instance, G_TYPE_FROM_INSTANCE (instance), GTypeClass);
if (G_STRUCT_MEMBER (gpointer, class, node->test_class_offset))
return FALSE;
}
/* are signals being debugged? */
#ifdef G_ENABLE_DEBUG
IF_DEBUG (SIGNALS, g_trace_instance_signals || g_trap_instance_signals)
return FALSE;
#endif /* G_ENABLE_DEBUG */
/* is this a no-recurse signal already in emission? */
if (node->flags & G_SIGNAL_NO_RECURSE &&
emission_find (g_restart_emissions, node->signal_id, detail, instance))
return FALSE;
/* do we have pending handlers? */
hlist = handler_list_lookup (node->signal_id, instance);
if (hlist && hlist->handlers)
return FALSE;
/* none of the above, no emission required */
return TRUE;
}
void void
g_signal_emitv (const GValue *instance_and_params, g_signal_emitv (const GValue *instance_and_params,
guint signal_id, guint signal_id,
@ -2020,6 +2089,15 @@ g_signal_emitv (const GValue *instance_and_params,
return_value = NULL; return_value = NULL;
#endif /* G_ENABLE_DEBUG */ #endif /* G_ENABLE_DEBUG */
/* optimize NOP emissions */
if (signal_check_skip_emission (node, instance, detail))
{
/* nothing to do to emit this signal */
SIGNAL_UNLOCK ();
/* g_printerr ("omitting emission of \"%s\"\n", node->name); */
return;
}
SIGNAL_UNLOCK (); SIGNAL_UNLOCK ();
signal_emit_unlocked_R (node, detail, instance, return_value, instance_and_params); signal_emit_unlocked_R (node, detail, instance, return_value, instance_and_params);
} }
@ -2056,6 +2134,15 @@ g_signal_emit_valist (gpointer instance,
} }
#endif /* !G_DISABLE_CHECKS */ #endif /* !G_DISABLE_CHECKS */
/* optimize NOP emissions */
if (signal_check_skip_emission (node, instance, detail))
{
/* nothing to do to emit this signal */
SIGNAL_UNLOCK ();
/* g_printerr ("omitting emission of \"%s\"\n", node->name); */
return;
}
n_params = node->n_params; n_params = node->n_params;
signal_return_type = node->return_type; signal_return_type = node->return_type;
if (node->n_params < MAX_STACK_VALUES) if (node->n_params < MAX_STACK_VALUES)