2009-05-16 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / class.c
index 7c3d3f7cbc20e3edb463a751dcbab54acf219972..a6e7e437ce5a1454899cd25d907a000cb6a58505 100644 (file)
@@ -15,7 +15,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <signal.h>
 #if !PLATFORM_WIN32
 #include <mono/io-layer/atomic.h>
 #endif
@@ -298,9 +297,11 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
        }
        case MONO_TYPE_VAR:
        case MONO_TYPE_MVAR:
-               g_assert (type->data.generic_param->name);
-               g_string_append (str, type->data.generic_param->name);
-       
+               if (!mono_generic_param_info (type->data.generic_param))
+                       g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
+               else
+                       g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
+
                mono_type_name_check_byref (type, str);
 
                break;
@@ -368,7 +369,7 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                        for (i = 0; i < klass->generic_container->type_argc; i++) {
                                if (i)
                                        g_string_append_c (str, ',');
-                               g_string_append (str, mono_generic_container_get_param (klass->generic_container, i)->name);
+                               g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
                        }
                        if (format == MONO_TYPE_NAME_FORMAT_IL) 
                                g_string_append_c (str, '>');
@@ -497,7 +498,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                if (!inst || !inst->type_argv)
                        return NULL;
                if (num >= inst->type_argc)
-                       g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
+                       g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations",
+                               num, mono_generic_param_info (type->data.generic_param)->name, inst->type_argc);
 
                /*
                 * Note that the VAR/MVAR cases are different from the rest.  The other cases duplicate @type,
@@ -516,7 +518,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                if (!inst)
                        return NULL;
                if (num >= inst->type_argc)
-                       g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc);
+                       g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations",
+                               num, mono_generic_param_info (type->data.generic_param)->name, inst->type_argc);
                nt = mono_metadata_type_dup (image, inst->type_argv [num]);
                nt->byref = type->byref;
                nt->attrs = type->attrs;
@@ -1071,6 +1074,7 @@ mono_class_setup_fields (MonoClass *class)
                MonoClass *gklass = class->generic_class->container_class;
                mono_class_setup_fields (gklass);
                top = gklass->field.count;
+               class->field.first = gklass->field.first;
                class->field.count = gklass->field.count;
        }
 
@@ -1778,12 +1782,6 @@ mono_class_get_vtable_entry (MonoClass *class, int offset)
                m = class->vtable [offset];
        }
 
-       /* 
-        * We have to add static rgctx wrappers somewhere, we do it here, 
-        * altough it should probably be done by the JIT.
-        */
-       if (mono_method_needs_static_rgctx_invoke (m, FALSE))
-               m = mono_marshal_get_static_rgctx_invoke (m);
        return m;
 }
 
@@ -4481,75 +4479,52 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        return klass;
 }
 
-/*
- * LOCKING: Acquires the loader lock.
- */
-MonoClass *
-mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+static MonoClass*
+make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is_mvar, MonoGenericParamInfo *pinfo)
 {
-       MonoGenericContainer *container;
        MonoClass *klass, **ptr;
        int count, pos, i;
 
-       mono_loader_lock ();
-
-       if (param->pklass) {
-               mono_loader_unlock ();
-               return param->pklass;
-       }
-
-       container = mono_generic_param_owner (param);
-       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;
-               }
-       }
        if (!image)
                /* FIXME: */
                image = mono_defaults.corlib;
 
        klass = mono_image_alloc0 (image, sizeof (MonoClass));
-
        classes_size += sizeof (MonoClass);
 
-       if (param->name)
-               klass->name = param->name;
-       else {
+       if (pinfo) {
+               klass->name = pinfo->name;
+       else {
                int n = mono_generic_param_num (param);
                klass->name = mono_image_alloc0 (image, 16);
-               sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", n);
+               sprintf ((char*)klass->name, "%d", n);
        }
+
        klass->name_space = "";
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
-       
-       for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++)
-               ;
+
+       count = 0;
+       if (pinfo)
+               for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
+                       ;
 
        pos = 0;
-       if ((count > 0) && !MONO_CLASS_IS_INTERFACE (param->constraints [0])) {
-               klass->parent = param->constraints [0];
+       if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
+               klass->parent = pinfo->constraints [0];
                pos++;
-       } else if (param->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)
+       } 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;
 
+
        if (count - pos > 0) {
                klass->interface_count = count - pos;
                klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos));
                for (i = pos; i < count; i++)
-                       klass->interfaces [i - pos] = param->constraints [i];
+                       klass->interfaces [i - pos] = pinfo->constraints [i];
        }
 
-       if (!image)
-               image = mono_defaults.corlib;
-
        klass->image = image;
 
        klass->inited = TRUE;
@@ -4560,39 +4535,107 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
        klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param;
        klass->this_arg.byref = TRUE;
 
