#include <mono/utils/mono-error-internals.h>
#include <mono/utils/bsearch.h>
#include <mono/utils/atomic.h>
+#include <mono/utils/mono-counters.h>
+
+static int img_set_cache_hit, img_set_cache_miss, img_set_count;
+
/* Auxiliary structure used for caching inflated signatures */
typedef struct {
#endif
+/* If TRUE (but also see DISABLE_STICT_STRONG_NAMES #define), Mono will check
+ * that the public key token, culture and version of a candidate assembly matches
+ * the requested strong name. If FALSE, as long as the name matches, the candidate
+ * will be allowed.
+ */
+static gboolean check_strong_names_strictly = FALSE;
+
// Amount initially reserved in each imageset's mempool.
// FIXME: This number is arbitrary, a more practical number should be found
#define INITIAL_IMAGE_SET_SIZE 1024
break;
/*
- * CustomAttributeType: TypeDef, TypeRef, MethodDef,
- * MemberRef and String.
+ * CustomAttributeType: MethodDef, MemberRef.
*/
case MONO_MT_CAT_IDX:
- /* String is a heap, if it is wide, we know the size */
- /* See above, nope.
- if (meta->idx_string_wide){
- field_size = 4;
- break;
- }*/
-
- n = MAX (get_nrows (meta, MONO_TABLE_TYPEREF),
- get_nrows (meta, MONO_TABLE_TYPEDEF));
- n = MAX (n, get_nrows (meta, MONO_TABLE_METHOD));
- n = MAX (n, get_nrows (meta, MONO_TABLE_MEMBERREF));
+ n = MAX (get_nrows (meta, MONO_TABLE_METHOD),
+ get_nrows (meta, MONO_TABLE_MEMBERREF));
/* 3 bits to encode */
field_size = rtsize (meta, n, 16-3);
* \param ptr pointer to a blob object
* \param rptr the new position of the pointer
*
- * This decodes a compressed size as described by 23.1.4 (a blob or user string object)
+ * This decodes a compressed size as described by 24.2.4 (#US and #Blob a blob or user string object)
*
* \returns the size of the blob object
*/
#define NBUILTIN_TYPES() (sizeof (builtin_types) / sizeof (builtin_types [0]))
static GHashTable *type_cache = NULL;
-static int next_generic_inst_id = 0;
+static gint32 next_generic_inst_id = 0;
/* Protected by image_sets_mutex */
static MonoImageSet *mscorlib_image_set;
g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
mono_os_mutex_init_recursive (&image_sets_mutex);
+
+ mono_counters_register ("ImgSet Cache Hit", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_hit);
+ mono_counters_register ("ImgSet Cache Miss", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_cache_miss);
+ mono_counters_register ("ImgSet Count", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &img_set_count);
}
/**
mono_os_mutex_unlock (&image_sets_mutex);
}
+static int
+compare_pointers (const void *a, const void *b)
+{
+ return (size_t)a - (size_t)b;
+}
+
+//1103, 1327, 1597
+#define HASH_TABLE_SIZE 1103
+static MonoImageSet *img_set_cache [HASH_TABLE_SIZE];
+
+static guint32
+mix_hash (uintptr_t source)
+{
+ unsigned int hash = source;
+
+ // Actual hash
+ hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
+
+ // Mix in highest bits on 64-bit systems only
+ if (sizeof (source) > 4)
+ hash = hash ^ (source >> 32);
+
+ return hash;
+}
+
+static guint32
+hash_images (MonoImage **images, int nimages)
+{
+ guint32 res = 0;
+ int i;
+ for (i = 0; i < nimages; ++i)
+ res += mix_hash ((size_t)images [i]);
+
+ return res;
+}
+
+static gboolean
+compare_img_set (MonoImageSet *set, MonoImage **images, int nimages)
+{
+ int j, k;
+
+ if (set->nimages != nimages)
+ return FALSE;
+
+ for (j = 0; j < nimages; ++j) {
+ for (k = 0; k < nimages; ++k)
+ if (set->images [k] == images [j])
+ break; // Break on match
+
+ // If we iterated all the way through set->images, images[j] was *not* found.
+ if (k == nimages)
+ break; // Break on "image not found"
+ }
+
+ // If we iterated all the way through images without breaking, all items in images were found in set->images
+ return j == nimages;
+}
+
+
+static MonoImageSet*
+img_set_cache_get (MonoImage **images, int nimages)
+{
+ guint32 hash_code = hash_images (images, nimages);
+ int index = hash_code % HASH_TABLE_SIZE;
+ MonoImageSet *img = img_set_cache [index];
+ if (!img || !compare_img_set (img, images, nimages)) {
+ ++img_set_cache_miss;
+ return NULL;
+ }
+ ++img_set_cache_hit;
+ return img;
+}
+
+static void
+img_set_cache_add (MonoImageSet *set)
+{
+ guint32 hash_code = hash_images (set->images, set->nimages);
+ int index = hash_code % HASH_TABLE_SIZE;
+ img_set_cache [index] = set;
+}
+
+static void
+img_set_cache_remove (MonoImageSet *is)
+{
+ guint32 hash_code = hash_images (is->images, is->nimages);
+ int index = hash_code % HASH_TABLE_SIZE;
+ if (img_set_cache [index] == is)
+ img_set_cache [index] = NULL;
+}
/*
* get_image_set:
*
if (nimages == 0)
return mscorlib_image_set;
+ set = img_set_cache_get (images, nimages);
+ if (set)
+ return set;
+
image_sets_lock ();
if (!image_sets)
}
// If we iterated all the way through images without breaking, all items in images were found in set->images
- if (j == nimages)
- break; // Break on "found a set with equal members"
+ if (j == nimages) {
+ // Break on "found a set with equal members".
+ // This happens in case of a hash collision with a previously cached set.
+ break;
+ }
}
l = l->next;
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);
set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
g_ptr_array_add (image_sets, set);
+ ++img_set_count;
}
+ /* Cache the set. If there was a cache collision, the previously cached value will be replaced. */
+ img_set_cache_add (set);
+
if (nimages == 1 && images [0] == mono_defaults.corlib) {
mono_memory_barrier ();
mscorlib_image_set = 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);
image_sets_unlock ();
+ img_set_cache_remove (set);
+
if (set->mempool)
mono_mempool_destroy (set->mempool);
g_free (set->images);
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);
return set;
}
+static gboolean
+type_is_gtd (MonoType *type)
+{
+ switch (type->type) {
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ return mono_class_is_gtd (type->data.klass);
+ default:
+ return FALSE;
+ }
+}
+
/*
* mono_metadata_get_generic_inst:
*
ginst->type_argc = type_argc;
memcpy (ginst->type_argv, type_argv, type_argc * sizeof (MonoType *));
+ for (i = 0; i < type_argc; ++i) {
+ MonoType *t = ginst->type_argv [i];
+ if (type_is_gtd (t)) {
+ ginst->type_argv [i] = mono_class_gtd_get_canonical_inst (t->data.klass);
+ }
+ }
+
return mono_metadata_get_canonical_generic_inst (ginst);
}
int size = MONO_SIZEOF_GENERIC_INST + type_argc * sizeof (MonoType *);
ginst = (MonoGenericInst *)mono_image_set_alloc0 (set, size);
#ifndef MONO_SMALL_CONFIG
- ginst->id = ++next_generic_inst_id;
+ ginst->id = InterlockedIncrement (&next_generic_inst_id);
#endif
ginst->is_open = is_open;
ginst->type_argc = type_argc;
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)
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;
}
/*
error_init (error);
- mono_image_lock (image);
- type = (MonoType *)g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
- mono_image_unlock (image);
+ type = (MonoType *)mono_conc_hashtable_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
if (type)
return type;
mono_metadata_free_type (type);
mono_image_lock (image);
- type = (MonoType *)g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
+
/* We might leak some data in the image mempool if found */
- if (!type) {
- g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
+ type = mono_conc_hashtable_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
+ if (!type)
type = type2;
- }
+
mono_image_unlock (image);
return type;
return owner;
}
+
+void
+mono_loader_set_strict_strong_names (gboolean enabled)
+{
+ check_strong_names_strictly = enabled;
+}
+
+gboolean
+mono_loader_get_strict_strong_names (void)
+{
+ return check_strong_names_strictly;
+}