Uniform use of the return error from mono_dl
[mono.git] / mono / utils / mono-hash.c
index 70cce73b0d35a26348012a35c13cccea6f2a0668..c6c947b9f2a72e38fb46165e4493669d20bd847d 100644 (file)
@@ -37,7 +37,6 @@
 #endif
 
 #include <glib.h>
-#include <mono/os/gc_wrapper.h>
 #include "mono-hash.h"
 #include "metadata/gc-internal.h"
 
@@ -77,9 +76,7 @@ struct _MonoGHashTable
 static void            g_hash_table_resize       (MonoGHashTable         *hash_table);
 static MonoGHashNode** g_hash_table_lookup_node  (MonoGHashTable     *hash_table,
                                                    gconstpointer   key);
-static MonoGHashNode*  g_hash_node_new           (gpointer        key,
-                                                   gpointer        value,
-                                                  gint            gc_type);
+static MonoGHashNode*  g_hash_node_new           (gint            gc_type);
 static void            g_hash_node_destroy       (MonoGHashNode          *hash_node,
                                                   MonoGHashGCType type,
                                                    GDestroyNotify  key_destroy_func,
@@ -93,19 +90,27 @@ static guint g_hash_table_foreach_remove_or_steal (MonoGHashTable     *hash_tabl
                                                    gpointer       user_data,
                                                    gboolean        notify);
 
+#ifdef HAVE_SGEN_GC
+static void mono_g_hash_mark (void *addr, MonoGCCopyFunc mark_func);
+#endif
 
 G_LOCK_DEFINE_STATIC (g_hash_global);
 
 #if defined(HAVE_NULL_GC)
 static GMemChunk *node_mem_chunk = NULL;
-#endif
-#if defined(HAVE_SGEN_GC)
-static void *node_gc_descs [4] = {NULL};
+static MonoGHashNode *node_free_list = NULL;
+#elif defined(HAVE_SGEN_GC)
 static MonoGHashNode *node_free_lists [4] = {NULL};
+static void *hash_descr = NULL;
+static GMemChunk *node_mem_chunk = NULL;
 #else
-static MonoGHashNode *node_free_list = NULL;
+static void *node_gc_descs [4] = {NULL};
+static MonoGHashNode *node_free_lists [4] = {NULL};
 #endif
 
+#define SET_NODE_KEY(node, gc_type, val) do { (node)->key = (val); } while (0)
+#define SET_NODE_VALUE(node, gc_type, val) do { (node)->value = (val); } while (0)
+
 /**
  * g_hash_table_new:
  * @hash_func: a function to create a hash value from a key.
@@ -137,8 +142,21 @@ mono_g_hash_table_new_type (GHashFunc    hash_func,
                  MonoGHashGCType type)
 {
   MonoGHashTable *table = mono_g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
+  if (type == MONO_HASH_KEY_GC || type == MONO_HASH_KEY_VALUE_GC)
+         g_assert (hash_func);
   table->gc_type = type;
 #if defined(HAVE_SGEN_GC)
+  if (type < 0 || type > MONO_HASH_KEY_VALUE_GC)
+         g_error ("wrong type for gc hashtable");
+  /* 
+   * We use a user defined marking function to avoid having to register a GC root for
+   * each hash node.
+   */
+  if (!hash_descr)
+         hash_descr = mono_gc_make_root_descr_user (mono_g_hash_mark);
+  if (type != MONO_HASH_CONSERVATIVE_GC)
+         mono_gc_register_root_wbarrier ((char*)table, sizeof (MonoGHashTable), hash_descr);
+#elif defined(HAVE_BOEHM_GC)
   if (type < 0 || type > MONO_HASH_KEY_VALUE_GC)
          g_error ("wrong type for gc hashtable");
   if (!node_gc_descs [type] && type > MONO_HASH_CONSERVATIVE_GC) {
@@ -147,7 +165,10 @@ mono_g_hash_table_new_type (GHashFunc    hash_func,
                  bmap |= 1; /* the first field in the node is the key */
          if (type & MONO_HASH_VALUE_GC)
                  bmap |= 2; /* the second is the value */
-         node_gc_descs [type] = mono_gc_make_descr_from_bitmap (&bmap, 2);
+         bmap |= 4; /* next */
+         node_gc_descs [type] = mono_gc_make_descr_from_bitmap (&bmap, 3);
+
+         MONO_GC_REGISTER_ROOT (node_free_lists [type]);
   }
 #endif
   return table;
@@ -182,8 +203,8 @@ mono_g_hash_table_new_full (GHashFunc       hash_func,
 #if HAVE_BOEHM_GC
   static gboolean inited = FALSE;
   if (!inited) {
-    MONO_GC_REGISTER_ROOT (node_free_list);
-    inited = TRUE;
+         MONO_GC_REGISTER_ROOT (node_free_lists [0]);
+         inited = TRUE;
   }
   
   hash_table = GC_MALLOC (sizeof (MonoGHashTable));
@@ -230,6 +251,9 @@ mono_g_hash_table_destroy (MonoGHashTable *hash_table)
 
 #if HAVE_BOEHM_GC
 #else
+#if HAVE_SGEN_GC
+  mono_gc_deregister_root ((char*)hash_table);
+#endif
   g_free (hash_table->nodes);
   g_free (hash_table);
 #endif
@@ -320,24 +344,28 @@ mono_g_hash_table_lookup_extended (MonoGHashTable    *hash_table,
 }
 
 static inline MonoGHashNode*
-g_hash_node_new (gpointer key,
-                gpointer value,
-                gint gc_type)
+g_hash_node_new (gint gc_type)
 {
   MonoGHashNode *hash_node = NULL;
 
 #if HAVE_BOEHM_GC
-  if (node_free_list) {
+  if (node_free_lists [gc_type]) {
          G_LOCK (g_hash_global);
 
-         if (node_free_list) {
-                 hash_node = node_free_list;
-                 node_free_list = node_free_list->next;
+         if (node_free_lists [gc_type]) {
+                 hash_node = node_free_lists [gc_type];
+                 node_free_lists [gc_type] = node_free_lists [gc_type]->next;
          }
          G_UNLOCK (g_hash_global);
   }
-  if (!hash_node)
-      hash_node = GC_MALLOC (sizeof (MonoGHashNode));
+  if (!hash_node) {
+         if (gc_type != MONO_HASH_CONSERVATIVE_GC) {
+                 //hash_node = GC_MALLOC (sizeof (MonoGHashNode));
+                 hash_node = GC_MALLOC_EXPLICITLY_TYPED (sizeof (MonoGHashNode), (GC_descr)node_gc_descs [gc_type]);
+         } else {
+                 hash_node = GC_MALLOC (sizeof (MonoGHashNode));
+         }
+  }
 #elif defined(HAVE_SGEN_GC)
   if (node_free_lists [gc_type]) {
          G_LOCK (g_hash_global);
@@ -348,8 +376,34 @@ g_hash_node_new (gpointer key,
          }
          G_UNLOCK (g_hash_global);
   }
-  if (!hash_node)
-      hash_node = mono_gc_alloc_fixed (sizeof (MonoGHashNode), node_gc_descs [gc_type]);
+  if (!hash_node) {
+         if (gc_type != MONO_HASH_CONSERVATIVE_GC) {
+                 /* 
+                  * Marking is handled by the marker function, no need to allocate GC visible
+                  * memory.
+                  */
+                 if (!node_mem_chunk)
+                         node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
+                                                                                               sizeof (MonoGHashNode),
+                                                                                               1024, G_ALLOC_ONLY);
+                 hash_node = g_chunk_new (MonoGHashNode, node_mem_chunk);
+         } else {
+                 hash_node = mono_gc_alloc_fixed (sizeof (MonoGHashNode), NULL);
+         }
+  }
+#else
+#ifdef _EGLIB_MAJOR
+  G_LOCK (g_hash_global);
+  if (node_free_list)
+    {
+      hash_node = node_free_list;
+      node_free_list = node_free_list->next;
+    }
+  else
+    {
+      hash_node = g_new0 (MonoGHashNode, 1);
+    }
+  G_UNLOCK (g_hash_global);
 #else
   G_LOCK (g_hash_global);
   if (node_free_list)
@@ -367,10 +421,11 @@ g_hash_node_new (gpointer key,
       hash_node = g_chunk_new (MonoGHashNode, node_mem_chunk);
     }
   G_UNLOCK (g_hash_global);
+  #endif
 #endif
-  
-  hash_node->key = key;
-  hash_node->value = value;
+
+  hash_node->key = NULL;
+  hash_node->value = NULL;
   hash_node->next = NULL;
   
   return hash_node;
@@ -415,13 +470,16 @@ mono_g_hash_table_insert (MonoGHashTable *hash_table,
       if (hash_table->value_destroy_func)
        hash_table->value_destroy_func ((*node)->value);
 
-      (*node)->value = value;
+         SET_NODE_VALUE ((*node), hash_table->gc_type, value);
     }
   else
     {
-      *node = g_hash_node_new (key, value, hash_table->gc_type);
-      hash_table->nnodes++;
-      G_HASH_TABLE_RESIZE (hash_table);
+           gint gc_type = hash_table->gc_type;
+           *node = g_hash_node_new (gc_type);
+           SET_NODE_KEY (*node, gc_type, key);
+           SET_NODE_VALUE (*node, gc_type, value);
+           hash_table->nnodes++;
+           G_HASH_TABLE_RESIZE (hash_table);
     }
 }
 
@@ -457,14 +515,17 @@ mono_g_hash_table_replace (MonoGHashTable *hash_table,
       if (hash_table->value_destroy_func)
        hash_table->value_destroy_func ((*node)->value);
 
-      (*node)->key   = key;
-      (*node)->value = value;
+         SET_NODE_KEY ((*node), hash_table->gc_type, key);
+         SET_NODE_VALUE ((*node), hash_table->gc_type, value);
     }
   else
     {
-      *node = g_hash_node_new (key, value, hash_table->gc_type);
-      hash_table->nnodes++;
-      G_HASH_TABLE_RESIZE (hash_table);
+           gint gc_type = hash_table->gc_type;
+           *node = g_hash_node_new (gc_type);
+           SET_NODE_KEY (*node, gc_type, key);
+           SET_NODE_VALUE (*node, gc_type, value);
+           hash_table->nnodes++;
+           G_HASH_TABLE_RESIZE (hash_table);
     }
 }
 
@@ -668,6 +729,23 @@ mono_g_hash_table_foreach (MonoGHashTable *hash_table,
       (* func) (node->key, node->value, user_data);
 }
 
+gpointer
+mono_g_hash_table_find (MonoGHashTable *hash_table, GHRFunc predicate, gpointer user_data)
+{
+       int i;
+       MonoGHashNode *node;
+       
+       g_return_val_if_fail (hash_table != NULL, NULL);
+       g_return_val_if_fail (predicate != NULL, NULL);
+
+       for (i = 0; i < hash_table->size; i++){
+               for (node = hash_table->nodes[i]; node; node = node->next)
+                       if ((*predicate)(node->key, node->value, user_data))
+                               return node->value;
+       }
+       return NULL;
+}
+
 /**
  * g_hash_table_size:
  * @hash_table: a #GHashTable.
@@ -704,8 +782,10 @@ mono_g_hash_table_remap (MonoGHashTable *hash_table,
   g_return_if_fail (func != NULL);
   
   for (i = 0; i < hash_table->size; i++)
-    for (node = hash_table->nodes[i]; node; node = node->next)
-      node->value = (* func) (node->key, node->value, user_data);
+         for (node = hash_table->nodes[i]; node; node = node->next) {
+                 gpointer new_val = (* func) (node->key, node->value, user_data);
+                 SET_NODE_VALUE (node, hash_table->gc_type, new_val);
+         }
 }
 
 static void
@@ -761,7 +841,7 @@ g_hash_node_destroy (MonoGHashNode      *hash_node,
   hash_node->value = NULL;
 
   G_LOCK (g_hash_global);
-#if defined(HAVE_SGEN_GC)
+#if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
   hash_node->next = node_free_lists [type];
   node_free_lists [type] = hash_node;
 #else
@@ -803,7 +883,7 @@ g_hash_nodes_destroy (MonoGHashNode *hash_node,
       node->value = NULL;
  
       G_LOCK (g_hash_global);
-#if defined(HAVE_SGEN_GC)
+#if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
       node->next = node_free_lists [type];
       node_free_lists [type] = hash_node;
 #else
@@ -813,3 +893,41 @@ g_hash_nodes_destroy (MonoGHashNode *hash_node,
       G_UNLOCK (g_hash_global);
     }
 }
+
+#ifdef HAVE_SGEN_GC
+
+/* GC marker function */
+static void
+mono_g_hash_mark (void *addr, MonoGCCopyFunc mark_func)
+{
+       MonoGHashTable *table = (MonoGHashTable*)addr;
+       MonoGHashNode *node;
+       int i;
+
+       if (table->gc_type == MONO_HASH_KEY_GC) {
+               for (i = 0; i < table->size; i++) {
+                       for (node = table->nodes [i]; node; node = node->next) {
+                               if (node->key)
+                                       node->key = mark_func (node->key);
+                       }
+               }
+       } else if (table->gc_type == MONO_HASH_VALUE_GC) {
+               for (i = 0; i < table->size; i++) {
+                       for (node = table->nodes [i]; node; node = node->next) {
+                               if (node->value)
+                                       node->value = mark_func (node->value);
+                       }
+               }
+       } else if (table->gc_type == MONO_HASH_KEY_VALUE_GC) {
+               for (i = 0; i < table->size; i++) {
+                       for (node = table->nodes [i]; node; node = node->next) {
+                               if (node->key)
+                                       node->key = mark_func (node->key);
+                               if (node->value)
+                                       node->value = mark_func (node->value);
+                       }
+               }
+       }
+}
+
+#endif