2002-08-14 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / metadata / class.c
index 8f2bb790c3bb5816b0cb0aeaa20bc9a5cce2e676..e39982c4d49abf66be8d0dd77317f14565b3e9c1 100644 (file)
@@ -189,6 +189,35 @@ class_compute_field_layout (MonoClass *class)
        MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
        int i, blittable = TRUE;
        guint32 rva;
+       guint32 packing_size = 0;
+
+       if (class->size_inited)
+               return;
+
+       if (class->parent) {
+               if (!class->parent->size_inited)
+                       class_compute_field_layout (class->parent);
+               class->instance_size += class->parent->instance_size;
+               class->class_size += class->parent->class_size;
+               class->min_align = class->parent->min_align;
+       } else {
+               class->instance_size = sizeof (MonoObject);
+               class->min_align = 1;
+       }
+
+       if (mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &class->instance_size)) {
+               class->instance_size += sizeof (MonoObject);
+       }
+
+       g_assert ((packing_size & 0xfffffff0) == 0);
+       class->packing_size = packing_size;
+
+       if (!top) {
+               class->size_inited = 1;
+               return;
+       }
+
+       class->fields = g_new0 (MonoClassField, top);
 
        /*
         * Fetch all the field information.
@@ -232,6 +261,9 @@ class_compute_field_layout (MonoClass *class)
                }
        }
 
+       if (class == mono_defaults.string_class)
+               blittable = FALSE;
+
        class->blittable = blittable;
 
        if (class->enumtype && !class->enum_basetype) {
@@ -441,108 +473,27 @@ mono_get_unique_iid (MonoClass *class)
        return iid - 1;
 }
 
-/**
- * mono_class_init:
- * @class: the class to initialize
- *
- * compute the instance_size, class_size and other infos that cannot be 
- * computed at mono_class_get() time. Also compute a generic vtable and 
- * the method slot numbers. We use this infos later to create a domain
- * specific vtable.  
- */
 void
-mono_class_init (MonoClass *class)
+mono_class_setup_vtable (MonoClass *class)
 {
        MonoClass *k, *ic;
        MonoMethod **vtable;
-       int i, max_vtsize = 0, max_iid, cur_slot = 0;
-       static MonoMethod *default_ghc = NULL;
-       static MonoMethod *default_finalize = NULL;
-       static int finalize_slot = -1;
-       static int ghc_slot = -1;
-       guint32 packing_size = 0;
-
-       g_assert (class);
-
-       if (class->inited)
-               return;
-
-       if (class->init_pending) {
-               /* this indicates a cyclic dependency */
-               g_error ("pending init %s.%s\n", class->name_space, class->name);
-       }
-
-       class->init_pending = 1;
-
-       mono_stats.initialized_class_count++;
+       int i, onum = 0, max_vtsize = 0, max_iid, cur_slot = 0;
+       MonoMethod **overrides;
 
+       for (i = 0; i < class->interface_count; i++) 
+               max_vtsize += class->interfaces [i]->method.count;
+       
        if (class->parent) {
-               if (!class->parent->inited)
-                       mono_class_init (class->parent);
-               class->instance_size += class->parent->instance_size;
-               class->class_size += class->parent->class_size;
-               class->min_align = class->parent->min_align;
+               max_vtsize += class->parent->vtable_size;
                cur_slot = class->parent->vtable_size;
-       } else
-               class->min_align = 1;
-
-       if (mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &class->instance_size)) {
-               class->instance_size += sizeof (MonoObject);
        }
 
-       g_assert ((packing_size & 0xfffffff0) == 0);
-       class->packing_size = packing_size;
-
-       /*
-        * Computes the size used by the fields, and their locations
-        */
-       if (!class->size_inited && class->field.count > 0){
-               class->fields = g_new0 (MonoClassField, class->field.count);
-               class_compute_field_layout (class);
-       }
-
-       if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
-               for (i = 0; i < class->interface_count; i++) 
-                       max_vtsize += class->interfaces [i]->method.count;
-       
-               if (class->parent)
-                       max_vtsize += class->parent->vtable_size;
-
-               max_vtsize += class->method.count;
-       }
+       max_vtsize += class->method.count;
 
        vtable = alloca (sizeof (gpointer) * max_vtsize);
        memset (vtable, 0, sizeof (gpointer) * max_vtsize);
 
