Merge pull request #2237 from xmcclure/container-owner
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 7 Dec 2015 01:43:37 +0000 (20:43 -0500)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 7 Dec 2015 01:43:37 +0000 (20:43 -0500)
Unambiguous ownership of generic param objects

1  2 
mono/metadata/class.c
mono/metadata/icall.c
mono/metadata/image.c
mono/metadata/loader.c
mono/metadata/metadata.c
mono/metadata/reflection.c
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/debugger-agent.c
mono/mini/mini-generic-sharing.c

diff --combined mono/metadata/class.c
index 132c3a745cd4b70c880f867e1c2945890d26b301,55dfcc1a488f6254f0d17fff813568b5ed05dc3c..342faae81789e1996052f8959b26af6bbc3f67d7
@@@ -43,6 -43,7 +43,7 @@@
  #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;
  
@@@ -103,13 -104,13 +104,13 @@@ typedef gboolean (*gclass_record_func) 
  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);
  }
  
  /* 
@@@ -4268,7 -4269,7 +4269,7 @@@ verify_class_overrides (MonoClass *klas
                }
  
                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;
                }
  
@@@ -5692,13 -5693,16 +5693,16 @@@ mono_class_setup_supertypes (MonoClass 
        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
@@@ -5808,6 -5812,7 +5812,7 @@@ mono_class_create_from_typedef (MonoIma
        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;
        }
  
@@@ -5977,7 -5982,7 +5982,7 @@@ parent_failure
        return NULL;
  }
  
- /** is klass Nullable<T>? */
+ /** Is klass a Nullable<T> ginst? */
  gboolean
  mono_class_is_nullable (MonoClass *klass)
  {
@@@ -6117,42 -6122,84 +6122,84 @@@ mono_generic_class_get_class (MonoGener
        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)
  {
@@@ -6539,10 -6601,9 +6601,9 @@@ mono_class_from_mono_type (MonoType *ty
                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 ();
@@@ -6637,11 -6698,11 +6698,11 @@@ mono_bounded_array_class_get (MonoClas
                 * 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);
@@@ -9800,7 -9861,7 +9861,7 @@@ mono_class_get_exception_data (MonoClas
  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);
@@@ -9825,7 -9886,7 +9886,7 @@@ mono_classes_cleanup (void
        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);
  }
  
  /**
diff --combined mono/metadata/icall.c
index 584dff8ffcf78022d1268bc95577924ec56dcaf9,a4a6e9202d65b15ae71f9bc40f5882d79a9d500f..f2d76301c3c7d267a7cf9b3cf318c473b369a905
@@@ -89,7 -89,7 +89,7 @@@
  #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)
@@@ -2324,7 -2324,7 +2324,7 @@@ ves_icall_MonoType_GetGenericArguments 
                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) {
@@@ -2678,8 -2678,7 +2678,7 @@@ ves_icall_MonoMethod_GetGenericArgument
        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));
        }
@@@ -3567,17 -3566,6 +3566,17 @@@ property_hash (gconstpointer data
        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;
  }
  
@@@ -7293,19 -7265,19 +7292,19 @@@ mono_icall_init (void
  #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
@@@ -7314,7 -7286,7 +7313,7 @@@ mono_icall_cleanup (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
diff --combined mono/metadata/image.c
index 9035d99aaa69c839b4653ffeda334d8cd54c18ec,a82df45a5bfd6ae83b322c6d07112e528b6de672..dbe802939861bc131a7a5c7b94c2ecb6ac7b4963
@@@ -79,8 -79,8 +79,8 @@@ static GHashTable *get_loaded_images_by
  
  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;
  
@@@ -222,7 -222,7 +222,7 @@@ mono_image_rva_map (MonoImage *image, g
  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++)
@@@ -246,7 -246,7 +246,7 @@@ mono_images_cleanup (void
        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.
@@@ -713,8 -713,8 +713,8 @@@ class_next_value (gpointer value
  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,
@@@ -1062,7 -1062,7 +1062,7 @@@ do_mono_image_load (MonoImage *image, M
                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) {
@@@ -1847,8 -1847,8 +1847,8 @@@ mono_image_close_except_pools (MonoImag
        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)) {
@@@ -2469,13 -2469,13 +2469,13 @@@ g_slist_append_image (MonoImage *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);
  }
  
  
@@@ -2538,51 -2538,24 +2538,24 @@@ mono_image_append_class_to_reflection_i
        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
diff --combined mono/metadata/loader.c
index be83f8f68d3589c58e2828c4320bc5e171e913ea,0cb4cb401d62e7985e1403914389035fd9820574..d2136bbfc6419667341cf5066afe5afd7140a877
@@@ -56,8 -56,7 +56,8 @@@ MonoDefaults mono_defaults
   * 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 */
@@@ -83,13 -82,13 +83,13 @@@ static void dllmap_cleanup (void)
  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
@@@ -98,8 -97,8 +98,8 @@@ mono_loader_init (
        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);
@@@ -127,8 -126,8 +127,8 @@@ mono_loader_cleanup (void
        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;     
  }
  
@@@ -1943,6 -1942,7 +1943,7 @@@ mono_get_method_from_token (MonoImage *
        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;
@@@ -2541,7 -2541,10 +2542,7 @@@ static gboolean loader_lock_track_owner
  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));
        }
