Merge pull request #3948 from henricm/fix-pinvoke-utf8-windows
[mono.git] / mono / metadata / reflection.c
index 0a5ea615a03f73a95bfc4822f98dd4307a265158..c0c334a0f23e3b0671c51336e7144180378d7774 100644 (file)
@@ -46,6 +46,7 @@
 #include <mono/utils/mono-string.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/checked-build.h>
+#include <mono/utils/mono-counters.h>
 
 static void get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types);
 static MonoType* mono_reflection_get_type_with_rootimage (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve, MonoError *error);
@@ -53,8 +54,6 @@ static MonoType* mono_reflection_get_type_with_rootimage (MonoImage *rootimage,
 /* Class lazy loading functions */
 static GENERATE_GET_CLASS_WITH_CACHE (mono_assembly, System.Reflection, MonoAssembly)
 static GENERATE_GET_CLASS_WITH_CACHE (mono_module, System.Reflection, MonoModule)
-static GENERATE_GET_CLASS_WITH_CACHE (mono_generic_method, System.Reflection, MonoGenericMethod);
-static GENERATE_GET_CLASS_WITH_CACHE (mono_generic_cmethod, System.Reflection, MonoGenericCMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_method, System.Reflection, MonoMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_cmethod, System.Reflection, MonoCMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_field, System.Reflection, MonoField);
@@ -68,10 +67,17 @@ static GENERATE_GET_CLASS_WITH_CACHE (exception_handling_clause, System.Reflecti
 static GENERATE_GET_CLASS_WITH_CACHE (type_builder, System.Reflection.Emit, TypeBuilder);
 static GENERATE_GET_CLASS_WITH_CACHE (dbnull, System, DBNull);
 
+
+static int class_ref_info_handle_count;
+
 void
 mono_reflection_init (void)
 {
        mono_reflection_emit_init ();
+
+       mono_counters_register ("MonoClass::ref_info_handle count",
+                                                       MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ref_info_handle_count);
+
 }
 
 /*
@@ -83,11 +89,12 @@ gpointer
 mono_class_get_ref_info (MonoClass *klass)
 {
        MONO_REQ_GC_UNSAFE_MODE;
+       guint32 ref_info_handle = mono_class_get_ref_info_handle (klass);
 
-       if (klass->ref_info_handle == 0)
+       if (ref_info_handle == 0)
                return NULL;
        else
-               return mono_gchandle_get_target (klass->ref_info_handle);
+               return mono_gchandle_get_target (ref_info_handle);
 }
 
 void
@@ -95,18 +102,23 @@ mono_class_set_ref_info (MonoClass *klass, gpointer obj)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       klass->ref_info_handle = mono_gchandle_new ((MonoObject*)obj, FALSE);
-       g_assert (klass->ref_info_handle != 0);
+       guint32 candidate = mono_gchandle_new ((MonoObject*)obj, FALSE);
+       guint32 handle = mono_class_set_ref_info_handle (klass, candidate);
+       ++class_ref_info_handle_count;
+
+       if (handle != candidate)
+               mono_gchandle_free (candidate);
 }
 
 void
 mono_class_free_ref_info (MonoClass *klass)
 {
        MONO_REQ_GC_NEUTRAL_MODE;
+       guint32 handle = mono_class_get_ref_info_handle (klass);
 
-       if (klass->ref_info_handle) {
-               mono_gchandle_free (klass->ref_info_handle);
-               klass->ref_info_handle = 0;
+       if (handle) {
+               mono_gchandle_free (handle);
+               mono_class_set_ref_info_handle (klass, 0);
        }
 }
 
@@ -325,36 +337,6 @@ mono_module_file_get_object_checked (MonoDomain *domain, MonoImage *image, int t
        return res;
 }
 
-static gboolean
-verify_safe_for_managed_space (MonoType *type)
-{
-       switch (type->type) {
-#ifdef DEBUG_HARDER
-       case MONO_TYPE_ARRAY:
-               return verify_safe_for_managed_space (&type->data.array->eklass->byval_arg);
-       case MONO_TYPE_PTR:
-               return verify_safe_for_managed_space (type->data.type);
-       case MONO_TYPE_SZARRAY:
-               return verify_safe_for_managed_space (&type->data.klass->byval_arg);
-       case MONO_TYPE_GENERICINST: {
-               MonoGenericInst *inst = type->data.generic_class->inst;
-               int i;
-               if (!inst->is_open)
-                       break;
-               for (i = 0; i < inst->type_argc; ++i)
-                       if (!verify_safe_for_managed_space (inst->type_argv [i]))
-                               return FALSE;
-               return TRUE;
-       }
-#endif
-       case MONO_TYPE_VAR:
-       case MONO_TYPE_MVAR:
-               return TRUE;
-       default:
-               return TRUE;
-       }
-}
-
 static MonoType*
 mono_type_normalize (MonoType *type)
 {
@@ -375,7 +357,7 @@ mono_type_normalize (MonoType *type)
                return type;
 
        gtd = gclass->container_class;
-       gcontainer = gtd->generic_container;
+       gcontainer = mono_class_get_generic_container (gtd);
        argv = g_newa (MonoType*, ginst->type_argc);
 
        for (i = 0; i < ginst->type_argc; ++i) {
@@ -483,40 +465,10 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err
        if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder)
                g_assert (0);
 
-       if (!verify_safe_for_managed_space (type)) {
+       if (mono_class_get_ref_info (klass) && !klass->wastypebuilder && !type->byref) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
-               mono_error_set_generic_error (error, "System", "InvalidOperationException", "This type cannot be propagated to managed space");
-               return NULL;
-       }
-
-       if (mono_class_get_ref_info (klass) && !klass->wastypebuilder) {
-               gboolean is_type_done = TRUE;
-               /* Generic parameters have reflection_info set but they are not finished together with their enclosing type.
-                * We must ensure that once a type is finished we don't return a GenericTypeParameterBuilder.
-                * We can't simply close the types as this will interfere with other parts of the generics machinery.
-               */
-               if (klass->byval_arg.type == MONO_TYPE_MVAR || klass->byval_arg.type == MONO_TYPE_VAR) {
-                       MonoGenericParam *gparam = klass->byval_arg.data.generic_param;
-
-                       if (gparam->owner && gparam->owner->is_method) {
-                               MonoMethod *method = gparam->owner->owner.method;
-                               if (method && mono_class_get_generic_type_definition (method->klass)->wastypebuilder)
-                                       is_type_done = FALSE;
-                       } else if (gparam->owner && !gparam->owner->is_method) {
-                               MonoClass *klass = gparam->owner->owner.klass;
-                               if (klass && mono_class_get_generic_type_definition (klass)->wastypebuilder)
-                                       is_type_done = FALSE;
-                       }
-               } 
-
-               /* g_assert_not_reached (); */
-               /* should this be considered an error condition? */
-               if (is_type_done && !type->byref) {
-                       mono_domain_unlock (domain);
-                       mono_loader_unlock ();
-                       return (MonoReflectionType *)mono_class_get_ref_info (klass);
-               }
+               return (MonoReflectionType *)mono_class_get_ref_info (klass);
        }
        /* This is stored in vtables/JITted code so it has to be pinned */
        res = (MonoReflectionType *)mono_object_new_pinned (domain, mono_defaults.runtimetype_class, error);
@@ -575,33 +527,6 @@ mono_method_get_object_checked (MonoDomain *domain, MonoMethod *method, MonoClas
 
        mono_error_init (error);
 
-       if (method->is_inflated) {
-               MonoReflectionGenericMethod *gret;
-
-               if (!refclass)
-                       refclass = method->klass;
-               CHECK_OBJECT (MonoReflectionMethod *, method, refclass);
-               if ((*method->name == '.') && (!strcmp (method->name, ".ctor") || !strcmp (method->name, ".cctor"))) {
-                       klass = mono_class_get_mono_generic_cmethod_class ();
-               } else {
-                       klass = mono_class_get_mono_generic_method_class ();
-               }
-               gret = (MonoReflectionGenericMethod*)mono_object_new_checked (domain, klass, error);
-               if (!mono_error_ok (error))
-                       goto leave;
-               gret->method.method = method;
-
-               MONO_OBJECT_SETREF (gret, method.name, mono_string_new (domain, method->name));
-
-               rt = mono_type_get_object_checked (domain, &refclass->byval_arg, error);
-               if (!mono_error_ok (error))
-                   goto leave;
-
-               MONO_OBJECT_SETREF (gret, method.reftype, rt);
-
-               CACHE_OBJECT (MonoReflectionMethod *, method, (MonoReflectionMethod*)gret, refclass);
-       }
-
        if (!refclass)
                refclass = method->klass;
 
@@ -2149,9 +2074,7 @@ mono_reflection_get_token_checked (MonoObject *obj, MonoError *error)
 
                token = mc->type_token;
        } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
-                  strcmp (klass->name, "MonoMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericCMethod") == 0) {
+                          strcmp (klass->name, "MonoMethod") == 0) {
                MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
                if (m->method->is_inflated) {
                        MonoMethodInflated *inflated = (MonoMethodInflated *) m->method;
@@ -2214,7 +2137,6 @@ MonoType*
 mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error)
 {
        MonoClass *klass;
-       MonoReflectionTypeBuilder *tb = NULL;
        gboolean is_dynamic = FALSE;
        MonoClass *geninst;
 
@@ -2223,25 +2145,13 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
        mono_loader_lock ();
 
        if (mono_is_sre_type_builder (mono_object_class (type))) {
-               tb = (MonoReflectionTypeBuilder *) type;
-
                is_dynamic = TRUE;
        } else if (mono_is_sre_generic_instance (mono_object_class (type))) {
                MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;
                MonoReflectionType *gtd = rgi->generic_type;
 
-               if (mono_is_sre_type_builder (mono_object_class (gtd))) {
-                       tb = (MonoReflectionTypeBuilder *)gtd;
+               if (mono_is_sre_type_builder (mono_object_class (gtd)))
                        is_dynamic = TRUE;
-               }
-       }
-
-       /* FIXME: fix the CreateGenericParameters protocol to avoid the two stage setup of TypeBuilders */
-       if (tb && tb->generic_container) {
-               if (!mono_reflection_create_generic_class (tb, error)) {
-                       mono_loader_unlock ();
-                       return NULL;
-               }
        }
 
        MonoType *t = mono_reflection_type_get_handle (type, error);
@@ -2251,17 +2161,22 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
        }
 
        klass = mono_class_from_mono_type (t);
-       if (!klass->generic_container) {
+       if (!mono_class_is_gtd (klass)) {
                mono_loader_unlock ();
                mono_error_set_type_load_class (error, klass, "Cannot bind generic parameters of a non-generic type");
                return NULL;
        }
 
-       if (klass->wastypebuilder) {
-               tb = (MonoReflectionTypeBuilder *) mono_class_get_ref_info (klass);
+       guint gtd_type_argc = mono_class_get_generic_container (klass)->type_argc;
+       if (gtd_type_argc != type_argc) {
+               mono_loader_unlock ();
+               mono_error_set_argument (error, "types", "The generic type definition needs %d type arguments, but was instantiated with %d ", gtd_type_argc, type_argc);
+               return NULL;
+       }
+
 
+       if (klass->wastypebuilder)
                is_dynamic = TRUE;
-       }
 
        mono_loader_unlock ();
 
@@ -2276,7 +2191,7 @@ mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType **
        MonoGenericClass *gclass;
        MonoGenericInst *inst;
 
-       g_assert (klass->generic_container);
+       g_assert (mono_class_is_gtd (klass));
 
        inst = mono_metadata_get_generic_inst (type_argc, types);
        gclass = mono_metadata_lookup_generic_class (klass, inst, is_dynamic);
@@ -2297,13 +2212,9 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr
 
        mono_error_init (error);
 
-       /*FIXME but this no longer should happen*/
-       if (!strcmp (rmethod->object.vtable->klass->name, "MethodBuilder")) {
-               method = mono_reflection_method_builder_to_mono_method ((MonoReflectionMethodBuilder*)rmethod, error);
-               return_val_if_nok (error, NULL);
-       } else {
-               method = rmethod->method;
-       }
+       g_assert (strcmp (rmethod->object.vtable->klass->name, "MethodBuilder"));
+
+       method = rmethod->method;
 
        klass = method->klass;
 
@@ -2326,7 +2237,7 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr
        ginst = mono_metadata_get_generic_inst (count, type_argv);
        g_free (type_argv);
 
-       tmp_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL;
+       tmp_context.class_inst = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->context.class_inst : NULL;
        tmp_context.method_inst = ginst;
 
        inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error);
@@ -2350,17 +2261,7 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr
                return NULL;
        }
        
