X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-hash.c;h=55d8adf05834f3ccab1a0fd323331e1bb27b9f53;hb=b3ea62b4135307b48532b4886357528d212e65b6;hp=70cce73b0d35a26348012a35c13cccea6f2a0668;hpb=987f8c63e214937c50dcb308149f7558a2cbba41;p=mono.git diff --git a/mono/utils/mono-hash.c b/mono/utils/mono-hash.c index 70cce73b0d3..55d8adf0583 100644 --- a/mono/utils/mono-hash.c +++ b/mono/utils/mono-hash.c @@ -37,7 +37,6 @@ #endif #include -#include #include "mono-hash.h" #include "metadata/gc-internal.h" @@ -93,6 +92,9 @@ 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); @@ -100,10 +102,32 @@ 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 /** @@ -139,6 +163,17 @@ mono_g_hash_table_new_type (GHashFunc hash_func, 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) { @@ -147,7 +182,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 +220,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 +268,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 @@ -327,17 +368,23 @@ g_hash_node_new (gpointer key, 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 +395,21 @@ 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 G_LOCK (g_hash_global); if (node_free_list) @@ -368,9 +428,9 @@ g_hash_node_new (gpointer key, } 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; @@ -415,7 +475,7 @@ 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 { @@ -457,8 +517,8 @@ 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 { @@ -704,8 +764,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 +823,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 +865,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 +875,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) + 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