diff --combined mono/metadata/metadata.c
index 21f4895e259083fc027af3e07aa1798acf5771ee,e8eaed11c9e7c5d20fe704043caa18b8d59fd287..7aa5300a753aaeebd2063a4603a4b57195efea61
@@@ -28,6 -28,7 +28,7 @@@
  #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 {
@@@ -1492,10 -1493,14 +1493,14 @@@ mono_generic_inst_equal_full (const Mon
  {
        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;
        }
@@@ -1557,7 -1562,7 +1562,7 @@@ mono_metadata_init (void
        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);
  }
  
  /**
@@@ -1573,7 -1578,7 +1578,7 @@@ mono_metadata_cleanup (void
        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);
  }
  
  /**
@@@ -1611,7 -1616,7 +1616,7 @@@ mono_metadata_parse_type_internal (Mono
        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);
        }
@@@ -2288,43 -2294,9 +2294,9 @@@ retry
                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);
  }
  
  /*
@@@ -2355,11 -2327,12 +2327,12 @@@ get_image_set (MonoImage **images, int 
        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);
  
@@@ -2445,20 -2426,20 +2426,20 @@@ delete_image_set (MonoImageSet *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
@@@ -2503,6 -2484,24 +2484,24 @@@ mono_image_set_strdup (MonoImageSet *se
        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.
   */
@@@ -2637,48 -2636,13 +2636,13 @@@ retry
        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);
@@@ -3016,12 -2980,11 +2980,11 @@@ mono_metadata_lookup_generic_class (Mon
        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);
  
