2009-12-09 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / reflection.c
index 81fdfb75859c5ccb18c72ac697f2919a483b547c..0bb970b541e81e4bdc2af18a38235fa7ee73e93b 100644 (file)
@@ -55,6 +55,9 @@ static void* reflection_info_desc = NULL;
 #define MOVING_GC_REGISTER(addr)
 #endif
 
+static gboolean is_usertype (MonoReflectionType *ref);
+static MonoReflectionType *mono_reflection_type_resolve_user_types (MonoReflectionType *type);
+
 typedef struct {
        char *p;
        char *buf;
@@ -183,7 +186,7 @@ static gboolean is_sre_byref (MonoClass *class);
 static gboolean is_sre_pointer (MonoClass *class);
 static guint32 mono_image_get_methodspec_token (MonoDynamicImage *assembly, MonoMethod *method);
 static guint32 mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m);
-static MonoMethod * inflate_method (MonoReflectionGenericClass *type, MonoObject *obj);
+static MonoMethod * inflate_method (MonoReflectionType *type, MonoObject *obj);
 
 #define RESOLVE_TYPE(type) do { type = (void*)mono_reflection_type_resolve_user_types ((MonoReflectionType*)type); } while (0)
 #define RESOLVE_ARRAY_TYPE_ELEMENT(array, index) do {  \
@@ -2598,16 +2601,29 @@ is_field_on_inst (MonoClassField *field)
 static MonoType*
 get_field_on_inst_generic_type (MonoClassField *field)
 {
+       MonoClass *class, *gtd;
        MonoDynamicGenericClass *dgclass;
        int field_index;
 
        g_assert (is_field_on_inst (field));
 
        dgclass = (MonoDynamicGenericClass*)field->parent->generic_class;
-       field_index = field - dgclass->fields;
 
-       g_assert (field_index >= 0 && field_index < dgclass->count_fields);
-       return dgclass->field_generic_types [field_index];
+       if (field >= dgclass->fields && field - dgclass->fields < dgclass->count_fields) {
+               field_index = field - dgclass->fields;
+               return dgclass->field_generic_types [field_index];              
+       }
+
+       class = field->parent;
+       gtd = class->generic_class->container_class;
+
+       if (field >= class->fields && field - class->fields < class->field.count) {
+               field_index = field - class->fields;
+               return gtd->fields [field_index].type;
+       }
+
+       g_assert_not_reached ();
+       return 0;
 }
 
 #ifndef DISABLE_REFLECTION_EMIT
@@ -5919,16 +5935,24 @@ mono_image_module_basic_init (MonoReflectionModuleBuilder *moduleb)
        MonoDynamicImage *image = moduleb->dynamic_image;
        MonoReflectionAssemblyBuilder *ab = moduleb->assemblyb;
        if (!image) {
+               MonoError error;
                int module_count;
                MonoImage **new_modules;
                MonoImage *ass;
+               char *name, *fqname;
                /*
                 * FIXME: we already created an image in mono_image_basic_init (), but
                 * we don't know which module it belongs to, since that is only 
                 * determined at assembly save time.
                 */
                /*image = (MonoDynamicImage*)ab->dynamic_assembly->assembly.image; */
-               image = create_dynamic_mono_image (ab->dynamic_assembly, mono_string_to_utf8 (ab->name), mono_string_to_utf8 (moduleb->module.fqname));
+               name = mono_string_to_utf8 (ab->name);
+               fqname = mono_string_to_utf8_checked (moduleb->module.fqname, &error);
+               if (!mono_error_ok (&error)) {
+                       g_free (name);
+                       mono_error_raise_exception (&error);
+               }
+               image = create_dynamic_mono_image (ab->dynamic_assembly, name, fqname);
 
                moduleb->module.image = &image->image;
                moduleb->dynamic_image = image;
@@ -8634,13 +8658,13 @@ mono_reflection_get_custom_attrs_data (MonoObject *obj)
 static MonoReflectionType*
 mono_reflection_type_get_underlying_system_type (MonoReflectionType* t)
 {
-        MonoMethod *method_get_underlying_system_type;
+       static MonoMethod *method_get_underlying_system_type = NULL;
+       MonoMethod *usertype_method;
 
-        method_get_underlying_system_type = mono_object_get_virtual_method ((MonoObject *) t,
-                                                                            mono_class_get_method_from_name (mono_object_class (t),
-                                                                                                             "get_UnderlyingSystemType",
-                                                                                                             0));
-        return (MonoReflectionType *) mono_runtime_invoke (method_get_underlying_system_type, t, NULL, NULL);
+       if (!method_get_underlying_system_type)
+               method_get_underlying_system_type = mono_class_get_method_from_name (mono_defaults.systemtype_class, "get_UnderlyingSystemType", 0);
+       usertype_method = mono_object_get_virtual_method ((MonoObject *) t, method_get_underlying_system_type);
+        return (MonoReflectionType *) mono_runtime_invoke (usertype_method, t, NULL, NULL);
 }
 
 #ifndef DISABLE_REFLECTION_EMIT
@@ -8651,13 +8675,6 @@ is_corlib_type (MonoClass *class)
        return class->image == mono_defaults.corlib;
 }
 
