Dont leak loader errors in the aot compiler, as it could cause later methods to not...
[mono.git] / mono / mini / mini-generic-sharing.c
index 912efbfc84889a721b58f881aa2f79bc4fa4fa93..018054018d8d7821eff5e82ec348bbe2d0f8cf44 100644 (file)
@@ -236,12 +236,6 @@ register_generic_subclass (MonoClass *class)
        MonoClass *parent = class->parent;
        MonoClass *subclass;
        MonoRuntimeGenericContextTemplate *rgctx_template = class_lookup_rgctx_template (class);
-       static gboolean hook_installed;
-
-       if (!hook_installed) {
-               mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
-               hook_installed = TRUE;
-       }
 
        g_assert (rgctx_template);
 
@@ -365,6 +359,17 @@ alloc_oti (MonoImage *image)
 
 #define MONO_RGCTX_SLOT_USED_MARKER    ((gpointer)&mono_defaults.object_class->byval_arg)
 
+/*
+ * Return true if this info type has the notion of identify.
+ *
+ * Some info types expect that each insert results in a new slot been assigned.
+ */
+static int
+other_info_has_identity (int info_type)
+{
+       return info_type != MONO_RGCTX_INFO_CAST_CACHE;
+}
+
 /*
  * LOCKING: loader lock
  */
@@ -500,7 +505,8 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M
        case MONO_RGCTX_INFO_KLASS:
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
-       case MONO_RGCTX_INFO_REFLECTION_TYPE: {
+       case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE: {
                gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
                        data, context, &error);
                g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
@@ -577,6 +583,7 @@ free_inflated_info (int info_type, gpointer info)
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                mono_metadata_free_type (info);
                break;
        default:
@@ -595,6 +602,41 @@ class_uninstantiated (MonoClass *class)
        return class;
 }
 
+static gboolean
+generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
+                                                 gboolean allow_partial)
+{
+       gboolean has_refs;
+       int i;
+
+       has_refs = FALSE;
+       for (i = 0; i < inst->type_argc; ++i) {
+               MonoType *type = inst->type_argv [i];
+
+               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
+                       has_refs = TRUE;
+       }
+       for (i = 0; i < inst->type_argc; ++i) {
+               MonoType *type = inst->type_argv [i];
+
+               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
+                       continue;
+               /*
+                * Allow non ref arguments, if there is at least one ref argument
+                * (partial sharing).
+                * FIXME: Allow more types
+                */
+               if (allow_partial && !type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
+                       continue;
+
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 /*
  * mono_is_partially_sharable_inst:
  *
@@ -658,6 +700,9 @@ get_shared_class (MonoClass *class)
                        g_free (type_argv);
 
                        return mono_class_inflate_generic_class (class->generic_class->container_class, &shared_context);
+               } else if (!generic_inst_is_sharable (inst, TRUE, FALSE)) {
+                       /* Happens for partially shared methods of nono-sharable generic class */
+                       return class;
                }
        }
 
@@ -684,7 +729,7 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
        if (template)
                return template;
 
-       g_assert (get_shared_class (class) == class);
+       //g_assert (get_shared_class (class) == class);
 
        template = alloc_template (class);
 
@@ -812,6 +857,12 @@ class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
                        mono_raise_exception (mono_class_get_exception_for_failure (class));
                return vtable;
        }
+       case MONO_RGCTX_INFO_CAST_CACHE: {
+               /*First slot is the cache itself, the second the vtable.*/
+               gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
+               cache_data [1] = (gpointer)class;
+               return cache_data;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -833,6 +884,7 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        case MONO_RGCTX_INFO_STATIC_DATA:
        case MONO_RGCTX_INFO_KLASS:
        case MONO_RGCTX_INFO_VTABLE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                temporary = TRUE;
                break;
        default:
@@ -844,7 +896,8 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        switch (oti->info_type) {
        case MONO_RGCTX_INFO_STATIC_DATA:
        case MONO_RGCTX_INFO_KLASS:
-       case MONO_RGCTX_INFO_VTABLE: {
+       case MONO_RGCTX_INFO_VTABLE:
+       case MONO_RGCTX_INFO_CAST_CACHE: {
                MonoClass *arg_class = mono_class_from_mono_type (data);
 
                free_inflated_info (oti->info_type, data);
@@ -924,7 +977,6 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
                MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
                MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
 
-               g_assert (!subclass->generic_class);
                g_assert (subclass_template);
 
                subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index, FALSE, FALSE, NULL);
@@ -992,6 +1044,7 @@ other_info_equal (gpointer data1, gpointer data2, int info_type)
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
        case MONO_RGCTX_INFO_METHOD:
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
@@ -1022,22 +1075,24 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, i
 
        mono_loader_lock ();
 
-       oti_list = get_other_info_templates (rgctx_template, type_argc);
+       if (other_info_has_identity (info_type)) {
+               oti_list = get_other_info_templates (rgctx_template, type_argc);
 
-       for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
-               gpointer inflated_data;
+               for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
+                       gpointer inflated_data;
 
-               if (oti->info_type != info_type || !oti->data)
-                       continue;
+                       if (oti->info_type != info_type || !oti->data)
+                               continue;
 
-               inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
+                       inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
 
-               if (other_info_equal (data, inflated_data, info_type)) {
+                       if (other_info_equal (data, inflated_data, info_type)) {
+                               free_inflated_info (info_type, inflated_data);
+                               mono_loader_unlock ();
+                               return i;
+                       }
                        free_inflated_info (info_type, inflated_data);
-                       mono_loader_unlock ();
-                       return i;
                }
-               free_inflated_info (info_type, inflated_data);
        }
 
        /* We haven't found the info */
@@ -1356,41 +1411,6 @@ mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst
        return mrgctx;
 }
 
-static gboolean
-generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars,
-                                                 gboolean allow_partial)
-{
-       gboolean has_refs;
-       int i;
-
-       has_refs = FALSE;
-       for (i = 0; i < inst->type_argc; ++i) {
-               MonoType *type = inst->type_argv [i];
-
-               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
-                       has_refs = TRUE;
-       }
-       for (i = 0; i < inst->type_argc; ++i) {
-               MonoType *type = inst->type_argv [i];
-
-               if (MONO_TYPE_IS_REFERENCE (type) || (allow_type_vars && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)))
-                       continue;
-               /*
-                * Allow non ref arguments, if there is at least one ref argument
-                * (partial sharing).
-                * FIXME: Allow more types
-                */
-               if (!type->byref && type->type == MONO_TYPE_I4 && has_refs && allow_partial)
-                       continue;
-
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
 /*
  * mono_generic_context_is_sharable_full:
  * @context: a generic context
@@ -1856,4 +1876,14 @@ mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint3
 void
 mono_generic_sharing_init (void)
 {
+       mono_install_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
+}
+
+void
+mono_generic_sharing_cleanup (void)
+{
+       mono_remove_image_unload_hook (mono_class_unregister_image_generic_subclasses, NULL);
+
+       if (generic_subclass_hash)
+               g_hash_table_destroy (generic_subclass_hash);
 }