#include <mono/utils/mono-memory-model.h>
#include <mono/utils/atomic.h>
#include <mono/utils/bsearch.h>
+ #include <mono/utils/checked-build.h>
MonoStats mono_stats;
static inline void
classes_lock (void)
{
- mono_locks_acquire (&classes_mutex, ClassesLock);
+ mono_locks_os_acquire (&classes_mutex, ClassesLock);
}
static inline void
classes_unlock (void)
{
- mono_locks_release (&classes_mutex, ClassesLock);
+ mono_locks_os_release (&classes_mutex, ClassesLock);
}
/*
}
if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type"));
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that is not extended or implemented by this type"));
return FALSE;
}
supertypes = mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
if (klass->parent) {
- supertypes [klass->idepth - 1] = klass;
- memcpy (supertypes, klass->parent->supertypes, klass->parent->idepth * sizeof (gpointer));
+ CHECKED_METADATA_WRITE_PTR ( supertypes [klass->idepth - 1] , klass );
+
+ int supertype_idx;
+ for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
+ CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
} else {
- supertypes [0] = klass;
+ CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
}
- mono_atomic_store_release (&klass->supertypes, supertypes);
+ CHECKED_METADATA_WRITE_PTR_ATOMIC ( klass->supertypes , supertypes );
}
static gboolean
if (klass->generic_container) {
klass->is_generic = 1;
klass->generic_container->owner.klass = klass;
+ klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
context = &klass->generic_container->context;
}
return NULL;
}
- /** is klass Nullable<T>? */
+ /** Is klass a Nullable<T> ginst? */
gboolean
mono_class_is_nullable (MonoClass *klass)
{
return klass;
}
+ static MonoImage *
+ get_image_for_container (MonoGenericContainer *container)
+ {
+ MonoImage *result;
+ if (container->is_anonymous) {
+ result = container->owner.image;
+ } else {
+ MonoClass *klass;
+ if (container->is_method) {
+ MonoMethod *method = container->owner.method;
+ g_assert_checked (method);
+ klass = method->klass;
+ } else {
+ klass = container->owner.klass;
+ }
+ g_assert_checked (klass);
+ result = klass->image;
+ }
+ g_assert (result);
+ return result;
+ }
+
+ MonoImage *
+ get_image_for_generic_param (MonoGenericParam *param)
+ {
+ MonoGenericContainer *container = mono_generic_param_owner (param);
+ g_assert_checked (container);
+ return get_image_for_container (container);
+ }
+
+ // Make a string in the designated image consisting of a single integer.
+ #define INT_STRING_SIZE 16
+ char *
+ make_generic_name_string (MonoImage *image, int num)
+ {
+ char *name = mono_image_alloc0 (image, INT_STRING_SIZE);
+ snprintf (name, INT_STRING_SIZE, "%d", num);
+ return name;
+ }
+
+ // This is called by mono_class_from_generic_parameter_internal when a new class must be created.
+ // pinfo is derived from param by the caller for us.
static MonoClass*
- make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
+ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
{
MonoClass *klass, **ptr;
int count, pos, i;
MonoGenericContainer *container = mono_generic_param_owner (param);
+ g_assert_checked (container);
- if (!image)
- /* FIXME: */
- image = mono_defaults.corlib;
+ MonoImage *image = get_image_for_container (container);
+ gboolean is_mvar = container->is_method;
+ gboolean is_anonymous = container->is_anonymous;
klass = mono_image_alloc0 (image, sizeof (MonoClass));
classes_size += sizeof (MonoClass);
if (pinfo) {
- klass->name = pinfo->name;
+ CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
} else {
int n = mono_generic_param_num (param);
- klass->name = mono_image_alloc0 (image, 16);
- sprintf ((char*)klass->name, "%d", n);
+
+ CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , make_generic_name_string (image, n) );
}
- if (container) {
- if (is_mvar) {
- MonoMethod *omethod = container->owner.method;
- klass->name_space = (omethod && omethod->klass) ? omethod->klass->name_space : "";
- } else {
- MonoClass *oklass = container->owner.klass;
- klass->name_space = oklass ? oklass->name_space : "";
- }
+ if (is_anonymous) {
+ CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
+ } else if (is_mvar) {
+ MonoMethod *omethod = container->owner.method;
+ CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
} else {
- klass->name_space = "";
+ MonoClass *oklass = container->owner.klass;
+ CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
}
mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+ // Count non-NULL items in pinfo->constraints
count = 0;
if (pinfo)
for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
pos = 0;
if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
- klass->parent = pinfo->constraints [0];
+ CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
pos++;
- } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
- klass->parent = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
- else
- klass->parent = mono_defaults.object_class;
-
+ } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
+ CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_from_name (mono_defaults.corlib, "System", "ValueType") );
+ } else {
+ CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
+ }
if (count - pos > 0) {
klass->interface_count = count - pos;
- klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
+ CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
klass->interfaces_inited = TRUE;
for (i = pos; i < count; i++)
- klass->interfaces [i - pos] = pinfo->constraints [i];
+ CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
}
- klass->image = image;
+ CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
klass->inited = TRUE;
- klass->cast_class = klass->element_class = klass;
+ CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
+ CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
klass->flags = TYPE_ATTRIBUTE_PUBLIC;
klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
- klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
+ CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
+ CHECKED_METADATA_WRITE_PTR ( klass->byval_arg.data.generic_param , param );
klass->this_arg.byref = TRUE;
/* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
#define FAST_CACHE_SIZE 16
/*
+ * get_anon_gparam_class and set_anon_gparam_class are helpers for mono_class_from_generic_parameter_internal.
+ * The latter will sometimes create MonoClasses for anonymous generic params. To prevent this being wasteful,
+ * we cache the MonoClasses.
+ * FIXME: It would be better to instead cache anonymous MonoGenericParams, and allow anonymous params to point directly to classes using the pklass field.
* LOCKING: Takes the image lock depending on @take_lock.
*/
static MonoClass *
- get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, gboolean take_lock)
+ get_anon_gparam_class (MonoGenericParam *param, gboolean take_lock)
{
int n = mono_generic_param_num (param);
- MonoImage *image = param->image;
+ MonoImage *image = get_image_for_generic_param (param);
+ gboolean is_mvar = mono_generic_param_owner (param)->is_method;
MonoClass *klass = NULL;
GHashTable *ht;
g_assert (image);
+ // For params with a small num and no constraints, we use a "fast" cache which does simple num lookup in an array.
+ // For high numbers or constraints we have to use pointer hashes.
if (param->gshared_constraint) {
ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
if (ht) {
* LOCKING: Image lock (param->image) must be held
*/
static void
- set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
+ set_anon_gparam_class (MonoGenericParam *param, MonoClass *klass)
{
int n = mono_generic_param_num (param);
- MonoImage *image = param->image;
+ MonoImage *image = get_image_for_generic_param (param);
+ gboolean is_mvar = mono_generic_param_owner (param)->is_method;
g_assert (image);
* LOCKING: Acquires the image lock (@image).
*/
MonoClass *
- mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+ mono_class_from_generic_parameter_internal (MonoGenericParam *param)
{
- MonoGenericContainer *container = mono_generic_param_owner (param);
- MonoGenericParamInfo *pinfo = NULL;
+ MonoImage *image = get_image_for_generic_param (param);
+ MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
MonoClass *klass, *klass2;
- if (container) {
- pinfo = mono_generic_param_info (param);
+ // If a klass already exists for this object and is cached, return it.
+ if (pinfo) // Non-anonymous
klass = pinfo->pklass;
- } else {
- image = NULL;
- klass = get_anon_gparam_class (param, is_mvar, TRUE);
- }
+ else // Anonymous
+ klass = get_anon_gparam_class (param, TRUE);
+
if (klass)
return klass;
- if (!image && container) {
- if (is_mvar) {
- MonoMethod *method = container->owner.method;
- image = (method && method->klass) ? method->klass->image : NULL;
- } else {
- MonoClass *klass = container->owner.klass;
- // FIXME: 'klass' should not be null
- // But, monodis creates GenericContainers without associating a owner to it
- image = klass ? klass->image : NULL;
- }
- }
-
- klass = make_generic_param_class (param, image, is_mvar, pinfo);
+ // Create a new klass
+ klass = make_generic_param_class (param, pinfo);
+ // Now we need to cache the klass we created.
+ // But since we wait to grab the lock until after creating the klass, we need to check to make sure
+ // another thread did not get in and cache a klass ahead of us. In that case, return their klass
+ // and allow our newly-created klass object to just leak.
mono_memory_barrier ();
- if (!image) //FIXME is this only needed by monodis? Can't we fix monodis instead of having this hack?
- image = mono_defaults.corlib;
-
mono_image_lock (image);
- if (container)
+
+ // Here "klass2" refers to the klass potentially created by the other thread.
+ if (pinfo) // Repeat check from above
klass2 = pinfo->pklass;
else
- klass2 = get_anon_gparam_class (param, is_mvar, FALSE);
+ klass2 = get_anon_gparam_class (param, FALSE);
if (klass2) {
klass = klass2;
} else {
- if (container)
+ // Cache here
+ if (pinfo)
pinfo->pklass = klass;
else
- set_anon_gparam_class (param, is_mvar, klass);
+ set_anon_gparam_class (param, klass);
}
mono_image_unlock (image);
/* FIXME: Should this go inside 'make_generic_param_klass'? */
if (klass2)
- mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED);
+ mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
else
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
return klass;
}
+ /**
+ * mono_class_from_generic_parameter:
+ * @param: Parameter to find/construct a class for.
+ * @arg2: Is ignored.
+ * @arg3: Is ignored.
+ */
+ MonoClass *
+ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
+ {
+ return mono_class_from_generic_parameter_internal (param);
+ }
+
+
MonoClass *
mono_ptr_class_get (MonoType *type)
{
return type->data.klass;
case MONO_TYPE_GENERICINST:
return mono_generic_class_get_class (type->data.generic_class);
- case MONO_TYPE_VAR:
- return mono_class_from_generic_parameter (type->data.generic_param, NULL, FALSE);
case MONO_TYPE_MVAR:
- return mono_class_from_generic_parameter (type->data.generic_param, NULL, TRUE);
+ case MONO_TYPE_VAR:
+ return mono_class_from_generic_parameter_internal (type->data.generic_param);
default:
g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
g_assert_not_reached ();
* from mono_class_from_mono_type (), mono_array_new (),
* Array:CreateInstance (), etc, so use a separate cache + a separate lock.
*/
- mono_mutex_lock (&image->szarray_cache_lock);
+ mono_os_mutex_lock (&image->szarray_cache_lock);
if (!image->szarray_cache)
image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
klass = g_hash_table_lookup (image->szarray_cache, eclass);
- mono_mutex_unlock (&image->szarray_cache_lock);
+ mono_os_mutex_unlock (&image->szarray_cache_lock);
if (klass)
return klass;
if (rank == 1 && !bounded) {
MonoClass *prev_class;
- mono_mutex_lock (&image->szarray_cache_lock);
+ mono_os_mutex_lock (&image->szarray_cache_lock);
prev_class = g_hash_table_lookup (image->szarray_cache, eclass);
if (prev_class)
/* Someone got in before us */
klass = prev_class;
else
g_hash_table_insert (image->szarray_cache, eclass, klass);
- mono_mutex_unlock (&image->szarray_cache_lock);
+ mono_os_mutex_unlock (&image->szarray_cache_lock);
} else {
list = g_slist_append (rootlist, klass);
g_hash_table_insert (image->array_cache, eclass, list);
void
mono_classes_init (void)
{
- mono_mutex_init (&classes_mutex);
+ mono_os_mutex_init (&classes_mutex);
mono_counters_register ("Inflated methods size",
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
global_interface_bitset = NULL;
- mono_mutex_destroy (&classes_mutex);
+ mono_os_mutex_destroy (&classes_mutex);
}
/**
#include <mono/utils/mono-io-portability.h>
#include <mono/utils/mono-digest.h>
#include <mono/utils/bsearch.h>
-#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-os-mutex.h>
#include <mono/utils/mono-threads.h>
#if defined (HOST_WIN32)
MonoGenericContainer *container = klass->generic_container;
res = create_type_array (domain, runtimeTypeArray, container->type_argc);
for (i = 0; i < container->type_argc; ++i) {
- pklass = mono_class_from_generic_parameter (mono_generic_container_get_param (container, i), klass->image, FALSE);
+ pklass = mono_class_from_generic_parameter_internal (mono_generic_container_get_param (container, i));
mono_array_setref (res, i, mono_type_get_object (domain, &pklass->byval_arg));
}
} else if (klass->generic_class) {
for (i = 0; i < count; i++) {
MonoGenericContainer *container = mono_method_get_generic_container (method->method);
MonoGenericParam *param = mono_generic_container_get_param (container, i);
- MonoClass *pklass = mono_class_from_generic_parameter (
- param, method->method->klass->image, TRUE);
+ MonoClass *pklass = mono_class_from_generic_parameter_internal (param);
mono_array_setref (res, i,
mono_type_get_object (domain, &pklass->byval_arg));
}
return g_str_hash (prop->name);
}
+static gboolean
+method_declaring_signatures_equal (MonoMethod *method1, MonoMethod *method2)
+{
+ if (method1->is_inflated)
+ method1 = ((MonoMethodInflated*) method1)->declaring;
+ if (method2->is_inflated)
+ method2 = ((MonoMethodInflated*) method2)->declaring;
+
+ return mono_metadata_signature_equal (mono_method_signature (method1), mono_method_signature (method2));
+}
+
static gboolean
property_equal (MonoProperty *prop1, MonoProperty *prop2)
{
if (!g_str_equal (prop1->name, prop2->name))
return FALSE;
- if (prop1->get && prop2->get && !mono_metadata_signature_equal (mono_method_signature (prop1->get), mono_method_signature (prop2->get)))
+ /* If we see a property in a generic method, we want to
+ compare the generic signatures, not the inflated signatures
+ because we might conflate two properties that were
+ distinct:
+
+ class Foo<T,U> {
+ public T this[T t] { getter { return t; } } // method 1
+ public U this[U u] { getter { return u; } } // method 2
+ }
+
+ If we see int Foo<int,int>::Item[int] we need to know if
+ the indexer came from method 1 or from method 2, and we
+ shouldn't conflate them. (Bugzilla 36283)
+ */
+ if (prop1->get && prop2->get && !method_declaring_signatures_equal (prop1->get, prop2->get))
return FALSE;
- if (prop1->set && prop2->set && !mono_metadata_signature_equal (mono_method_signature (prop1->set), mono_method_signature (prop2->set)))
+
+ if (prop1->set && prop2->set && !method_declaring_signatures_equal (prop1->set, prop2->set))
return FALSE;
+
return TRUE;
}
#endif
icall_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- mono_mutex_init (&icall_mutex);
+ mono_os_mutex_init (&icall_mutex);
}
static void
mono_icall_lock (void)
{
- mono_locks_mutex_acquire (&icall_mutex, IcallLock);
+ mono_locks_os_acquire (&icall_mutex, IcallLock);
}
static void
mono_icall_unlock (void)
{
- mono_locks_mutex_release (&icall_mutex, IcallLock);
+ mono_locks_os_release (&icall_mutex, IcallLock);
}
void
g_hash_table_destroy (icall_hash);
g_hash_table_destroy (jit_icall_hash_name);
g_hash_table_destroy (jit_icall_hash_addr);
- mono_mutex_destroy (&icall_mutex);
+ mono_os_mutex_destroy (&icall_mutex);
}
void
static gboolean debug_assembly_unload = FALSE;
-#define mono_images_lock() if (mutex_inited) mono_mutex_lock (&images_mutex)
-#define mono_images_unlock() if (mutex_inited) mono_mutex_unlock (&images_mutex)
+#define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
+#define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
static gboolean mutex_inited;
static mono_mutex_t images_mutex;
void
mono_images_init (void)
{
- mono_mutex_init_recursive (&images_mutex);
+ mono_os_mutex_init_recursive (&images_mutex);
int hash_idx;
for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
GHashTableIter iter;
MonoImage *image;
- mono_mutex_destroy (&images_mutex);
+ mono_os_mutex_destroy (&images_mutex);
// If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
// Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
void
mono_image_init (MonoImage *image)
{
- mono_mutex_init_recursive (&image->lock);
- mono_mutex_init_recursive (&image->szarray_cache_lock);
+ mono_os_mutex_init_recursive (&image->lock);
+ mono_os_mutex_init_recursive (&image->szarray_cache_lock);
image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
mono_internal_hash_table_init (&image->class_cache,
if (!mono_image_load_pe_data (image))
goto invalid_image;
} else {
- image->loader = &pe_loader;
+ image->loader = (MonoImageLoader*)&pe_loader;
}
if (care_about_cli == FALSE) {
if (image->modules_loaded)
g_free (image->modules_loaded);
- mono_mutex_destroy (&image->szarray_cache_lock);
- mono_mutex_destroy (&image->lock);
+ mono_os_mutex_destroy (&image->szarray_cache_lock);
+ mono_os_mutex_destroy (&image->lock);
/*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
if (image_is_dynamic (image)) {
void
mono_image_lock (MonoImage *image)
{
- mono_locks_acquire (&image->lock, ImageDataLock);
+ mono_locks_os_acquire (&image->lock, ImageDataLock);
}
void
mono_image_unlock (MonoImage *image)
{
- mono_locks_release (&image->lock, ImageDataLock);
+ mono_locks_os_release (&image->lock, ImageDataLock);
}
mono_image_unlock (image);
}
- #if CHECKED_BUILD
-
- // These are support for the mempool reference tracking feature in checked-build, but live in image.c due to use of static variables of this file.
-
- // Given an image and a pointer, return the mempool owner if it is either this image or one of its imagesets.
- static MonoMemPoolOwner
- check_for_mempool_owner (void *ptr, MonoImage *image)
- {
- if (mono_mempool_contains_addr (image->mempool, ptr))
- {
- MonoMemPoolOwner owner = {image, NULL};
- return owner;
- }
-
- GSList *l;
- for (l = image->image_sets; l; l = l->next) {
- MonoImageSet *set = l->data;
-
- if (mono_mempool_contains_addr (set->mempool, ptr))
- {
- MonoMemPoolOwner owner = {NULL, set};
- return owner;
- }
- }
-
- return mono_mempool_no_owner;
- }
+ // This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
/**
- * mono_find_mempool_owner:
+ * mono_find_image_owner:
*
- * Find the image or imageset, if any, which a given pointer is located in the memory of.
+ * Find the image, if any, which a given pointer is located in the memory of.
*/
- MonoMemPoolOwner
- mono_find_mempool_owner (void *ptr)
+ MonoImage *
+ mono_find_image_owner (void *ptr)
{
mono_images_lock ();
- MonoMemPoolOwner owner = mono_mempool_no_owner;
- gboolean searching = TRUE;
+ MonoImage *owner = NULL;
// Iterate over both by-path image hashes
const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
int hash_idx;
- for (hash_idx = 0; searching && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
+ for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
{
GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
GHashTableIter iter;
// Iterate over images within a hash
g_hash_table_iter_init (&iter, target);
- while (searching && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
+ while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
{
mono_image_lock (image);
- owner = check_for_mempool_owner (ptr, image);
+ if (mono_mempool_contains_addr (image->mempool, ptr))
+ owner = image;
mono_image_unlock (image);
-
- // Continue searching if null owner returned
- searching = check_mempool_owner_eq (owner, mono_mempool_no_owner);
}
}
return owner;
}
-
- #endif
* See domain-internals.h for locking policy in combination with the
* domain lock.
*/
-static mono_mutex_t loader_mutex, global_loader_data_mutex;
+static MonoCoopMutex loader_mutex;
+static mono_mutex_t global_loader_data_mutex;
static gboolean loader_lock_inited;
/* Statistics */
static void
global_loader_data_lock (void)
{
- mono_locks_acquire (&global_loader_data_mutex, LoaderGlobalDataLock);
+ mono_locks_os_acquire (&global_loader_data_mutex, LoaderGlobalDataLock);
}
static void
global_loader_data_unlock (void)
{
- mono_locks_release (&global_loader_data_mutex, LoaderGlobalDataLock);
+ mono_locks_os_release (&global_loader_data_mutex, LoaderGlobalDataLock);
}
void
static gboolean inited;
if (!inited) {
- mono_mutex_init_recursive (&loader_mutex);
- mono_mutex_init_recursive (&global_loader_data_mutex);
+ mono_coop_mutex_init_recursive (&loader_mutex);
+ mono_os_mutex_init_recursive (&global_loader_data_mutex);
loader_lock_inited = TRUE;
mono_native_tls_alloc (&loader_error_thread_id, NULL);
mono_native_tls_free (loader_error_thread_id);
mono_native_tls_free (loader_lock_nest_id);
- mono_mutex_destroy (&loader_mutex);
- mono_mutex_destroy (&global_loader_data_mutex);
+ mono_coop_mutex_destroy (&loader_mutex);
+ mono_os_mutex_destroy (&global_loader_data_mutex);
loader_lock_inited = FALSE;
}
if (generic_container) {
result->is_generic = TRUE;
generic_container->owner.method = result;
+ generic_container->is_anonymous = FALSE; // Method is now known, container is no longer anonymous
/*FIXME put this before the image alloc*/
if (!mono_metadata_load_generic_param_constraints_checked (image, token, generic_container, error))
return NULL;
void
mono_loader_lock (void)
{
- MONO_TRY_BLOCKING;
- mono_locks_acquire (&loader_mutex, LoaderLock);
- MONO_FINISH_TRY_BLOCKING;
-
+ mono_locks_coop_acquire (&loader_mutex, LoaderLock);
if (G_UNLIKELY (loader_lock_track_ownership)) {
mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) + 1));
}
void
mono_loader_unlock (void)
{
- mono_locks_release (&loader_mutex, LoaderLock);
+ mono_locks_coop_release (&loader_mutex, LoaderLock);
if (G_UNLIKELY (loader_lock_track_ownership)) {
mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) - 1));
}
#include "abi-details.h"
#include <mono/utils/mono-error-internals.h>
#include <mono/utils/bsearch.h>
+ #include <mono/utils/atomic.h>
/* Auxiliary structure used for caching inflated signatures */
typedef struct {
{
int i;
- #ifndef MONO_SMALL_CONFIG
- if (a->id && b->id) {
+ // An optimization: if the ids of two insts are the same, we know they are the same inst and don't check contents.
+ // Furthermore, because we perform early de-duping, if the ids differ, we know the contents differ.
+ #ifndef MONO_SMALL_CONFIG // Optimization does not work in MONO_SMALL_CONFIG: There are no IDs
+ if (a->id && b->id) { // "id 0" means "object has no id"-- de-duping hasn't been performed yet, must check contents.
if (a->id == b->id)
return TRUE;
+ // In signature-comparison mode id equality implies object equality, but this is not true for inequality.
+ // Two separate objects could have signature-equavalent contents.
if (!signature_only)
return FALSE;
}
for (i = 0; i < NBUILTIN_TYPES (); ++i)
g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
- mono_mutex_init_recursive (&image_sets_mutex);
+ mono_os_mutex_init_recursive (&image_sets_mutex);
}
/**
type_cache = NULL;
g_ptr_array_free (image_sets, TRUE);
image_sets = NULL;
- mono_mutex_destroy (&image_sets_mutex);
+ mono_os_mutex_destroy (&image_sets_mutex);
}
/**
gboolean byref = FALSE;
gboolean pinned = FALSE;
const char *tmp_ptr;
- int count = 0;
+ int count = 0; // Number of mod arguments
gboolean found;
/*
}
}
- if (count) {
+ if (count) { // There are mods, so the MonoType will be of nonstandard size.
int size;
size = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod);
type->num_mods = count;
if (count > 64)
g_warning ("got more than 64 modifiers in type");
- } else {
+ } else { // The type is of standard size, so we can allocate it on the stack.
type = &stype;
memset (type, 0, MONO_SIZEOF_TYPE);
}
- /* Parse pinned, byref and custom modifiers */
+ /* Iterate again, but now parse pinned, byref and custom modifiers */
found = TRUE;
count = 0;
while (found) {
if (rptr)
*rptr = ptr;
+ // Possibly we can return an already-allocated type instead of the one we decoded
if (!type->num_mods && !transient) {
/* no need to free type here, because it is on the stack */
if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
/* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
- if (type == &stype) {
+ if (type == &stype) { // Type was allocated on the stack, so we need to copy it to safety
type = transient ? g_malloc (MONO_SIZEOF_TYPE) : mono_image_alloc (m, MONO_SIZEOF_TYPE);
memcpy (type, &stype, MONO_SIZEOF_TYPE);
}
goto retry;
case MONO_TYPE_FNPTR:
return signature_in_image (type->data.method, image);
- case MONO_TYPE_VAR: {
- MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
- if (container) {
- g_assert (!container->is_method);
- /*
- * FIXME: The following check is here solely
- * for monodis, which uses the internal
- * function
- * mono_metadata_load_generic_params(). The
- * caller of that function needs to fill in
- * owner->klass or owner->method of the
- * returned struct, but monodis doesn't do
- * that. The image unloading depends on that,
- * however, so a crash results without this
- * check.
- */
- if (!container->owner.klass)
- return container->image == image;
- return container->owner.klass->image == image;
- } else {
- return type->data.generic_param->image == image;
- }
- }
- case MONO_TYPE_MVAR: {
- MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
- if (type->data.generic_param->image == image)
- return TRUE;
- if (container) {
- g_assert (container->is_method);
- if (!container->owner.method)
- /* RefEmit created generic param whose method is not finished */
- return container->image == image;
- return container->owner.method->klass->image == image;
- } else {
- return type->data.generic_param->image == image;
- }
- }
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ return image == get_image_for_generic_param (type->data.generic_param);
default:
/* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
return image == mono_class_from_mono_type (type)->image;
static inline void
image_sets_lock (void)
{
- mono_mutex_lock (&image_sets_mutex);
+ mono_os_mutex_lock (&image_sets_mutex);
}
static inline void
image_sets_unlock (void)
{
- mono_mutex_unlock (&image_sets_mutex);
+ mono_os_mutex_unlock (&image_sets_mutex);
}
/*
MonoImageSet *set;
GSList *l;
- /* Common case */
+ /* Common case: Image set contains corlib only. If we've seen that case before, we cached the set. */
if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
return mscorlib_image_set;
/* Happens with empty generic instances */
+ // FIXME: Is corlib the correct thing to return here? If so, why? This may be an artifact of generic instances previously defaulting to allocating from corlib.
if (nimages == 0)
return mscorlib_image_set;
if (!image_sets)
image_sets = g_ptr_array_new ();
+ // Before we go on, we should check to see whether a MonoImageSet with these images already exists.
+ // We can search the referred-by imagesets of any one of our images to do this. Arbitrarily pick one here:
if (images [0] == mono_defaults.corlib && nimages > 1)
- l = images [1]->image_sets;
+ l = images [1]->image_sets; // Prefer not to search the imagesets of corlib-- that will be a long list.
else
l = images [0]->image_sets;
set = NULL;
- for (; l; l = l->next) {
+ while (l) // Iterate over selected list, looking for an imageset with members equal to our target one
+ {
set = l->data;
- if (set->nimages == nimages) {
+ if (set->nimages == nimages) { // Member count differs, this can't be it
+ // Compare all members to all members-- order might be different
for (j = 0; j < nimages; ++j) {
for (k = 0; k < nimages; ++k)
if (set->images [k] == images [j])
- break;
+ break; // Break on match
+
+ // If we iterated all the way through set->images, images[j] was *not* found.
if (k == nimages)
- /* Not found */
- break;
+ 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
if (j == nimages)
- /* Found */
- break;
+ break; // Break on "found a set with equal members"
}
+
+ l = l->next;
}
+ // If we iterated all the way through l without breaking, the imageset does not already exist and we shuold create it
if (!l) {
- /* Not found */
set = g_new0 (MonoImageSet, 1);
set->nimages = nimages;
set->images = g_new0 (MonoImage*, nimages);
- mono_mutex_init_recursive (&set->lock);
+ 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->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);
-
+
for (i = 0; i < nimages; ++i)
set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
if (set->mempool)
mono_mempool_destroy (set->mempool);
g_free (set->images);
- mono_mutex_destroy (&set->lock);
+ mono_os_mutex_destroy (&set->lock);
g_free (set);
}
void
mono_image_set_lock (MonoImageSet *set)
{
- mono_mutex_lock (&set->lock);
+ mono_os_mutex_lock (&set->lock);
}
void
mono_image_set_unlock (MonoImageSet *set)
{
- mono_mutex_unlock (&set->lock);
+ mono_os_mutex_unlock (&set->lock);
}
gpointer
return res;
}
+ // Get a descriptive string for a MonoImageSet
+ // Callers are obligated to free buffer with g_free after use
+ char *
+ mono_image_set_description (MonoImageSet *set)
+ {
+ GString *result = g_string_new (NULL);
+ int img;
+ g_string_append (result, "[");
+ for (img = 0; img < set->nimages; img++)
+ {
+ if (img > 0)
+ g_string_append (result, ", ");
+ g_string_append (result, set->images[img]->name);
+ }
+ g_string_append (result, "]");
+ return g_string_free (result, FALSE);
+ }
+
/*
* Structure used by the collect_..._images functions to store the image list.
*/
case MONO_TYPE_FNPTR:
//return signature_in_image (type->data.method, image);
g_assert_not_reached ();
- case MONO_TYPE_VAR: {
- MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
- if (container) {
- g_assert (!container->is_method);
- /*
- * FIXME: The following check is here solely
- * for monodis, which uses the internal
- * function
- * mono_metadata_load_generic_params(). The
- * caller of that function needs to fill in
- * owner->klass or owner->method of the
- * returned struct, but monodis doesn't do
- * that. The image unloading depends on that,
- * however, so a crash results without this
- * check.
- */
- if (!container->owner.klass)
- add_image (container->image, data);
- else
- add_image (container->owner.klass->image, data);
- } else {
- add_image (type->data.generic_param->image, data);
- }
- }
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ {
+ MonoImage *image = get_image_for_generic_param (type->data.generic_param);
+ add_image (image, data);
break;
- case MONO_TYPE_MVAR: {
- MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
- if (type->data.generic_param->image)
- add_image (type->data.generic_param->image, data);
- if (container) {
- if (!container->owner.method) {
- /* RefEmit created generic param whose method is not finished */
- add_image (container->image, data);
- } else {
- g_assert (container->is_method);
- add_image (container->owner.method->klass->image, data);
- }
- } else {
- add_image (type->data.generic_param->image, data);
- }
}
- break;
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
add_image (mono_class_from_mono_type (type)->image, data);
MonoImageSet *set;
CollectData data;
+ memset (&helper, 0, sizeof(helper)); // act like g_new0
helper.container_class = container_class;
helper.context.class_inst = inst;
- helper.context.method_inst = NULL;
helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
helper.is_tb_open = is_tb_open;
- helper.cached_class = NULL;
collect_data_init (&data);
return gc;
}
- /*
+ MonoGenericContainer *
+ get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar)
+ {
+ MonoGenericContainer **container_pointer;
+ if (is_mvar)
+ container_pointer = &image->anonymous_generic_method_container;
+ else
+ container_pointer = &image->anonymous_generic_class_container;
+ MonoGenericContainer *result = *container_pointer;
+
+ // This container has never been created; make it now.
+ if (!result)
+ {
+ // Note this is never deallocated anywhere-- it exists for the lifetime of the image it's allocated from
+ result = mono_image_alloc0 (image, sizeof (MonoGenericContainer));
+ result->owner.image = image;
+ result->is_anonymous = TRUE;
+ result->is_small_param = TRUE;
+ result->is_method = is_mvar;
+
+ // If another thread already made a container, use that and leak this new one.
+ // (Technically it would currently be safe to just assign instead of CASing.)
+ MonoGenericContainer *exchange = InterlockedCompareExchangePointer ((volatile gpointer *)container_pointer, result, NULL);
+ if (exchange)
+ result = exchange;
+ }
+ return result;
+ }
+
+ /*
* mono_metadata_parse_generic_param:
* @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
* see mono_metadata_parse_type_full() for details.
generic_container = select_container (generic_container, type);
if (!generic_container) {
+ gboolean is_mvar = FALSE;
+ switch (type)
+ {
+ case MONO_TYPE_VAR:
+ break;
+ case MONO_TYPE_MVAR:
+ is_mvar = TRUE;
+ break;
+ default:
+ g_error ("Cerating generic param object with invalid MonoType"); // This is not a generic param
+ }
+
/* Create dummy MonoGenericParam */
MonoGenericParam *param;
param = mono_image_alloc0 (m, sizeof (MonoGenericParam));
param->num = index;
- param->image = m;
+ param->owner = get_anonymous_container_for_image (m, is_mvar);
return param;
}
* image B gets that generic inst from the cache, image A is
* unloaded, so the inst is deleted, but image B still retains
* a pointer to it.
- *
- * The AOT runtime doesn't set the image when it's decoding
- * types, so we only compare it when the owner is NULL.
*/
- if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2) &&
- (mono_generic_param_owner (p1) || p1->image == p2->image))
+ if (mono_generic_param_owner (p1) == mono_generic_param_owner (p2))
return TRUE;
/*
* mono_metadata_type_equal:
* @t1: a type
* @t2: another type
+ * @signature_only: If true, treat ginsts as equal which are instantiated separately but have equal positional value
*
* Determine if @t1 and @t2 represent the same type.
* Returns: #TRUE if @t1 and @t2 are equal.
params = NULL;
n = 0;
container = mono_image_alloc0 (image, sizeof (MonoGenericContainer));
- container->image = image;
+ container->owner.image = image; // Temporarily mark as anonymous, but this will be overriden by caller
+ container->is_anonymous = TRUE;
do {
n++;
params = g_realloc (params, sizeof (MonoGenericParamFull) * n);
return &method->klass->image->wrapper_caches;
}
}
+
+ // This is support for the mempool reference tracking feature in checked-build, but lives in metadata.c due to use of static variables of this file.
+
+ /**
+ * mono_find_image_set_owner:
+ *
+ * Find the imageset, if any, which a given pointer is located in the memory of.
+ */
+ MonoImageSet *
+ mono_find_image_set_owner (void *ptr)
+ {
+ MonoImageSet *owner = NULL;
+ int i;
+
+ image_sets_lock ();
+
+ if (image_sets)
+ {
+ for (i = 0; !owner && i < image_sets->len; ++i) {
+ MonoImageSet *set = g_ptr_array_index (image_sets, i);
+ if (mono_mempool_contains_addr (set->mempool, ptr))
+ owner = set;
+ }
+ }
+
+ image_sets_unlock ();
+
+ return owner;
+ }
#define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
#define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
+ // The dynamic images list is only needed to support the mempool reference tracking feature in checked-build.
+ static GPtrArray *dynamic_images;
+ static mono_mutex_t dynamic_images_mutex;
+
+ static inline void
+ dynamic_images_lock (void)
+ {
+ mono_mutex_lock (&dynamic_images_mutex);
+ }
+
+ static inline void
+ dynamic_images_unlock (void)
+ {
+ mono_mutex_unlock (&dynamic_images_mutex);
+ }
+
+ /**
+ * mono_find_dynamic_image_owner:
+ *
+ * Find the dynamic image, if any, which a given pointer is located in the memory of.
+ */
+ MonoImage *
+ mono_find_dynamic_image_owner (void *ptr)
+ {
+ MonoImage *owner = NULL;
+ int i;
+
+ dynamic_images_lock ();
+
+ if (dynamic_images)
+ {
+ for (i = 0; !owner && i < dynamic_images->len; ++i) {
+ MonoImage *image = g_ptr_array_index (dynamic_images, i);
+ if (mono_mempool_contains_addr (image->mempool, ptr))
+ owner = image;
+ }
+ }
+
+ dynamic_images_unlock ();
+
+ return owner;
+ }
void
mono_reflection_init (void)
static inline void
dynamic_image_lock (MonoDynamicImage *image)
{
- MONO_TRY_BLOCKING;
+ MONO_PREPARE_BLOCKING;
mono_image_lock ((MonoImage*)image);
- MONO_FINISH_TRY_BLOCKING;
+ MONO_FINISH_BLOCKING;
}
static inline void
mono_profiler_module_loaded (&image->image, MONO_PROFILE_OK);
+ dynamic_images_lock ();
+
+ if (!dynamic_images)
+ dynamic_images = g_ptr_array_new ();
+
+ g_ptr_array_add (dynamic_images, image);
+
+ dynamic_images_unlock ();
+
return image;
}
#endif
release_hashtable (&image->methodspec);
}
+ // Free dynamic image pass one: Free resources but not image itself
void
mono_dynamic_image_free (MonoDynamicImage *image)
{
for (i = 0; i < MONO_TABLE_NUM; ++i) {
g_free (di->tables [i].values);
}
- }
+ dynamic_images_lock ();
+
+ if (dynamic_images)
+ g_ptr_array_remove (dynamic_images, di);
+
+ dynamic_images_unlock ();
+ }
+
+ // Free dynamic image pass two: Free image itself (might never get called in some debug modes)
void
mono_dynamic_image_free_image (MonoDynamicImage *image)
{
container->type_argc = count;
container->type_params = image_g_new0 (image, MonoGenericParamFull, count);
container->owner.method = m;
+ container->is_anonymous = FALSE; // Method is now known, container is no longer anonymous
m->is_generic = TRUE;
mono_method_set_generic_container (m, container);
* Cannot set owner.method, since the MonoMethod is not created yet.
* Set the image field instead, so type_in_image () works.
*/
- gparam->mbuilder->generic_container->image = klass->image;
+ gparam->mbuilder->generic_container->is_anonymous = TRUE;
+ gparam->mbuilder->generic_container->owner.image = klass->image;
}
param->param.owner = gparam->mbuilder->generic_container;
} else if (gparam->tbuilder) {
param->param.owner = gparam->tbuilder->generic_container;
}
- pklass = mono_class_from_generic_parameter ((MonoGenericParam *) param, image, gparam->mbuilder != NULL);
+ pklass = mono_class_from_generic_parameter_internal ((MonoGenericParam *) param);
gparam->type.type = &pklass->byval_arg;
gboolean jit_used, llvm_used;
} MonoPltEntry;
-#define mono_acfg_lock(acfg) mono_mutex_lock (&((acfg)->mutex))
-#define mono_acfg_unlock(acfg) mono_mutex_unlock (&((acfg)->mutex))
+#define mono_acfg_lock(acfg) mono_os_mutex_lock (&((acfg)->mutex))
+#define mono_acfg_unlock(acfg) mono_os_mutex_unlock (&((acfg)->mutex))
/* This points to the current acfg in LLVM mode */
static MonoAotCompile *llvm_acfg;
encode_value (klass->byval_arg.type, p, &p);
encode_value (mono_type_get_generic_param_num (&klass->byval_arg), p, &p);
- encode_value (container ? 1 : 0, p, &p);
- if (container) {
+ encode_value (container->is_anonymous ? 0 : 1, p, &p);
+ if (!container->is_anonymous) {
encode_value (container->is_method, p, &p);
- g_assert (!par->gshared_constraint);
if (container->is_method)
encode_method_ref (acfg, container->owner.method, p, &p);
else
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
case MONO_PATCH_INFO_ICALL_ADDR:
case MONO_PATCH_INFO_RGCTX_FETCH:
- case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
return TRUE;
default:
return FALSE;
if (klass)
add_instances_of (acfg, klass, insts, ninsts, TRUE);
- /* Add an instance of LongEnumEqualityComparer<long/ulong> which is created by EqualityComparer<T> for enums */
+ /* Add instances of EnumEqualityComparer which are created by EqualityComparer<T> for enums */
{
MonoClass *enum_comparer;
- MonoGenericContext ctx;
- MonoType *args [16];
+ MonoType *insts [16];
+ int ninsts;
+
+ ninsts = 0;
+ insts [ninsts ++] = &mono_defaults.int32_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint32_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint16_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.byte_class->byval_arg;
+ enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "EnumEqualityComparer`1");
+ g_assert (enum_comparer);
+ add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
- enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "LongEnumEqualityComparer`1");
+ ninsts = 0;
+ insts [ninsts ++] = &mono_defaults.int16_class->byval_arg;
+ enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "ShortEnumEqualityComparer`1");
g_assert (enum_comparer);
+ add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
- memset (&ctx, 0, sizeof (ctx));
- args [0] = &mono_defaults.int64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (enum_comparer, &ctx), FALSE, "EqualityComparer<T>");
+ ninsts = 0;
+ insts [ninsts ++] = &mono_defaults.sbyte_class->byval_arg;
+ enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "SByteEnumEqualityComparer`1");
+ g_assert (enum_comparer);
+ add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
- memset (&ctx, 0, sizeof (ctx));
- args [0] = &mono_defaults.uint64_class->byval_arg;
- ctx.class_inst = mono_metadata_get_generic_inst (1, args);
- add_generic_class (acfg, mono_class_inflate_generic_class (enum_comparer, &ctx), FALSE, "EqualityComparer<T>");
+ enum_comparer = mono_class_from_name (mono_defaults.corlib, "System.Collections.Generic", "LongEnumEqualityComparer`1");
+ g_assert (enum_comparer);
+ ninsts = 0;
+ insts [ninsts ++] = &mono_defaults.int64_class->byval_arg;
+ insts [ninsts ++] = &mono_defaults.uint64_class->byval_arg;
+ add_instances_of (acfg, enum_comparer, insts, ninsts, FALSE);
}
/* Add instances of the array generic interfaces for primitive types */
case MONO_PATCH_INFO_SEQ_POINT_INFO:
case MONO_PATCH_INFO_AOT_MODULE:
break;
- case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
- encode_method_ref (acfg, patch_info->data.imt_tramp->method, p, &p);
- encode_value (patch_info->data.imt_tramp->vt_offset, p, &p);
- break;
case MONO_PATCH_INFO_SIGNATURE:
encode_signature (acfg, (MonoMethodSignature*)patch_info->data.target, p, &p);
break;
acfg->klass_blob_hash = g_hash_table_new (NULL, NULL);
acfg->method_blob_hash = g_hash_table_new (NULL, NULL);
acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
- mono_mutex_init_recursive (&acfg->mutex);
+ mono_os_mutex_init_recursive (&acfg->mutex);
init_got_info (&acfg->got_info);
init_got_info (&acfg->llvm_got_info);
} TrampolinePage;
static GHashTable *aot_modules;
-#define mono_aot_lock() mono_mutex_lock (&aot_mutex)
-#define mono_aot_unlock() mono_mutex_unlock (&aot_mutex)
+#define mono_aot_lock() mono_os_mutex_lock (&aot_mutex)
+#define mono_aot_unlock() mono_os_mutex_unlock (&aot_mutex)
static mono_mutex_t aot_mutex;
/*
#define USE_PAGE_TRAMPOLINES 0
#endif
-#define mono_aot_page_lock() mono_mutex_lock (&aot_page_mutex)
-#define mono_aot_page_unlock() mono_mutex_unlock (&aot_page_mutex)
+#define mono_aot_page_lock() mono_os_mutex_lock (&aot_page_mutex)
+#define mono_aot_page_unlock() mono_os_mutex_unlock (&aot_page_mutex)
static mono_mutex_t aot_page_mutex;
static MonoAotModule *mscorlib_aot_module;
static inline void
amodule_lock (MonoAotModule *amodule)
{
- mono_mutex_lock (&amodule->mutex);
+ mono_os_mutex_lock (&amodule->mutex);
}
static inline void
amodule_unlock (MonoAotModule *amodule)
{
- mono_mutex_unlock (&amodule->mutex);
+ mono_os_mutex_unlock (&amodule->mutex);
}
/*
break;
}
case MONO_AOT_TYPEREF_VAR: {
- MonoType *t;
+ MonoType *t = NULL;
MonoGenericContainer *container = NULL;
int type = decode_value (p, &p);
int num = decode_value (p, &p);
- gboolean has_container = decode_value (p, &p);
+ gboolean is_not_anonymous = decode_value (p, &p);
MonoType *gshared_constraint = NULL;
- char *par_name = NULL;
- t = NULL;
- if (has_container) {
+ if (is_not_anonymous) {
gboolean is_method = decode_value (p, &p);
if (is_method) {
t = mini_get_shared_gparam (&par_klass->byval_arg, gshared_constraint);
}
+
+ // We didn't decode is_method, so we have to infer it from type enum.
+ container = get_anonymous_container_for_image (module->assembly->image, type == MONO_TYPE_MVAR);
}
if (t) {
} else {
t = g_new0 (MonoType, 1);
t->type = type;
- if (container) {
+ if (is_not_anonymous) {
t->data.generic_param = mono_generic_container_get_param (container, num);
g_assert (gshared_constraint == NULL);
} else {
/* Anonymous */
MonoGenericParam *par = (MonoGenericParam*)mono_image_alloc0 (module->assembly->image, sizeof (MonoGenericParamFull));
+ par->owner = container;
par->num = num;
par->gshared_constraint = gshared_constraint;
- par->image = module->assembly->image;
t->data.generic_param = par;
- if (par_name)
- ((MonoGenericParamFull*)par)->info.name = par_name;
+ ((MonoGenericParamFull*)par)->info.name = make_generic_name_string (module->assembly->image, num);
}
// FIXME: Maybe use types directly to avoid
// the overhead of creating MonoClass-es
g_assert_not_reached ();
break;
}
- if (target && wrapper != target)
- return FALSE;
- ref->method = wrapper;
+ if (target) {
+ /*
+ * Due to the way mini_get_shared_method () works, we could end up with
+ * multiple copies of the same wrapper.
+ */
+ if (wrapper->klass != target->klass)
+ return FALSE;
+ ref->method = target;
+ } else {
+ ref->method = wrapper;
+ }
} else {
/*
* These wrappers are associated with a signature, not with a method.
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
g_free (err);
- aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), ARCHITECTURE, g_path_get_basename (assembly->image->name), MONO_SOLIB_EXT);
+ aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, g_path_get_basename (assembly->image->name), MONO_SOLIB_EXT);
sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
if (!sofile) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
amodule->blob = blob;
amodule->shared_got = g_new0 (gpointer, info->nshared_got_entries);
- mono_mutex_init_recursive (&amodule->mutex);
+ mono_os_mutex_init_recursive (&amodule->mutex);
/* Read image table */
{
void
mono_aot_init (void)
{
- mono_mutex_init_recursive (&aot_mutex);
- mono_mutex_init_recursive (&aot_page_mutex);
+ mono_os_mutex_init_recursive (&aot_mutex);
+ mono_os_mutex_init_recursive (&aot_page_mutex);
aot_modules = g_hash_table_new (NULL, NULL);
#ifndef __native_client__
case MONO_PATCH_INFO_AOT_MODULE:
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
break;
- case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE: {
- MonoJumpInfoImtTramp *imt_tramp = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoImtTramp));
-
- imt_tramp->method = decode_resolve_method_ref (aot_module, p, &p);
- imt_tramp->vt_offset = decode_value (p, &p);
-
- ji->data.imt_tramp = imt_tramp;
- break;
- }
case MONO_PATCH_INFO_SIGNATURE:
ji->data.target = decode_signature (aot_module, p, &p);
break;
mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
{
MonoClass *klass = method->klass;
+ MonoMethod *orig_method = method;
guint32 method_index;
MonoAotModule *amodule = klass->image->aot_module;
guint8 *code;
+ gboolean cache_result = FALSE;
+
+ if (domain != mono_get_root_domain ())
+ /* Non shared AOT code can't be used in other appdomains */
+ return NULL;
if (enable_aot_cache && !amodule && domain->entry_assembly && klass->image == mono_defaults.corlib) {
/* This cannot be AOTed during startup, so do it now */
if (code)
return code;
+ cache_result = TRUE;
method_index = find_aot_method (method, &amodule);
/*
* Special case the ICollection<T> wrappers for arrays, as they cannot
method_index = mono_metadata_token_index (method->token) - 1;
}
- return load_method (domain, amodule, klass->image, method, method->token, method_index);
+ code = load_method (domain, amodule, klass->image, method, method->token, method_index);
+ if (code && cache_result) {
+ amodule_lock (amodule);
+ g_hash_table_insert (amodule->method_to_code, orig_method, code);
+ amodule_unlock (amodule);
+ }
+ return code;
}
/**
#include <mono/metadata/assembly.h>
#include <mono/metadata/runtime.h>
#include <mono/metadata/verify-internals.h>
-#include <mono/utils/mono-semaphore.h>
+#include <mono/utils/mono-coop-mutex.h>
+#include <mono/utils/mono-coop-semaphore.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-stack-unwinding.h>
#include <mono/utils/mono-time.h>
#ifndef DISABLE_DEBUGGER_AGENT
-#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-os-mutex.h>
#define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
static gboolean debugger_thread_exited;
/* Cond variable used to wait for debugger_thread_exited becoming true */
-static mono_cond_t debugger_thread_exited_cond;
+static MonoCoopCond debugger_thread_exited_cond;
/* Mutex for the cond var above */
-static mono_mutex_t debugger_thread_exited_mutex;
+static MonoCoopMutex debugger_thread_exited_mutex;
static DebuggerProfiler debugger_profiler;
static ReplyPacket reply_packets [128];
int nreply_packets;
-#define dbg_lock() do { \
- MONO_TRY_BLOCKING; \
- mono_mutex_lock (&debug_mutex); \
- MONO_FINISH_TRY_BLOCKING; \
-} while (0)
-
-#define dbg_unlock() mono_mutex_unlock (&debug_mutex)
-static mono_mutex_t debug_mutex;
+#define dbg_lock() mono_coop_mutex_lock (&debug_mutex)
+#define dbg_unlock() mono_coop_mutex_unlock (&debug_mutex)
+static MonoCoopMutex debug_mutex;
static void transport_init (void);
static void transport_connect (const char *address);
void
mono_debugger_agent_init (void)
{
- mono_mutex_init_recursive (&debug_mutex);
+ mono_coop_mutex_init_recursive (&debug_mutex);
if (!agent_config.enabled)
return;
event_requests = g_ptr_array_new ();
- mono_mutex_init (&debugger_thread_exited_mutex);
- mono_cond_init (&debugger_thread_exited_cond, 0);
+ mono_coop_mutex_init (&debugger_thread_exited_mutex);
+ mono_coop_cond_init (&debugger_thread_exited_cond);
mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS);
breakpoints_cleanup ();
objrefs_cleanup ();
ids_cleanup ();
-
- mono_mutex_destroy (&debugger_thread_exited_mutex);
- mono_cond_destroy (&debugger_thread_exited_cond);
}
/*
/* Write handshake message */
sprintf (handshake_msg, "DWP-Handshake");
/* Must use try blocking as this can nest into code that runs blocking */
- MONO_TRY_BLOCKING;
+ MONO_PREPARE_BLOCKING;
do {
res = transport_send (handshake_msg, strlen (handshake_msg));
} while (res == -1 && get_last_sock_error () == MONO_EINTR);
- MONO_FINISH_TRY_BLOCKING;
+ MONO_FINISH_BLOCKING;
g_assert (res != -1);
/* Read answer */
- MONO_TRY_BLOCKING;
+ MONO_PREPARE_BLOCKING;
res = transport_recv (buf, strlen (handshake_msg));
- MONO_FINISH_TRY_BLOCKING;
+ MONO_FINISH_BLOCKING;
if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
return FALSE;
*/
if (!is_debugger_thread ()) {
do {
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&debugger_thread_exited_mutex);
+ mono_coop_mutex_lock (&debugger_thread_exited_mutex);
if (!debugger_thread_exited)
- mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
- mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
+ mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
} while (!debugger_thread_exited);
}
*/
static gint32 threads_suspend_count;
-static mono_mutex_t suspend_mutex;
+static MonoCoopMutex suspend_mutex;
/* Cond variable used to wait for suspend_count becoming 0 */
-static mono_cond_t suspend_cond;
+static MonoCoopCond suspend_cond;
/* Semaphore used to wait for a thread becoming suspended */
-static MonoSemType suspend_sem;
+static MonoCoopSem suspend_sem;
static void
suspend_init (void)
{
- mono_mutex_init (&suspend_mutex);
- mono_cond_init (&suspend_cond, 0);
- MONO_SEM_INIT (&suspend_sem, 0);
+ mono_coop_mutex_init (&suspend_mutex);
+ mono_coop_cond_init (&suspend_cond);
+ mono_coop_sem_init (&suspend_sem, 0);
}
typedef struct
mono_memory_barrier ();
tls->suspended = TRUE;
- MONO_SEM_POST (&suspend_sem);
+ mono_coop_sem_post (&suspend_sem);
}
}
}
{
mono_loader_lock ();
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_mutex_lock (&suspend_mutex);
suspend_count ++;
mono_g_hash_table_foreach (thread_to_tls, notify_thread, NULL);
}
- mono_mutex_unlock (&suspend_mutex);
+ mono_coop_mutex_unlock (&suspend_mutex);
if (suspend_count == 1)
/*
mono_loader_lock ();
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_mutex_lock (&suspend_mutex);
g_assert (suspend_count > 0);
suspend_count --;
}
/* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
- err = mono_cond_broadcast (&suspend_cond);
+ err = mono_coop_cond_broadcast (&suspend_cond);
g_assert (err == 0);
- mono_mutex_unlock (&suspend_mutex);
+ mono_coop_mutex_unlock (&suspend_mutex);
//g_assert (err == 0);
if (suspend_count == 0)
tls = mono_g_hash_table_lookup (thread_to_tls, thread);
g_assert (tls);
-
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING;
+
+ mono_coop_mutex_lock (&suspend_mutex);
g_assert (suspend_count > 0);
* Signal suspend_count without decreasing suspend_count, the threads will wake up
* but only the one whose resume_count field is > 0 will be resumed.
*/
- err = mono_cond_broadcast (&suspend_cond);
+ err = mono_coop_cond_broadcast (&suspend_cond);
g_assert (err == 0);
- mono_mutex_unlock (&suspend_mutex);
+ mono_coop_mutex_unlock (&suspend_mutex);
//g_assert (err == 0);
mono_loader_unlock ();
tls = mono_native_tls_get_value (debugger_tls_id);
g_assert (tls);
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_mutex_lock (&suspend_mutex);
tls->suspending = FALSE;
tls->really_suspended = TRUE;
if (!tls->suspended) {
tls->suspended = TRUE;
- MONO_SEM_POST (&suspend_sem);
+ mono_coop_sem_post (&suspend_sem);
}
DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)mono_native_thread_id_get ());
- MONO_TRY_BLOCKING;
while (suspend_count - tls->resume_count > 0) {
- err = mono_cond_wait (&suspend_cond, &suspend_mutex);
+ err = mono_coop_cond_wait (&suspend_cond, &suspend_mutex);
g_assert (err == 0);
}
- MONO_FINISH_TRY_BLOCKING;
tls->suspended = FALSE;
tls->really_suspended = FALSE;
threads_suspend_count --;
- mono_mutex_unlock (&suspend_mutex);
+ mono_coop_mutex_unlock (&suspend_mutex);
DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer)mono_native_thread_id_get ());
nwait = count_threads_to_wait_for ();
if (nwait) {
DEBUG_PRINTF (1, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads);
- err = MONO_SEM_WAIT (&suspend_sem);
+ err = mono_coop_sem_wait (&suspend_sem, MONO_SEM_FLAGS_NONE);
g_assert (err == 0);
waited = TRUE;
} else {
minfo = mono_debug_lookup_method (method);
if (minfo)
- loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
+ loc = mono_debug_method_lookup_location (minfo, sp->il_offset);
if (!loc) {
DEBUG_PRINTF (1, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)mono_native_thread_id_get (), sp->il_offset);
minfo = mono_debug_lookup_method (frame->method);
if (minfo && frame->il_offset != -1) {
- MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, frame->il_offset);
+ MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, frame->il_offset);
if (loc) {
ss_req->last_line = loc->row;
count = container->type_argc;
buffer_add_int (buf, count);
for (i = 0; i < count; i++) {
- pklass = mono_class_from_generic_parameter (mono_generic_container_get_param (container, i), klass->image, FALSE);
+ pklass = mono_class_from_generic_parameter_internal (mono_generic_container_get_param (container, i));
buffer_add_typeid (buf, domain, pklass);
}
} else {
buffer_add_int (buf, count);
for (i = 0; i < count; i++) {
MonoGenericParam *param = mono_generic_container_get_param (container, i);
- MonoClass *pklass = mono_class_from_generic_parameter (param, method->klass->image, TRUE);
+ MonoClass *pklass = mono_class_from_generic_parameter_internal (param);
buffer_add_typeid (buf, domain, pklass);
}
} else {
}
mono_set_is_debugger_attached (FALSE);
-
- MONO_TRY_BLOCKING;
- mono_mutex_lock (&debugger_thread_exited_mutex);
+
+ mono_coop_mutex_lock (&debugger_thread_exited_mutex);
debugger_thread_exited = TRUE;
- mono_cond_signal (&debugger_thread_exited_cond);
- mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING;
+ mono_coop_cond_signal (&debugger_thread_exited_cond);
+ mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");
static void
mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
-static gboolean partial_supported = FALSE;
+/* Counters */
+static int num_templates_allocted;
+static int num_templates_bytes;
+static int num_oti_allocted;
+static int num_oti_bytes;
+
+static gboolean partial_supported = TRUE;
static inline gboolean
partial_sharing_supported (void)
static MonoRuntimeGenericContextTemplate*
alloc_template (MonoClass *klass)
{
- static gboolean inited = FALSE;
- static int num_allocted = 0;
- static int num_bytes = 0;
-
int size = sizeof (MonoRuntimeGenericContextTemplate);
- if (!inited) {
- mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
- mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
- inited = TRUE;
- }
-
- num_allocted++;
- num_bytes += size;
+ num_templates_allocted++;
+ num_templates_bytes += size;
return mono_image_alloc0 (klass->image, size);
}
+/* LOCKING: Takes the loader lock */
static MonoRuntimeGenericContextInfoTemplate*
alloc_oti (MonoImage *image)
{
- static gboolean inited = FALSE;
- static int num_allocted = 0;
- static int num_bytes = 0;
-
int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
- if (!inited) {
- mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
- mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
- inited = TRUE;
- }
-
- num_allocted++;
- num_bytes += size;
+ num_oti_allocted++;
+ num_oti_bytes += size;
return mono_image_alloc0 (image, size);
}
void
mono_generic_sharing_init (void)
{
+ mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_allocted);
+ mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_templates_bytes);
+ mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_allocted);
+ mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_oti_bytes);
+
mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
}
key.param.param.gshared_constraint = constraint;
g_assert (mono_generic_param_info (par));
- /* image might not be set for sre */
- if (par->owner && par->owner->image) {
- image = par->owner->image;
+ image = get_image_for_generic_param(par);
- /*
- * Need a cache to ensure the newly created gparam
- * is unique wrt T/CONSTRAINT.
- */
- mono_image_lock (image);
- if (!image->gshared_types) {
- image->gshared_types_len = MONO_TYPE_INTERNAL;
- image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
- }
- if (!image->gshared_types [constraint->type])
- image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
- res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
- mono_image_unlock (image);
- if (res)
- return res;
- copy = mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
- memcpy (©->param, par, sizeof (MonoGenericParamFull));
- name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
- copy->param.info.name = mono_image_strdup (image, name);
- g_free (name);
- } else {
- /* mono_generic_param_name () expects this to be a MonoGenericParamFull */
- copy = g_new0 (MonoGSharedGenericParam, 1);
- memcpy (©->param, par, sizeof (MonoGenericParam));
- }
- copy->param.param.owner = NULL;
- // FIXME:
- copy->param.param.image = image ? image : mono_defaults.corlib;
+ /*
+ * Need a cache to ensure the newly created gparam
+ * is unique wrt T/CONSTRAINT.
+ */
+ mono_image_lock (image);
+ if (!image->gshared_types) {
+ image->gshared_types_len = MONO_TYPE_INTERNAL;
+ image->gshared_types = g_new0 (GHashTable*, image->gshared_types_len);
+ }
+ if (!image->gshared_types [constraint->type])
+ image->gshared_types [constraint->type] = g_hash_table_new (shared_gparam_hash, shared_gparam_equal);
+ res = g_hash_table_lookup (image->gshared_types [constraint->type], &key);
+ mono_image_unlock (image);
+ if (res)
+ return res;
+ copy = mono_image_alloc0 (image, sizeof (MonoGSharedGenericParam));
+ memcpy (©->param, par, sizeof (MonoGenericParamFull));
+ name = get_shared_gparam_name (constraint->type, ((MonoGenericParamFull*)copy)->info.name);
+ copy->param.info.name = mono_image_strdup (image, name);
+ g_free (name);
+
+ copy->param.param.owner = par->owner;
copy->param.param.gshared_constraint = constraint;
copy->parent = par;