-       /* initialize method pointers */
-       class->methods = g_new (MonoMethod*, class->method.count);
-       for (i = 0; i < class->method.count; ++i)
-               class->methods [i] = mono_get_method (class->image,
-                       MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class);
-
-       init_properties (class);
-       init_events (class);
-
-       i = mono_metadata_nesting_typedef (class->image, class->type_token);
-       while (i) {
-               MonoClass* nclass;
-               guint32 cols [MONO_NESTED_CLASS_SIZE];
-               mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
-               if (cols [MONO_NESTED_CLASS_ENCLOSING] != mono_metadata_token_index (class->type_token))
-                       break;
-               nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
-               class->nested_classes = g_list_prepend (class->nested_classes, nclass);
-               ++i;
-       }
-
-       if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               for (i = 0; i < class->method.count; ++i)
-                       class->methods [i]->slot = i;
-               class->init_pending = 0;
-               class->inited = 1;
-               return;
-       }
-
        /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
 
        /* compute maximum number of slots and maximum interface id */
@@ -588,7 +539,20 @@ mono_class_init (MonoClass *class)
 
        if (class->parent && class->parent->vtable_size)
                memcpy (vtable, class->parent->vtable,  sizeof (gpointer) * class->parent->vtable_size);
+
+       overrides = mono_class_get_overrides (class->image, class->type_token, &onum);
+
+       /* override interface methods */
+       for (i = 0; i < onum; i++) {
+               MonoMethod *decl = overrides [i*2];
+               if (decl->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                       int dslot;
+                       g_assert (decl->slot != -1);
+                       dslot = decl->slot + class->interface_offsets [decl->klass->interface_id];
+                       vtable [dslot] = overrides [i*2 + 1];
+               }
+       }
+
        for (k = class; k ; k = k->parent) {
                for (i = 0; i < k->interface_count; i++) {
                        int j, l, io;
@@ -686,6 +650,10 @@ mono_class_init (MonoClass *class)
                                        MonoMethod *im = ic->methods [l];                                               
                                        g_assert (io + l <= max_vtsize);
                                        if (!(vtable [io + l])) {
+                                               for (j = 0; j < onum; ++j) {
+                                                       g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name, 
+                                                                overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
+                                               }
                                                msig = mono_signature_get_desc (im->signature, FALSE);
                                                printf ("no implementation for interface method %s.%s::%s(%s) in class %s.%s\n",
                                                        ic->name_space, ic->name, im->name, msig, class->name_space, class->name);
@@ -758,14 +726,21 @@ mono_class_init (MonoClass *class)
                        vtable [cm->slot] = cm;
        }
 
+       /* override non interface methods */
+       for (i = 0; i < onum; i++) {
+               MonoMethod *decl = overrides [i*2];
+               if (!(decl->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                       g_assert (decl->slot != -1);
+                       vtable [decl->slot] = overrides [i*2 + 1];
+               }
+       }
+       
+       g_free (overrides);
 
        class->vtable_size = cur_slot;
        class->vtable = g_malloc0 (sizeof (gpointer) * class->vtable_size);
        memcpy (class->vtable, vtable,  sizeof (gpointer) * class->vtable_size);
 
-       class->inited = 1;
-       class->init_pending = 0;
-
        if (mono_print_vtable) {
                int icount = 0;
 
@@ -810,11 +785,88 @@ mono_class_init (MonoClass *class)
                }
        }
 
+}
+
+/**
+ * mono_class_init:
+ * @class: the class to initialize
+ *
+ * compute the instance_size, class_size and other infos that cannot be 
+ * computed at mono_class_get() time. Also compute a generic vtable and 
+ * the method slot numbers. We use this infos later to create a domain
+ * specific vtable.  
+ */
+void
+mono_class_init (MonoClass *class)
+{
+       int i;
+       static MonoMethod *default_ghc = NULL;
+       static MonoMethod *default_finalize = NULL;
+       static int finalize_slot = -1;
+       static int ghc_slot = -1;
+
+       g_assert (class);
+
+       if (class->inited)
+               return;
+
+       if (class->init_pending) {
+               /* this indicates a cyclic dependency */
+               g_error ("pending init %s.%s\n", class->name_space, class->name);
+       }
+
+       class->init_pending = 1;
+
+       mono_stats.initialized_class_count++;
+
+       if (class->parent && !class->parent->inited)
+               mono_class_init (class->parent);
+
+       /*
+        * Computes the size used by the fields, and their locations
+        */
+       if (!class->size_inited)
+               class_compute_field_layout (class);
+
+       /* initialize method pointers */
+       class->methods = g_new (MonoMethod*, class->method.count);
+       for (i = 0; i < class->method.count; ++i)
+               class->methods [i] = mono_get_method (class->image,
+                       MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class);
+
+       init_properties (class);
+       init_events (class);
+
+       i = mono_metadata_nesting_typedef (class->image, class->type_token);
+       while (i) {
+               MonoClass* nclass;
+               guint32 cols [MONO_NESTED_CLASS_SIZE];
+               mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
+               if (cols [MONO_NESTED_CLASS_ENCLOSING] != mono_metadata_token_index (class->type_token))
+                       break;
+               nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
+               class->nested_classes = g_list_prepend (class->nested_classes, nclass);
+               ++i;
+       }
+
+       if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               for (i = 0; i < class->method.count; ++i)
+                       class->methods [i]->slot = i;
+               class->init_pending = 0;
+               class->inited = 1;
+               return;
+       }
+
+       mono_class_setup_vtable (class);
+
+       class->inited = 1;
+       class->init_pending = 0;
+
        if (!default_ghc) {
                if (class == mono_defaults.object_class) { 
                       
                        for (i = 0; i < class->vtable_size; ++i) {
-                               MonoMethod *cm = vtable [i];
+                               MonoMethod *cm = class->vtable [i];
               
                                if (!strcmp (cm->name, "GetHashCode")) {
                                        ghc_slot = i;
@@ -824,14 +876,14 @@ mono_class_init (MonoClass *class)
 
                        g_assert (ghc_slot > 0);
 
-                       default_ghc = vtable [ghc_slot];
+                       default_ghc = class->vtable [ghc_slot];
                }
        }
        
        class->ghcimpl = 1;
        if (class != mono_defaults.object_class) { 
 
-               if (vtable [ghc_slot] == default_ghc) {
+               if (class->vtable [ghc_slot] == default_ghc) {
                        class->ghcimpl = 0;
                }
        }
@@ -840,7 +892,7 @@ mono_class_init (MonoClass *class)
                if (class == mono_defaults.object_class) { 
                       
                        for (i = 0; i < class->vtable_size; ++i) {
-                               MonoMethod *cm = vtable [i];
+                               MonoMethod *cm = class->vtable [i];
               
                                if (!strcmp (cm->name, "Finalize")) {
                                        finalize_slot = i;
@@ -850,14 +902,14 @@ mono_class_init (MonoClass *class)
 
                        g_assert (finalize_slot > 0);
 
-                       default_finalize = vtable [finalize_slot];
+                       default_finalize = class->vtable [finalize_slot];
                }
        }
 
        /* Object::Finalize should have empty implemenatation */
        class->has_finalize = 0;
        if (class != mono_defaults.object_class) { 
-               if (vtable [finalize_slot] != default_finalize)
+               if (class->vtable [finalize_slot] != default_finalize)
                        class->has_finalize = 1;
        }
 }
@@ -934,6 +986,7 @@ mono_class_setup_mono_type (MonoClass *class)
                        case 'D':
                                if (!strcmp (name, "Double")) {
                                        t = MONO_TYPE_R8;
+                                       class->blittable = TRUE;                                                
                                }
                                break;
                        case 'I':
@@ -954,6 +1007,7 @@ mono_class_setup_mono_type (MonoClass *class)
                        case 'S':
                                if (!strcmp (name, "Single")) {
                                        t = MONO_TYPE_R4;
+                                       class->blittable = TRUE;                                                
                                } else if (!strcmp(name, "SByte")) {
                                        t = MONO_TYPE_I1;
                                        class->blittable = TRUE;
@@ -1059,7 +1113,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        guint icount = 0; 
        MonoClass **interfaces;
 
-       if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token))))
+       if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) 
                return class;
 
        g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