-static gboolean
-is_usertype (MonoReflectionType *ref)
-{
-       MonoClass *class = mono_object_class (ref);
-       return class->image != mono_defaults.corlib || strcmp ("TypeDelegator", class->name) == 0;
-}
-
 #define check_corlib_type_cached(_class, _namespace, _name) do { \
        static MonoClass *cached_class; \
        if (cached_class) \
@@ -8693,6 +8710,12 @@ is_sre_generic_instance (MonoClass *class)
        check_corlib_type_cached (class, "System.Reflection", "MonoGenericClass");
 }
 
+static gboolean
+is_sre_type_builder (MonoClass *class)
+{
+       check_corlib_type_cached (class, "System.Reflection.Emit", "TypeBuilder");
+}
+
 MonoType*
 mono_reflection_type_get_handle (MonoReflectionType* ref)
 {
@@ -8761,20 +8784,7 @@ mono_reflection_type_get_handle (MonoReflectionType* ref)
        return NULL;
 }
 
-static MonoReflectionType*
-mono_reflection_type_resolve_user_types (MonoReflectionType *type)
-{
-       if (!type || type->type)
-               return type;
-
-       if (is_usertype (type)) {
-               type = mono_reflection_type_get_underlying_system_type (type);
-               if (is_usertype (type))
-                       mono_raise_exception (mono_get_exception_not_supported ("User defined subclasses of System.Type are not yet supported22"));
-       }
 
-       return type;
-}
 
 void
 mono_reflection_create_unmanaged_type (MonoReflectionType *type)
@@ -8872,6 +8882,27 @@ get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
 }
 #endif /* !DISABLE_REFLECTION_EMIT */
 