+       /* FIXME: shouldn't this be ->type_token? */
+       klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
+
+       mono_class_setup_supertypes (klass);
+
+       return klass;
+}
+
+#define FAST_CACHE_SIZE 1024
+static MonoClass *var_cache_fast [FAST_CACHE_SIZE];
+static MonoClass *mvar_cache_fast [FAST_CACHE_SIZE];
+static GHashTable *var_cache_slow;
+static GHashTable *mvar_cache_slow;
+
+static MonoClass *
+get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
+{
+       int n = mono_generic_param_num (param);
+       GHashTable *ht;
+
+       if (n < FAST_CACHE_SIZE)
+               return (is_mvar ? mvar_cache_fast : var_cache_fast) [n];
+       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+}
+
+static void
+set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
+{
+       int n = mono_generic_param_num (param);
+       GHashTable *ht;
+
+       if (n < FAST_CACHE_SIZE) {
+               (is_mvar ? mvar_cache_fast : var_cache_fast) [n] = klass;
+               return;
+       }
+       ht = is_mvar ? mvar_cache_slow : var_cache_slow;
+       if (!ht) {
+               ht = g_hash_table_new (NULL, NULL);
+               if (is_mvar)
+                       mvar_cache_slow = ht;
+               else
+                       var_cache_slow = ht;
+       }
+
+       g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
+}
+
+/*
+ * LOCKING: Acquires the loader lock.
+ */
+MonoClass *
+mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
+{
+       MonoGenericContainer *container = mono_generic_param_owner (param);
+       MonoGenericParamInfo *pinfo;
+       MonoClass *klass;
+
+       mono_loader_lock ();
+
        if (container) {
-               guint32 owner;
-               guint32 cols [MONO_GENERICPARAM_SIZE];
-               MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAM];
-               i = 0;
-
-               if (is_mvar && container->owner.method)
-                        i = mono_metadata_get_generic_param_row (image, container->owner.method->token, &owner);
-               else if (!is_mvar && container->owner.klass)
-                        i = mono_metadata_get_generic_param_row (image, container->owner.klass->type_token, &owner);
-
-               if (i) {
-                       mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
-                       do {
-                               if (cols [MONO_GENERICPARAM_NUMBER] == mono_generic_param_num (param)) {
-                                       klass->sizes.generic_param_token = i | MONO_TOKEN_GENERIC_PARAM;
-                                       break;
-                               }
-                               if (++i > tdef->rows)
-                                       break;
-                               mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
-                       } while (cols [MONO_GENERICPARAM_OWNER] == owner);
+               pinfo = mono_generic_param_info (param);
+               if (pinfo->pklass) {
+                       mono_loader_unlock ();
+                       return pinfo->pklass;
+               }
+       } else {
+               pinfo = NULL;
+               image = NULL;
+
+               klass = get_anon_gparam_class (param, is_mvar);
+               if (klass) {
+                       mono_loader_unlock ();
+                       return klass;
                }
        }
 
-       mono_class_setup_supertypes (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);
 
        mono_memory_barrier ();
 
-       param->pklass = klass;
+       if (container)
+               pinfo->pklass = klass;
+       else
+               set_anon_gparam_class (param, is_mvar, klass);
 
        mono_loader_unlock ();
 
+       /* FIXME: Should this go inside 'make_generic_param_klass'? */
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
        return klass;
@@ -5887,7 +5930,7 @@ mono_class_has_variant_generic_params (MonoClass *klass)
        container = klass->generic_class->container_class->generic_container;
 
        for (i = 0; i < container->type_argc; ++i)
-               if (mono_generic_container_get_param (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+               if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
                        return TRUE;
 
        return FALSE;
@@ -5965,9 +6008,9 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
                                                 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
                                                 */
                                                if (param1_class != param2_class) {
-                                                       if ((mono_generic_container_get_param (container, i)->flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+                                                       if ((mono_generic_container_get_param_info (container, i)->flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
                                                                ;
-                                                       else if (((mono_generic_container_get_param (container, i)->flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+                                                       else if (((mono_generic_container_get_param_info (container, i)->flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
                                                                ;
                                                        else {
                                                                match = FALSE;
@@ -7469,7 +7512,15 @@ can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
 static gboolean
 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
-       int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+       int access_level;
+
+       if (access_klass->element_class && !access_klass->enumtype)
+               access_klass = access_klass->element_class;
+
+       if (member_klass->element_class && !member_klass->enumtype)
+               member_klass = member_klass->element_class;
+
+       access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
 
        if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
                return TRUE;
@@ -7758,6 +7809,14 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
        return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
 }
 
+static gboolean gshared_supported;
+
+void
+mono_set_generic_sharing_supported (gboolean supported)
+{
+       gshared_supported = supported;
+}
+
 /*
  * mono_class_generic_sharing_enabled:
  * @class: a class
@@ -7771,19 +7830,13 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
 gboolean
 mono_class_generic_sharing_enabled (MonoClass *class)
 {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__mono_ppc__)
-       static gboolean supported = TRUE;
-#else
-       /* Not supported by the JIT backends */
-       static gboolean supported = FALSE;
-#endif
        static int generic_sharing = MONO_GENERIC_SHARING_NONE;
        static gboolean inited = FALSE;
 
        if (!inited) {
                const char *option;
 
-               if (supported)
+               if (gshared_supported)
                        generic_sharing = MONO_GENERIC_SHARING_ALL;
                else
                        generic_sharing = MONO_GENERIC_SHARING_NONE;
@@ -7801,7 +7854,7 @@ mono_class_generic_sharing_enabled (MonoClass *class)
                                g_warning ("Unknown generic sharing option `%s'.", option);
                }
 
-               if (!supported)
+               if (!gshared_supported)
                        generic_sharing = MONO_GENERIC_SHARING_NONE;
 
                inited = TRUE;