@@ -1139,10 +1193,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
 
        /*class->interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &class->interface_count); */
 
-       if (class->enumtype) {
-               class->fields = g_new0 (MonoClassField, class->field.count);
+       if (class->enumtype)
                class_compute_field_layout (class);
-       } 
 
        if ((type_token = mono_metadata_nested_in_typedef (image, type_token)))
                class->nested_in = mono_class_create_from_typedef (image, type_token);
@@ -1290,7 +1342,7 @@ mono_array_class_get (MonoType *element_type, guint32 rank)
        MonoClass *class;
        MonoClass *parent = NULL;
        GSList *list;
-       int rnum = 0;
+       int rnum = 0, nsize;
 
        eclass = mono_class_from_mono_type (element_type);
        g_assert (rank <= 255);
@@ -1313,8 +1365,15 @@ mono_array_class_get (MonoType *element_type, guint32 rank)
        class = g_malloc0 (sizeof (MonoClass) + parent->vtable_size * sizeof (gpointer));
 
        class->image = image;
-       class->name_space = "System";
-       class->name = "Array";
+       class->name_space = eclass->name_space;
+       nsize = strlen (eclass->name);
+       class->name = g_malloc (nsize + 2 + rank);
+       memcpy (class->name, eclass->name, nsize);
+       class->name [nsize] = '[';
+       if (rank > 1)
+               memset (class->name + nsize + 1, ',', rank - 1);
+       class->name [nsize + rank] = ']';
+       class->name [nsize + rank + 1] = 0;
        class->type_token = 0;
        class->flags = TYPE_ATTRIBUTE_CLASS;
        class->parent = parent;