+static gboolean
+is_usertype (MonoReflectionType *ref)
+{
+       MonoClass *class = mono_object_class (ref);
+       return class->image != mono_defaults.corlib || strcmp ("TypeDelegator", class->name) == 0;
+}
+
+static MonoReflectionType*
+mono_reflection_type_resolve_user_types (MonoReflectionType *type)
+{
+       if (!type || type->type)
+               return type;
+
+       if (is_usertype (type)) {
+               type = mono_reflection_type_get_underlying_system_type (type);
+               if (is_usertype (type))
+                       mono_raise_exception (mono_get_exception_not_supported ("User defined subclasses of System.Type are not yet supported22"));
+       }
+
+       return type;
+}
 /*
  * Encode a value in a custom attribute stream of bytes.
  * The value to encode is either supplied as an object in argument val
@@ -10086,12 +10117,24 @@ inflate_mono_method (MonoClass *klass, MonoMethod *method, MonoObject *obj)
 }
 
 static MonoMethod *
-inflate_method (MonoReflectionGenericClass *type, MonoObject *obj)
+inflate_method (MonoReflectionType *type, MonoObject *obj)
 {
        MonoMethod *method;
        MonoClass *gklass;
 
-       gklass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)type->generic_type));
+       MonoClass *type_class = mono_object_class (type);
+
+       if (is_sre_generic_instance (type_class)) {
+               MonoReflectionGenericClass *mgc = (MonoReflectionGenericClass*)type;
+               gklass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)mgc->generic_type));
+       } else if (is_sre_type_builder (type_class)) {
+               gklass = mono_class_from_mono_type (mono_reflection_type_get_handle (type));
+       } else if (type->type) {
+               gklass = mono_class_from_mono_type (type->type);
+               gklass = mono_class_get_generic_type_definition (gklass);
+       } else {
+               g_error ("Can't handle type %s", mono_type_get_full_name (mono_object_class (type)));
+       }
 
        if (!strcmp (obj->vtable->klass->name, "MethodBuilder"))
                if (((MonoReflectionMethodBuilder*)obj)->mhandle)
@@ -10155,13 +10198,13 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
        for (i = 0; i < dgclass->count_methods; i++) {
                MonoObject *obj = mono_array_get (methods, gpointer, i);
 
-               dgclass->methods [i] = inflate_method (type, obj);
+               dgclass->methods [i] = inflate_method ((MonoReflectionType*)type, obj);
        }
 
        for (i = 0; i < dgclass->count_ctors; i++) {
                MonoObject *obj = mono_array_get (ctors, gpointer, i);
 
-               dgclass->ctors [i] = inflate_method (type, obj);
+               dgclass->ctors [i] = inflate_method ((MonoReflectionType*)type, obj);
        }
 
        for (i = 0; i < dgclass->count_fields; i++) {
@@ -10203,9 +10246,9 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
                        property->attrs = pb->attrs;
                        property->name = mono_string_to_utf8 (pb->name);
                        if (pb->get_method)
-                               property->get = inflate_method (type, (MonoObject *) pb->get_method);
+                               property->get = inflate_method ((MonoReflectionType*)type, (MonoObject *) pb->get_method);
                        if (pb->set_method)
-                               property->set = inflate_method (type, (MonoObject *) pb->set_method);
+                               property->set = inflate_method ((MonoReflectionType*)type, (MonoObject *) pb->set_method);
                } else if (!strcmp (obj->vtable->klass->name, "MonoProperty")) {
                        *property = *((MonoReflectionProperty *) obj)->property;
                        property->name = g_strdup (property->name);
@@ -10229,9 +10272,9 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
                        event->attrs = eb->attrs;
                        event->name = mono_string_to_utf8 (eb->name);
                        if (eb->add_method)
-                               event->add = inflate_method (type, (MonoObject *) eb->add_method);
+                               event->add = inflate_method ((MonoReflectionType*)type, (MonoObject *) eb->add_method);
                        if (eb->remove_method)
-                               event->remove = inflate_method (type, (MonoObject *) eb->remove_method);
+                               event->remove = inflate_method ((MonoReflectionType*)type, (MonoObject *) eb->remove_method);
                } else if (!strcmp (obj->vtable->klass->name, "MonoEvent")) {
                        *event = *((MonoReflectionMonoEvent *) obj)->event;
                        event->name = g_strdup (event->name);
@@ -10248,34 +10291,55 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
 }
 
 static void
-ensure_generic_class_runtime_vtable (MonoClass *klass)
+fix_partial_generic_class (MonoClass *klass)
 {
        MonoClass *gklass = klass->generic_class->container_class;
+       MonoDynamicGenericClass *dgclass;
        int i;
 
        if (klass->wastypebuilder)
                return;
 
-       ensure_runtime_vtable (gklass);
+       dgclass = (MonoDynamicGenericClass *)  klass->generic_class;
 
-       klass->method.count = gklass->method.count;
-       klass->methods = mono_image_alloc (klass->image, sizeof (MonoMethod*) * (klass->method.count + 1));
+       if (!dgclass->initialized)
+               return;
+
+       if (klass->method.count != gklass->method.count) {
+               klass->method.count = gklass->method.count;
+               klass->methods = mono_image_alloc (klass->image, sizeof (MonoMethod*) * (klass->method.count + 1));
+
+               for (i = 0; i < klass->method.count; i++) {
+                       klass->methods [i] = mono_class_inflate_generic_method_full (
+                               gklass->methods [i], klass, mono_class_get_context (klass));
+               }
+       }
 
-       for (i = 0; i < klass->method.count; i++) {
-               klass->methods [i] = mono_class_inflate_generic_method_full (
-                       gklass->methods [i], klass, mono_class_get_context (klass));
+       if (klass->interface_count && klass->interface_count != gklass->interface_count) {
+               klass->interface_count = gklass->interface_count;
+               klass->interfaces = mono_image_alloc (klass->image, sizeof (MonoClass*) * gklass->interface_count);
+               klass->interfaces_packed = NULL; /*make setup_interface_offsets happy*/
+
+               for (i = 0; i < gklass->interface_count; ++i) {
+                       MonoType *iface_type = mono_class_inflate_generic_type (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass));
+                       klass->interfaces [i] = mono_class_from_mono_type (iface_type);
+                       mono_metadata_free_type (iface_type);
+
+                       ensure_runtime_vtable (klass->interfaces [i]);
+               }
+               klass->interfaces_inited = 1;
        }
 
