2008-11-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / reflection.c
index 78bb2be54357a2aededbaafd1ab34fe78d37a67a..d1745fdda389edddb3ea31b874a3f5a310ac9aeb 100644 (file)
@@ -822,12 +822,6 @@ encode_locals (MonoDynamicImage *assembly, MonoReflectionILGen *ilgen)
        int i;
 
        sigbuffer_init (&buf, 32);
-       table = &assembly->tables [MONO_TABLE_STANDALONESIG];
-       idx = table->next_idx ++;
-       table->rows ++;
-       alloc_table (table, table->rows);
-       values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
-
        sigbuffer_add_value (&buf, 0x07);
        sigbuffer_add_value (&buf, nl);
        for (i = 0; i < nl; ++i) {
@@ -841,8 +835,22 @@ encode_locals (MonoDynamicImage *assembly, MonoReflectionILGen *ilgen)
        sig_idx = sigbuffer_add_to_blob_cached (assembly, &buf);
        sigbuffer_free (&buf);
 
+       if (assembly->standalonesig_cache == NULL)
+               assembly->standalonesig_cache = g_hash_table_new (NULL, NULL);
+       idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx)));
+       if (idx)
+               return idx;
+
+       table = &assembly->tables [MONO_TABLE_STANDALONESIG];
+       idx = table->next_idx ++;
+       table->rows ++;
+       alloc_table (table, table->rows);
+       values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
+
        values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
 
+       g_hash_table_insert (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx), GUINT_TO_POINTER (idx));
+
        return idx;
 }
 
@@ -2512,19 +2520,55 @@ mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtor
        return token;
 }
 
+static gboolean
+is_field_on_inst (MonoClassField *field)
+{
+       return (field->parent->generic_class && field->parent->generic_class->is_dynamic && ((MonoDynamicGenericClass*)field->parent->generic_class)->fields);
+}
+
+/*
+ * If FIELD is a field of a MonoDynamicGenericClass, return its non-inflated type.
+ */
+static MonoType*
+get_field_on_inst_generic_type (MonoClassField *field)
+{
+       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];
+}
+
 static guint32
 mono_image_get_fieldref_token (MonoDynamicImage *assembly, MonoReflectionField *f)
 {
        MonoType *type;
        guint32 token;
+       MonoClassField *field;
 
        token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, f));
        if (token)
                return token;
        g_assert (f->field->parent);
-       type = f->field->generic_info ? f->field->generic_info->generic_type : f->field->type;
+
+       field = f->field;
+       if (field->parent->generic_class && field->parent->generic_class->container_class && field->parent->generic_class->container_class->fields) {
+               int index = field - field->parent->fields;
+               type = field->parent->generic_class->container_class->fields [index].type;
+       } else {
+               if (is_field_on_inst (f->field))
+                       type = get_field_on_inst_generic_type (f->field);
+               else
+                       type = f->field->type;
+       }
        token = mono_image_get_memberref_token (assembly, &f->field->parent->byval_arg, 
-               f->field->name,  fieldref_encode_signature (assembly, type));
+                                                                                       mono_field_get_name (f->field),  
+                                                                                       fieldref_encode_signature (assembly, type));
        g_hash_table_insert (assembly->handleref, f, GUINT_TO_POINTER(token));
        return token;
 }
@@ -3567,6 +3611,19 @@ compare_declsecurity_attrs (const void *a, const void *b)
        return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
 }
 
+static int
+compare_interface_impl (const void *a, const void *b)
+{
+       const guint32 *a_values = a;
+       const guint32 *b_values = b;
+
+       int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
+       if (klass)
+               return klass;
+
+       return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
+}
+
 static void
 pad_heap (MonoDynamicStream *sh)
 {
@@ -3629,7 +3686,8 @@ build_compressed_metadata (MonoDynamicImage *assembly)
                | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
                | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
                | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
-               | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM);
+               | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
+               | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
        
        /* Compute table sizes */
        /* the MonoImage has already been created in mono_image_basic_init() */
@@ -3766,6 +3824,9 @@ build_compressed_metadata (MonoDynamicImage *assembly)
        table = &assembly->tables [MONO_TABLE_DECLSECURITY];
        if (table->rows)
                qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