@@ -1341,9 +1400,6 @@ mono_array_class_get (MonoType *element_type, guint32 rank)
        class->this_arg = class->byval_arg;
        class->this_arg.byref = 1;
 
-       if (rank == 1 && class->element_class->blittable)
-               class->blittable = TRUE;
-
        list = g_slist_append (list, class);
        g_hash_table_insert (image->array_cache, &class->element_class->byval_arg, list);
        return class;
@@ -1488,9 +1544,27 @@ mono_class_get_field_from_name (MonoClass *klass, const char *name)
 {
        int i;
 
-       for (i = 0; i < klass->field.count; ++i) {
-               if (strcmp (name, klass->fields [i].name) == 0)
-                       return &klass->fields [i];
+       while (klass) {
+               for (i = 0; i < klass->field.count; ++i) {
+                       if (strcmp (name, klass->fields [i].name) == 0)
+                               return &klass->fields [i];
+               }
+               klass = klass->parent;
+       }
+       return NULL;
+}
+
+MonoProperty*
+mono_class_get_property_from_name (MonoClass *klass, const char *name)
+{
+       int i;
+
+       while (klass) {
+               for (i = 0; i < klass->property.count; ++i) {
+                       if (strcmp (name, klass->properties [i].name) == 0)
+                               return &klass->properties [i];
+               }
+               klass = klass->parent;
        }
        return NULL;
 }