added optimizations to skip NOP signal emissions.
authorTim Janik <timj@gtk.org>
Mon, 18 Aug 2003 23:32:17 +0000 (23:32 +0000)
committerTim Janik <timj@src.gnome.org>
Mon, 18 Aug 2003 23:32:17 +0000 (23:32 +0000)
Tue Aug 19 01:31:28 2003  Tim Janik  <timj@gtk.org>

        * gsignal.c: added optimizations to skip NOP signal emissions.

gobject/ChangeLog
gobject/gsignal.c

index 934d318916757a80ed27327af6543ef645537581..aacac34ea807918d427738735ca9c672b2e2e8cc 100644 (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>
 
        * testgobject.c (test_signal_accumulator): Add check
index 9f9e13284b6bcf0af2e730a0b5d924c4f8cd9651..0ba055ffc3aa95afb307ed8cd9eb62892a720082 100644 (file)
@@ -175,6 +175,7 @@ struct _SignalNode
   guint              destroyed : 1;
   
   /* reinitializable portion */
+  guint                     test_class_offset : 12;
   guint              flags : 8;
   guint              n_params : 8;
   GType                    *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
@@ -184,6 +185,8 @@ struct _SignalNode
   GSignalCMarshaller c_marshaller;
   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
 {
@@ -1124,6 +1127,18 @@ g_signal_new (const gchar         *signal_name,
                                    return_type, n_params, 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;
 }
@@ -1174,6 +1189,9 @@ signal_add_class_closure (SignalNode *node,
 {
   ClassClosure key;
 
+  /* can't optimize NOP emissions with overridden class closures */
+  node->test_class_offset = 0;
+
   if (!node->class_closure_bsa)
     node->class_closure_bsa = g_bsearch_array_new (&g_class_closure_bconfig);
   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);
     }
   node->destroyed = FALSE;
-  
+  node->test_class_offset = 0;
+
   /* setup reinitializable portion */
   node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
   node->n_params = n_params;
@@ -1307,6 +1326,11 @@ g_signal_newv (const gchar       *signal_name,
   node->emission_hooks = NULL;
   if (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 ();
 
   return signal_id;
@@ -1354,6 +1378,7 @@ signal_destroy_R (SignalNode *signal_node)
   signal_node->destroyed = TRUE;
   
   /* reentrancy caution, zero out real contents first */
+  signal_node->test_class_offset = 0;
   signal_node->n_params = 0;
   signal_node->param_types = NULL;
   signal_node->return_type = 0;
@@ -1947,6 +1972,50 @@ g_signal_has_handler_pending (gpointer instance,
   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
 g_signal_emitv (const GValue *instance_and_params,
                guint         signal_id,
@@ -2020,6 +2089,15 @@ g_signal_emitv (const GValue *instance_and_params,
     return_value = NULL;
 #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_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 */
 
+  /* 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;
   signal_return_type = node->return_type;
   if (node->n_params < MAX_STACK_VALUES)