+       table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
+       if (table->rows)
+               qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
 
        /* compress the tables */
        for (i = 0; i < MONO_TABLE_NUM; i++){
@@ -3884,7 +3945,7 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
                                MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
-                               g_assert (f->generic_info);
+                               g_assert (is_field_on_inst (f));
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
                                        !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
@@ -4554,7 +4615,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
                /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
        } else if (strcmp (klass->name, "MonoField") == 0) {
                MonoReflectionField *f = (MonoReflectionField *)obj;
-               if ((f->field->parent->image == &assembly->image) && !f->field->generic_info) {
+               if ((f->field->parent->image == &assembly->image) && !is_field_on_inst (f->field)) {
                        static guint32 field_table_idx = 0xffffff;
                        field_table_idx --;
                        token = MONO_TOKEN_FIELD_DEF | field_table_idx;
@@ -4737,6 +4798,8 @@ mono_dynamic_image_free (MonoDynamicImage *image)
                g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
                g_hash_table_destroy (di->blob_cache);
        }
+       if (di->standalonesig_cache)
+               g_hash_table_destroy (di->standalonesig_cache);
        for (list = di->array_methods; list; list = list->next) {
                ArrayMethod *am = (ArrayMethod *)list->data;
                g_free (am->sig);
@@ -5974,6 +6037,10 @@ mono_type_get_object (MonoDomain *domain, MonoType *type)
         */
        type = klass->byval_arg.byref == type->byref ? &klass->byval_arg : &klass->this_arg;
 
+       /* void is very common */
+       if (type->type == MONO_TYPE_VOID && domain->typeof_void)
+               return (MonoReflectionType*)domain->typeof_void;
+
        /*
         * If the vtable of the given class was already created, we can use
         * the MonoType from there and avoid all locking and hash table lookups.
@@ -6025,6 +6092,10 @@ mono_type_get_object (MonoDomain *domain, MonoType *type)
 #endif
        res->type = type;
        mono_g_hash_table_insert (domain->type_hash, type, res);
+
+       if (type->type == MONO_TYPE_VOID)
+               MONO_OBJECT_SETREF (domain, typeof_void, res);
+
        mono_domain_unlock (domain);
        return res;
 }
@@ -6120,9 +6191,9 @@ mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *fie
        res = (MonoReflectionField *)mono_object_new (domain, monofield_klass);
        res->klass = klass;
        res->field = field;
-       MONO_OBJECT_SETREF (res, name, mono_string_new (domain, field->name));
-       if (field->generic_info)
-               res->attrs = field->generic_info->generic_type->attrs;
+       MONO_OBJECT_SETREF (res, name, mono_string_new (domain, mono_field_get_name (field)));
+       if (is_field_on_inst (field))
+               res->attrs = get_field_on_inst_generic_type (field)->attrs;
        else
                res->attrs = field->type->attrs;
        MONO_OBJECT_SETREF (res, type, mono_type_get_object (domain, field->type));
@@ -7179,9 +7250,15 @@ mono_reflection_get_token (MonoObject *obj)
        } else if (strcmp (klass->name, "MonoField") == 0) {
                MonoReflectionField *f = (MonoReflectionField*)obj;
 
-               if (f->field->generic_info && f->field->generic_info->reflection_info)
-                       return mono_reflection_get_token (f->field->generic_info->reflection_info);
+               if (is_field_on_inst (f->field)) {
+                       MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass*)f->field->parent->generic_class;
+                       int field_index = f->field - dgclass->fields;
+                       MonoObject *obj;
 
+                       g_assert (field_index >= 0 && field_index < dgclass->count_fields);
+                       obj = dgclass->field_objects [field_index];
+                       return mono_reflection_get_token (obj);
+               }
                token = mono_class_get_field_token (f->field);
        } else if (strcmp (klass->name, "MonoProperty") == 0) {
                MonoReflectionProperty *p = (MonoReflectionProperty*)obj;
@@ -8339,7 +8416,7 @@ get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
                *type = fb->type->type;
        } else {
                MonoReflectionField *f = (MonoReflectionField *)field;
-               *name = g_strdup (f->field->name);
+               *name = g_strdup (mono_field_get_name (f->field));
                *type = f->field->type;
        }
 }
@@ -9364,8 +9441,6 @@ static MonoClassField*
 fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb)
 {
        MonoClassField *field;
-       const char *p, *p2;
-       guint32 len, idx;
        MonoType *custom;
 
        field = g_new0 (MonoClassField, 1);
@@ -9382,24 +9457,12 @@ fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder*
        } else {
                field->type = fb->type->type;
        }
-       if ((fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) && fb->rva_data)
-               field->data = mono_array_addr (fb->rva_data, char, 0); /* FIXME: GC pin array */
        if (fb->offset != -1)
                field->offset = fb->offset;
        field->parent = klass;
        mono_save_custom_attrs (klass->image, field, fb->cattrs);
 
-       if (fb->def_value) {
-               MonoDynamicImage *assembly = (MonoDynamicImage*)klass->image;
-               field->type->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
-               idx = encode_constant (assembly, fb->def_value, &field->def_type);
-               /* Copy the data from the blob since it might get realloc-ed */
-               p = assembly->blob.data + idx;
-               len = mono_metadata_decode_blob_size (p, &p2);
-               len += p2 - p;
-               field->data = g_malloc (len);
-               memcpy ((gpointer)field->data, p, len);
-       }
+       // FIXME: Can't store fb->def_value/RVA, is it needed for field_on_insts ?
 
        return field;
 }
@@ -9638,6 +9701,8 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
        dgclass->fields = g_new0 (MonoClassField, dgclass->count_fields);
        dgclass->properties = g_new0 (MonoProperty, dgclass->count_properties);
        dgclass->events = g_new0 (MonoEvent, dgclass->count_events);
+       dgclass->field_objects = g_new0 (MonoObject*, dgclass->count_fields);
+       dgclass->field_generic_types = g_new0 (MonoType*, dgclass->count_fields);
 
        for (i = 0; i < dgclass->count_methods; i++) {
                MonoObject *obj = mono_array_get (methods, gpointer, i);
@@ -9654,7 +9719,6 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
        for (i = 0; i < dgclass->count_fields; i++) {
                MonoObject *obj = mono_array_get (fields, gpointer, i);
                MonoClassField *field, *inflated_field = NULL;
-               MonoInflatedField *ifield;
 
                if (!strcmp (obj->vtable->klass->name, "FieldBuilder"))
                        inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj);
@@ -9665,19 +9729,15 @@ mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, Mono
                        g_assert_not_reached ();
                }
 
-               ifield = g_new0 (MonoInflatedField, 1);
-               ifield->generic_type = field->type;
-               MOVING_GC_REGISTER (&ifield->reflection_info);
-               ifield->reflection_info = obj;
-
                dgclass->fields [i] = *field;
                dgclass->fields [i].parent = klass;
-               dgclass->fields [i].generic_info = ifield;
                dgclass->fields [i].type = mono_class_inflate_generic_type (
                        field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass));
+               dgclass->field_generic_types [i] = field->type;
+               MOVING_GC_REGISTER (&dgclass->field_objects [i]);
+               dgclass->field_objects [i] = obj;
 
                if (inflated_field) {
-                       g_free ((char*)inflated_field->data);
                        g_free (inflated_field);
                } else {
                        dgclass->fields [i].name = g_strdup (dgclass->fields [i].name);
@@ -9869,6 +9929,7 @@ typebuilder_setup_fields (MonoClass *klass)
        }
        
        klass->fields = mp_g_new0 (mp, MonoClassField, klass->field.count);
+       klass->field_def_values = mp_g_new0 (mp, MonoFieldDefaultValue, klass->field.count);
 
        for (i = 0; i < klass->field.count; ++i) {
                fb = mono_array_get (tb->fields, gpointer, i);
@@ -9881,7 +9942,7 @@ typebuilder_setup_fields (MonoClass *klass)
                        field->type = fb->type->type;
                }
                if ((fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) && fb->rva_data)
-                       field->data = mono_array_addr (fb->rva_data, char, 0);
+                       klass->field_def_values [i].data = mono_array_addr (fb->rva_data, char, 0);
                if (fb->offset != -1)
                        field->offset = fb->offset;
                field->parent = klass;
@@ -9891,13 +9952,13 @@ typebuilder_setup_fields (MonoClass *klass)
                if (fb->def_value) {
                        MonoDynamicImage *assembly = (MonoDynamicImage*)klass->image;
                        field->type->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
-                       idx = encode_constant (assembly, fb->def_value, &field->def_type);
+                       idx = encode_constant (assembly, fb->def_value, &klass->field_def_values [i].def_type);
                        /* Copy the data from the blob since it might get realloc-ed */
                        p = assembly->blob.data + idx;
                        len = mono_metadata_decode_blob_size (p, &p2);
                        len += p2 - p;
-                       field->data = mono_mempool_alloc (mp, len);
-                       memcpy ((gpointer)field->data, p, len);
+                       klass->field_def_values [i].data = mono_mempool_alloc (mp, len);
+                       memcpy ((gpointer)klass->field_def_values [i].data, p, len);
                }
        }
 
@@ -10432,7 +10493,7 @@ resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, Mon
                        MonoType *type = mono_class_inflate_generic_type (&klass->byval_arg, context);
                        MonoClass *inflated = mono_class_from_mono_type (type);
 
-                       result = mono_class_get_field_from_name (inflated, fb->handle->name);
+                       result = mono_class_get_field_from_name (inflated, mono_field_get_name (fb->handle));
                        g_assert (result);
                        mono_metadata_free_type (type);
                }
@@ -10513,7 +10574,7 @@ resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, Mon
                inflated = mono_class_from_mono_type (type);
 
                g_assert (f->fb->handle);
-               result = mono_class_get_field_from_name (inflated, f->fb->handle->name);
+               result = mono_class_get_field_from_name (inflated, mono_field_get_name (f->fb->handle));
                g_assert (result);
                mono_metadata_free_type (type);
                *handle_class = mono_defaults.fieldhandle_class;