[loader] Make MonoImageSet::gclass_cache concurrent.
authorRodrigo Kumpera <kumpera@gmail.com>
Tue, 22 Nov 2016 17:06:26 +0000 (09:06 -0800)
committerRodrigo Kumpera <kumpera@gmail.com>
Tue, 11 Apr 2017 23:03:24 +0000 (16:03 -0700)
mono/metadata/metadata-internals.h
mono/metadata/metadata.c
mono/utils/mono-conc-hashtable.c
mono/utils/mono-conc-hashtable.h

index a81b48b64fca4b5f96cb27f562b975cfe06ea492..b1613fddc6faa72a156b6361486e9ab9d3a282a2 100644 (file)
@@ -430,7 +430,8 @@ typedef struct {
        MonoImage **images;
 
        // Generic-specific caches
-       GHashTable *gclass_cache, *ginst_cache, *gmethod_cache, *gsignature_cache;
+       GHashTable *ginst_cache, *gmethod_cache, *gsignature_cache;
+       MonoConcurrentHashTable *gclass_cache;
 
        MonoWrapperCaches wrapper_caches;
 
index 5e70d67a993e65521194dd3a7178dfa3ef607032..9b1c17772b0e72ee2c7795a9cfce1917ee642f74 100644 (file)
@@ -2564,7 +2564,7 @@ get_image_set (MonoImage **images, int nimages)
                mono_os_mutex_init_recursive (&set->lock);
                for (i = 0; i < nimages; ++i)
                        set->images [i] = images [i];
-               set->gclass_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
+               set->gclass_cache = mono_conc_hashtable_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
                set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
                set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
                set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
@@ -2593,7 +2593,7 @@ delete_image_set (MonoImageSet *set)
 {
        int i;
 
-       g_hash_table_destroy (set->gclass_cache);
+       mono_conc_hashtable_destroy (set->gclass_cache);
        g_hash_table_destroy (set->ginst_cache);
        g_hash_table_destroy (set->gmethod_cache);
        g_hash_table_destroy (set->gsignature_cache);
@@ -2954,7 +2954,7 @@ mono_metadata_clean_for_image (MonoImage *image)
                MonoImageSet *set = (MonoImageSet *)l->data;
 
                mono_image_set_lock (set);
-               g_hash_table_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
+               mono_conc_hashtable_foreach_steal (set->gclass_cache, steal_gclass_in_image, &gclass_data);
                g_hash_table_foreach_steal (set->ginst_cache, steal_ginst_in_image, &ginst_data);
                g_hash_table_foreach_remove (set->gmethod_cache, inflated_method_in_image, image);
                g_hash_table_foreach_remove (set->gsignature_cache, inflated_signature_in_image, image);
@@ -3196,17 +3196,13 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
 
        collect_data_free (&data);
 
-       mono_image_set_lock (set);
-
-       gclass = (MonoGenericClass *)g_hash_table_lookup (set->gclass_cache, &helper);
+       gclass = (MonoGenericClass *)mono_conc_hashtable_lookup (set->gclass_cache, &helper);
 
        /* A tripwire just to keep us honest */
        g_assert (!helper.cached_class);
 
-       if (gclass) {
-               mono_image_set_unlock (set);
+       if (gclass)
                return gclass;
-       }
 
        gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
        if (is_dynamic)
@@ -3220,11 +3216,17 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst
        if (inst == mono_class_get_generic_container (container_class)->context.class_inst && !is_tb_open)
                gclass->cached_class = container_class;
 
-       g_hash_table_insert (set->gclass_cache, gclass, gclass);
+       mono_image_set_lock (set);
+
+       MonoGenericClass *gclass2 = mono_conc_hashtable_insert (set->gclass_cache, gclass, gclass);
+       if (!gclass2)
+               gclass2 = gclass;
+
+       // g_hash_table_insert (set->gclass_cache, gclass, gclass);
 
        mono_image_set_unlock (set);
 
-       return gclass;
+       return gclass2;
 }
 
 /*
index ad8d340701a9fb539609031be33199263d393273..bfb94b7af9e7b024f475deb0e5907afbb85f38bf 100644 (file)
@@ -245,6 +245,7 @@ mono_conc_hashtable_remove (MonoConcurrentHashTable *hash_table, gpointer key)
                                kvs [i].value = NULL;
                                mono_memory_barrier ();
                                kvs [i].key = TOMBSTONE;
+                               --hash_table->element_count;
 
                                if (hash_table->key_destroy_func != NULL)
                                        (*hash_table->key_destroy_func) (key);
@@ -358,3 +359,28 @@ mono_conc_hashtable_foreach (MonoConcurrentHashTable *hash_table, GHFunc func, g
                }
        }
 }
+
+/**
+ * mono_conc_hashtable_foreach_steal:
+ *
+ * Calls @func for each entry in the hashtable, if @func returns true, remove from the hashtable. Requires external locking.
+ * Same semantics as g_hash_table_foreach_steal.
+ */
+void
+mono_conc_hashtable_foreach_steal (MonoConcurrentHashTable *hash_table, GHRFunc func, gpointer userdata)
+{
+       int i;
+       conc_table *table = (conc_table*)hash_table->table;
+       key_value_pair *kvs = table->kvs;
+
+       for (i = 0; i < table->table_size; ++i) {
+               if (kvs [i].key && kvs [i].key != TOMBSTONE) {
+                       if (func (kvs [i].key, kvs [i].value, userdata)) {
+                               kvs [i].value = NULL;
+                               mono_memory_barrier ();
+                               kvs [i].key = TOMBSTONE;
+                               --hash_table->element_count;
+                       }
+               }
+       }
+}
index d4cc69976ed609debe90c3c276c66145f3b01086..8c3c033ab568f3f10dd8f6107c0fb33f69f735d8 100644 (file)
@@ -25,6 +25,6 @@ MONO_API gpointer mono_conc_hashtable_lookup (MonoConcurrentHashTable *hash_tabl
 MONO_API gpointer mono_conc_hashtable_insert (MonoConcurrentHashTable *hash_table, gpointer key, gpointer value);
 MONO_API gpointer mono_conc_hashtable_remove (MonoConcurrentHashTable *hash_table, gpointer key);
 MONO_API void mono_conc_hashtable_foreach (MonoConcurrentHashTable *hashtable, GHFunc func, gpointer userdata);
-
+MONO_API void mono_conc_hashtable_foreach_steal (MonoConcurrentHashTable *hashtable, GHRFunc func, gpointer userdata);
 
 #endif