-       MonoReflectionMethod *ret = mono_method_get_object_checked (mono_object_domain (rmethod), inflated, NULL, error);
-       return ret;
-}
-
-MonoReflectionMethod*
-ves_icall_MethodBuilder_MakeGenericMethod (MonoReflectionMethod *rmethod, MonoArray *types)
-{
-       MonoError error;
-       MonoReflectionMethod *result = reflection_bind_generic_method_parameters (rmethod, types, &error);
-       mono_error_set_pending_exception (&error);
-       return result;
+       return mono_method_get_object_checked (mono_object_domain (rmethod), inflated, NULL, error);
 }
 
 MonoReflectionMethod*
@@ -2466,8 +2367,9 @@ mono_declsec_flags_from_method (MonoMethod *method)
 guint32
 mono_declsec_flags_from_class (MonoClass *klass)
 {
-       if (klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) {
-               if (!klass->ext || !klass->ext->declsec_flags) {
+       if (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_HAS_SECURITY) {
+               MonoClassExt *ext = mono_class_get_ext (klass);
+               if (!ext || !ext->declsec_flags) {
                        guint32 idx;
 
                        idx = mono_metadata_token_index (klass->type_token);
@@ -2475,11 +2377,12 @@ mono_declsec_flags_from_class (MonoClass *klass)
                        idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
                        mono_loader_lock ();
                        mono_class_alloc_ext (klass);
+                       ext = mono_class_get_ext (klass);
                        mono_loader_unlock ();
                        /* we cache the flags on classes */
-                       klass->ext->declsec_flags = mono_declsec_get_flags (klass->image, idx);
+                       ext->declsec_flags = mono_declsec_get_flags (klass->image, idx);
                }
-               return klass->ext->declsec_flags;
+               return ext->declsec_flags;
        }
        return 0;
 }