X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-hash.c;h=55d8adf05834f3ccab1a0fd323331e1bb27b9f53;hb=b3ea62b4135307b48532b4886357528d212e65b6;hp=fa209a9c94f8daa5d7763b04e201db1415177587;hpb=7f449e7aff8f374d13db7023c7b326dde01b763d;p=mono.git diff --git a/mono/utils/mono-hash.c b/mono/utils/mono-hash.c index fa209a9c94f..55d8adf0583 100644 --- a/mono/utils/mono-hash.c +++ b/mono/utils/mono-hash.c @@ -37,13 +37,12 @@ #endif #include -#include #include "mono-hash.h" +#include "metadata/gc-internal.h" #define HASH_TABLE_MIN_SIZE 11 #define HASH_TABLE_MAX_SIZE 13845163 - typedef struct _MonoGHashNode MonoGHashNode; struct _MonoGHashNode @@ -62,6 +61,7 @@ struct _MonoGHashTable GEqualFunc key_equal_func; GDestroyNotify key_destroy_func; GDestroyNotify value_destroy_func; + MonoGHashGCType gc_type; }; #define G_HASH_TABLE_RESIZE(hash_table) \ @@ -77,11 +77,14 @@ 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); + gpointer value, + gint gc_type); static void g_hash_node_destroy (MonoGHashNode *hash_node, + MonoGHashGCType type, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func); static void g_hash_nodes_destroy (MonoGHashNode *hash_node, + MonoGHashGCType type, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func); static guint g_hash_table_foreach_remove_or_steal (MonoGHashTable *hash_table, @@ -89,13 +92,43 @@ 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 !HAVE_BOEHM_GC +#if defined(HAVE_NULL_GC) +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 +#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 -static MonoGHashNode *node_free_list = NULL; /** * g_hash_table_new: @@ -122,6 +155,43 @@ mono_g_hash_table_new (GHashFunc hash_func, return mono_g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL); } +MonoGHashTable* +mono_g_hash_table_new_type (GHashFunc hash_func, + GEqualFunc key_equal_func, + MonoGHashGCType type) +{ + 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) { + gsize bmap = 0; + if (type & MONO_HASH_KEY_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 */ + 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; +} + + /** * g_hash_table_new_full: @@ -147,8 +217,13 @@ mono_g_hash_table_new_full (GHashFunc hash_func, GDestroyNotify value_destroy_func) { MonoGHashTable *hash_table; - #if HAVE_BOEHM_GC + static gboolean inited = FALSE; + if (!inited) { + MONO_GC_REGISTER_ROOT (node_free_lists [0]); + inited = TRUE; + } + hash_table = GC_MALLOC (sizeof (MonoGHashTable)); #else hash_table = g_new (MonoGHashTable, 1); @@ -164,6 +239,7 @@ mono_g_hash_table_new_full (GHashFunc hash_func, #else hash_table->nodes = g_new0 (MonoGHashNode*, hash_table->size); #endif + hash_table->gc_type = 0; return hash_table; } @@ -186,12 +262,15 @@ mono_g_hash_table_destroy (MonoGHashTable *hash_table) g_return_if_fail (hash_table != NULL); for (i = 0; i < hash_table->size; i++) - g_hash_nodes_destroy (hash_table->nodes[i], + g_hash_nodes_destroy (hash_table->nodes[i], hash_table->gc_type, hash_table->key_destroy_func, hash_table->value_destroy_func); #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 @@ -283,22 +362,54 @@ mono_g_hash_table_lookup_extended (MonoGHashTable *hash_table, static inline MonoGHashNode* g_hash_node_new (gpointer key, - gpointer value) + gpointer value, + 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_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) { + 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); - 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) { + /* + * 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) @@ -317,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; @@ -364,11 +475,11 @@ 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); + *node = g_hash_node_new (key, value, hash_table->gc_type); hash_table->nnodes++; G_HASH_TABLE_RESIZE (hash_table); } @@ -406,12 +517,12 @@ 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); + *node = g_hash_node_new (key, value, hash_table->gc_type); hash_table->nnodes++; G_HASH_TABLE_RESIZE (hash_table); } @@ -444,7 +555,7 @@ mono_g_hash_table_remove (MonoGHashTable *hash_table, { dest = *node; (*node) = dest->next; - g_hash_node_destroy (dest, + g_hash_node_destroy (dest, hash_table->gc_type, hash_table->key_destroy_func, hash_table->value_destroy_func); hash_table->nnodes--; @@ -480,7 +591,7 @@ mono_g_hash_table_steal (MonoGHashTable *hash_table, { dest = *node; (*node) = dest->next; - g_hash_node_destroy (dest, NULL, NULL); + g_hash_node_destroy (dest, hash_table->gc_type, NULL, NULL); hash_table->nnodes--; G_HASH_TABLE_RESIZE (hash_table); @@ -566,7 +677,7 @@ g_hash_table_foreach_remove_or_steal (MonoGHashTable *hash_table, if (prev) { prev->next = node->next; - g_hash_node_destroy (node, + g_hash_node_destroy (node, hash_table->gc_type, notify ? hash_table->key_destroy_func : NULL, notify ? hash_table->value_destroy_func : NULL); node = prev; @@ -574,7 +685,7 @@ g_hash_table_foreach_remove_or_steal (MonoGHashTable *hash_table, else { hash_table->nodes[i] = node->next; - g_hash_node_destroy (node, + g_hash_node_destroy (node, hash_table->gc_type, notify ? hash_table->key_destroy_func : NULL, notify ? hash_table->value_destroy_func : NULL); goto restart; @@ -653,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 @@ -697,6 +810,7 @@ g_hash_table_resize (MonoGHashTable *hash_table) static void g_hash_node_destroy (MonoGHashNode *hash_node, + MonoGHashGCType type, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func) { @@ -709,13 +823,19 @@ g_hash_node_destroy (MonoGHashNode *hash_node, hash_node->value = NULL; G_LOCK (g_hash_global); +#if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC) + hash_node->next = node_free_lists [type]; + node_free_lists [type] = hash_node; +#else hash_node->next = node_free_list; node_free_list = hash_node; +#endif G_UNLOCK (g_hash_global); } static void g_hash_nodes_destroy (MonoGHashNode *hash_node, + MonoGHashGCType type, GFreeFunc key_destroy_func, GFreeFunc value_destroy_func) { @@ -745,8 +865,51 @@ g_hash_nodes_destroy (MonoGHashNode *hash_node, node->value = NULL; G_LOCK (g_hash_global); +#if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC) + node->next = node_free_lists [type]; + node_free_lists [type] = hash_node; +#else node->next = node_free_list; node_free_list = hash_node; +#endif 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