#endif
#include <glib.h>
-#include <mono/os/gc_wrapper.h>
#include "mono-hash.h"
#include "metadata/gc-internal.h"
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,
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.
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) {
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;
#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));
#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
}
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);
}
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)
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;
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);
}
}
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);
}
}
(* 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.
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
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
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
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