#endif
#include <glib.h>
-#include <mono/os/gc_wrapper.h>
#include "mono-hash.h"
#include "metadata/gc-internal.h"
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);
static GMemChunk *node_mem_chunk = NULL;
#endif
#if defined(HAVE_SGEN_GC)
+static MonoGHashNode *node_free_lists [4] = {NULL};
+static void *hash_descr = NULL;
+static GMemChunk *node_mem_chunk = NULL;
+#else
static void *node_gc_descs [4] = {NULL};
static MonoGHashNode *node_free_lists [4] = {NULL};
+#endif
+
+#ifdef HAVE_SGEN_GC
+#define SET_NODE_KEY(node, gc_type, val) do { \
+ gpointer __val = (val); \
+ if (gc_type == MONO_HASH_KEY_GC || gc_type == MONO_HASH_KEY_VALUE_GC) \
+ MONO_ROOT_SETREF ((node), key, __val); \
+ else \
+ (node)->key = __val; \
+ } while (0)
+#define SET_NODE_VALUE(node, gc_type, val) do { \
+ gpointer __val = (val); \
+ if (gc_type == MONO_HASH_VALUE_GC || gc_type == MONO_HASH_KEY_VALUE_GC) \
+ MONO_ROOT_SETREF ((node), value, __val); \
+ else \
+ (node)->value = __val; \
+ } while (0)
#else
-static MonoGHashNode *node_free_list = NULL;
+#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)
#endif
/**
MonoGHashTable *table = mono_g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
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
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
G_LOCK (g_hash_global);
if (node_free_list)
}
G_UNLOCK (g_hash_global);
#endif
-
- hash_node->key = key;
- hash_node->value = value;
+
+ SET_NODE_KEY (hash_node, gc_type, key);
+ SET_NODE_VALUE (hash_node, gc_type, value);
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
{
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
{
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)
+ SET_NODE_KEY (node, table->gc_type, 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)
+ SET_NODE_VALUE (node, table->gc_type, 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)
+ SET_NODE_KEY (node, table->gc_type, mark_func (node->key));
+ if (node->value)
+ SET_NODE_VALUE (node, table->gc_type, mark_func (node->value));
+ }
+ }
+ }
+}
+
+#endif