-       klass->interface_count = gklass->interface_count;
-       klass->interfaces = mono_image_alloc (klass->image, sizeof (MonoClass*) * klass->interface_count);
-       for (i = 0; i < klass->interface_count; ++i) {
-               MonoType *iface_type = mono_class_inflate_generic_type (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass));
-               klass->interfaces [i] = mono_class_from_mono_type (iface_type);
-               mono_metadata_free_type (iface_type);
+       if (klass->field.count != gklass->field.count) {
+               klass->field.count = gklass->field.count;
+               klass->fields = image_g_new0 (klass->image, MonoClassField, klass->field.count);
 
-               ensure_runtime_vtable (klass->interfaces [i]);
+               for (i = 0; i < klass->field.count; i++) {
+                       klass->fields [i] = gklass->fields [i];
+                       klass->fields [i].parent = klass;
+                       klass->fields [i].type = mono_class_inflate_generic_type (gklass->fields [i].type, mono_class_get_context (klass));
+               }
        }
-       klass->interfaces_inited = 1;
 
        /*We can only finish with this klass once it's parent has as well*/
        if (gklass->wastypebuilder)
@@ -10283,6 +10347,16 @@ ensure_generic_class_runtime_vtable (MonoClass *klass)
        return;
 }
 
+static void
+ensure_generic_class_runtime_vtable (MonoClass *klass)
+{
+       MonoClass *gklass = klass->generic_class->container_class;
+
+       ensure_runtime_vtable (gklass); 
+
+       fix_partial_generic_class (klass);
+}
+
 static void
 ensure_runtime_vtable (MonoClass *klass)
 {
@@ -10325,6 +10399,7 @@ ensure_runtime_vtable (MonoClass *klass)
                for (i = 0; i < klass->method.count; ++i)
                        klass->methods [i]->slot = i;
                
+               klass->interfaces_packed = NULL; /*make setup_interface_offsets happy*/
                mono_class_setup_interface_offsets (klass);
                mono_class_setup_interface_id (klass);
        }
@@ -10576,16 +10651,17 @@ typebuilder_setup_events (MonoClass *klass, MonoError *error)
 }
 
 static gboolean
-remove_instantiations_of (gpointer key,
+remove_instantiations_of_and_ensure_contents (gpointer key,
                                                  gpointer value,
                                                  gpointer user_data)
 {
        MonoType *type = (MonoType*)key;
        MonoClass *klass = (MonoClass*)user_data;
 
-       if ((type->type == MONO_TYPE_GENERICINST) && (type->data.generic_class->container_class == klass))
+       if ((type->type == MONO_TYPE_GENERICINST) && (type->data.generic_class->container_class == klass)) {
+               fix_partial_generic_class (mono_class_from_mono_type (type)); //Ensure it's safe to use it.
                return TRUE;
-       else
+       else
                return FALSE;
 }
 
@@ -10745,9 +10821,11 @@ mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb)
         * If we are a generic TypeBuilder, there might be instantiations in the type cache
         * which have type System.Reflection.MonoGenericClass, but after the type is created, 
         * we want to return normal System.MonoType objects, so clear these out from the cache.
+        *
+        * Together with this we must ensure the contents of all instances to match the created type.
         */
        if (domain->type_hash && klass->generic_container)
-               mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of, klass);
+               mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of_and_ensure_contents, klass);
 
        mono_domain_unlock (domain);
        mono_loader_unlock ();