@@@ -3195,7 -3158,36 +3158,36 @@@ select_container (MonoGenericContainer 
        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.
@@@ -3214,12 -3206,24 +3206,24 @@@ mono_metadata_parse_generic_param (Mono
  
        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;
        }
@@@ -4931,12 -4935,8 +4935,8 @@@ mono_metadata_generic_param_equal_inter
         * 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;
  
        /*
@@@ -5014,6 -5014,7 +5014,7 @@@ mono_metadata_fnptr_equal (MonoMethodSi
   * 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.
@@@ -6212,7 -6213,8 +6213,8 @@@ mono_metadata_load_generic_params (Mono
        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);
@@@ -6638,3 -6640,32 +6640,32 @@@ mono_method_get_wrapper_cache (MonoMeth
                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;
+ }
index a6874280ae0781d657c50d95cad05f9a5a3892bd,30fbd69cf074408271947540d68000609181fc6e..9a65942432c83f060deb46011bc23ea4095d738f
@@@ -215,6 -215,48 +215,48 @@@ static void init_type_builder_generics 
  #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
@@@ -5338,6 -5380,15 +5380,15 @@@ create_dynamic_mono_image (MonoDynamicA
        
        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
@@@ -5368,6 -5419,7 +5419,7 @@@ mono_dynamic_image_release_gc_roots (Mo
        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)
  {
@@@ -10688,6 -10748,7 +10748,7 @@@ reflection_methodbuilder_to_mono_metho
                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);
@@@ -11888,7 -11949,8 +11949,8 @@@ mono_reflection_initialize_generic_para
                         * 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;
  
diff --combined mono/mini/aot-compiler.c
index e32a875d2ac945d6a64bd4a57fd8d5b6e80e991b,e828ba9d3d12bc5fcf107fbf2ab2ae109a4349de..67cf7924434cddab73471f621e42539ae60008fc
@@@ -251,8 -251,8 +251,8 @@@ typedef struct 
        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;
@@@ -2508,10 -2508,9 +2508,9 @@@ encode_klass_ref_inner (MonoAotCompile 
                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
@@@ -3058,6 -3057,7 +3057,6 @@@ is_plt_patch (MonoJumpInfo *patch_info
        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;
@@@ -4482,39 -4482,24 +4481,39 @@@ add_generic_instances (MonoAotCompile *
                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 */
@@@ -5362,6 -5347,10 +5361,6 @@@ encode_patch (MonoAotCompile *acfg, Mon
        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;
@@@ -9313,7 -9302,7 +9312,7 @@@ acfg_create (MonoAssembly *ass, guint3
        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);
diff --combined mono/mini/aot-runtime.c
index 6efdadfa4d523191172f2f61504f51a7646005b4,82e78f2a48b27da3de064c0cd0d95a05990da095..f56ff6e19a2d4d8477c403f75656b8a90e582813
@@@ -155,8 -155,8 +155,8 @@@ typedef struct 
  } 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;
  
  /* 
@@@ -201,8 -201,8 +201,8 @@@ static GHashTable *aot_jit_icall_hash
  #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;
@@@ -222,13 -222,13 +222,13 @@@ decode_patches (MonoAotModule *amodule
  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);
  }
  
  /*
@@@ -471,16 -471,14 +471,14 @@@ decode_klass_ref (MonoAotModule *module
                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
@@@ -1122,17 -1122,9 +1122,17 @@@ decode_method_ref_with_target (MonoAotM
                                        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.
@@@ -1890,7 -1882,7 +1890,7 @@@ load_aot_module (MonoAssembly *assembly
                                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 */
        {
@@@ -2192,8 -2184,8 +2192,8 @@@ mono_aot_register_module (gpointer *aot
  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__
@@@ -3453,6 -3445,15 +3453,6 @@@ decode_patch (MonoAotModule *aot_module
        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;
@@@ -4095,15 -4096,9 +4095,15 @@@ gpointe
  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;
  }
  
  /**
index fe827352e2bff76c153c1650ba8f42e01d92856a,87e05f89264656b7dc8617d51d43dd490f1ffd93..68e91c69713543f8adc162ff4a146becdd23ffb9
@@@ -62,8 -62,7 +62,8 @@@
  #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>
@@@ -92,7 -91,7 +92,7 @@@
  
  #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
  
@@@ -681,10 -680,10 +681,10 @@@ static GPtrArray *pending_assembly_load
  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;
  
@@@ -716,9 -715,14 +716,9 @@@ static gboolean buffer_replies
  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);
@@@ -957,7 -961,7 +957,7 @@@ mono_debugger_agent_parse_options (cha
  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);
@@@ -1100,6 -1104,9 +1100,6 @@@ mono_debugger_agent_cleanup (void
        breakpoints_cleanup ();
        objrefs_cleanup ();
        ids_cleanup ();
 -      
 -      mono_mutex_destroy (&debugger_thread_exited_mutex);
 -      mono_cond_destroy (&debugger_thread_exited_cond);
  }
  
  /*
@@@ -1531,18 -1538,18 +1531,18 @@@ transport_handshake (void
        /* 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;
@@@ -1597,10 -1604,12 +1597,10 @@@ stop_debugger_thread (void
         */
        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);
        }
  
@@@ -2471,20 -2480,20 +2471,20 @@@ save_thread_context (MonoContext *ctx
   */
  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
@@@ -2599,7 -2608,7 +2599,7 @@@ thread_interrupt (DebuggerTlsData *tls
                        mono_memory_barrier ();
  
                        tls->suspended = TRUE;
 -                      MONO_SEM_POST (&suspend_sem);
 +                      mono_coop_sem_post (&suspend_sem);
                }
        }
  }
@@@ -2738,7 -2747,9 +2738,7 @@@ suspend_vm (void
  {
        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)
                /*
@@@ -2776,7 -2787,9 +2776,7 @@@ resume_vm (void
  
        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)
@@@ -2819,8 -2832,10 +2819,8 @@@ resume_thread (MonoInternalThread *thre
  
        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 ();
@@@ -2895,29 -2910,33 +2895,29 @@@ suspend_current (void
        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 ());
  
@@@ -2976,7 -2995,7 +2976,7 @@@ wait_for_suspend (void
                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 {
@@@ -4545,7 -4564,7 +4545,7 @@@ ss_update (SingleStepReq *req, MonoJitI
        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);
@@@ -5343,7 -5362,7 +5343,7 @@@ ss_create (MonoInternalThread *thread, 
  
                                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;
@@@ -7913,7 -7932,7 +7913,7 @@@ type_commands_internal (int command, Mo
                                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 {
@@@ -8525,7 -8544,7 +8525,7 @@@ method_commands_internal (int command, 
                                                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 {
@@@ -9722,11 -9741,13 +9722,11 @@@ debugger_thread (void *arg
        }
  
        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");
        
index 69de50e4be0c04d2b40a9681314f33f0755acbea,a0841764ada79ee43107e7b5b8fbc2d443225608..a90afecd82dd6e8a2ca9cbcb925f6d6383e84220
  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)
@@@ -346,22 -340,41 +346,22 @@@ mono_class_unregister_image_generic_sub
  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);
  }
@@@ -2611,11 -2624,6 +2611,11 @@@ mini_type_stack_size_full (MonoType *t
  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);
  }
  
@@@ -2771,38 -2779,30 +2771,30 @@@ mini_get_shared_gparam (MonoType *t, Mo
        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 (&copy->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 (&copy->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 (&copy->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;