14a37c2eb6aa7cd47a8f1ffc0b72ec1aeaac514b
[mono.git] / mono / metadata / class.c
1 /*
2  * class.c: Class management for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  *
9  * Possible Optimizations:
10  *     in mono_class_create, do not allocate the class right away,
11  *     but wait until you know the size of the FieldMap, so that
12  *     the class embeds directly the FieldMap after the vtable.
13  *
14  * 
15  */
16 #include <config.h>
17 #include <glib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <mono/metadata/image.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/metadata.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/class.h>
28 #include <mono/metadata/object.h>
29 #include <mono/metadata/appdomain.h>
30 #include <mono/metadata/mono-endian.h>
31 #include <mono/metadata/debug-helpers.h>
32 #include <mono/os/gc_wrapper.h>
33
34 #define CSIZE(x) (sizeof (x) / 4)
35
36 MonoStats mono_stats;
37
38 gboolean mono_print_vtable = FALSE;
39
40 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
41
42 MonoClass *
43 mono_class_from_typeref (MonoImage *image, guint32 type_token)
44 {
45         guint32 cols [MONO_TYPEREF_SIZE];
46         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
47         guint32 idx;
48         const char *name, *nspace;
49         MonoClass *res;
50
51         mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
52
53         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
54         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
55         
56         idx = cols [MONO_TYPEREF_SCOPE] >> RESOLTION_SCOPE_BITS;
57         switch (cols [MONO_TYPEREF_SCOPE] & RESOLTION_SCOPE_MASK) {
58         case RESOLTION_SCOPE_MODULE:
59                 if (!idx)
60                         g_error ("null ResolutionScope not yet handled");
61                 /* a typedef in disguise */
62                 return mono_class_from_name (image, nspace, name);
63         case RESOLTION_SCOPE_MODULEREF:
64                 return mono_class_from_name (image->assembly->modules [idx - 1], nspace, name);
65         case RESOLTION_SCOPE_TYPEREF: {
66                 MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
67                 GList *tmp;
68                 mono_class_init (enclosing);
69                 for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) {
70                         res = tmp->data;
71                         if (strcmp (res->name, name) == 0)
72                                 return res;
73                 }
74                 g_warning ("TypeRef ResolutionScope not yet handled (%d)", idx);
75                 return NULL;
76         }
77         case RESOLTION_SCOPE_ASSEMBLYREF:
78                 break;
79         }
80
81         if (!image->references ||  !image->references [idx-1]) {
82                 /* 
83                  * detected a reference to mscorlib, we simply return a reference to a dummy 
84                  * until we have a better solution.
85                  */
86                 fprintf(stderr, "Sending dummy where %s.%s expected\n", mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]), mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME])); 
87                 
88                 res = mono_class_from_name (image, "System", "MonoDummy");
89                 /* prevent method loading */
90                 res->dummy = 1;
91                 /* some storage if the type is used  - very ugly hack */
92                 res->instance_size = 2*sizeof (gpointer);
93                 return res;
94         }       
95
96         /* load referenced assembly */
97         image = image->references [idx-1]->image;
98
99         return mono_class_from_name (image, nspace, name);
100 }
101
102 MonoMarshalType *
103 mono_marshal_load_type_info (MonoClass* klass)
104 {
105         int i, j, count = 0;
106         MonoMarshalType *info;
107         guint32 layout;
108
109         g_assert (klass != NULL);
110
111         if (klass->marshal_info)
112                 return klass->marshal_info;
113
114         if (!klass->inited)
115                 mono_class_init (klass);
116         
117         for (i = 0; i < klass->field.count; ++i) {
118                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
119                         continue;
120                 count++;
121         }
122
123         layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
124
125         klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
126         info->num_fields = count;
127         
128         if (klass->parent)
129                 info->native_size = mono_class_native_size (klass->parent, NULL);
130
131         for (j = i = 0; i < klass->field.count; ++i) {
132                 int size, align;
133                 
134                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
135                         continue;
136
137                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
138                         mono_metadata_field_info (klass->image, klass->field.first + i, 
139                                                   NULL, NULL, &info->fields [j].mspec);
140
141                 info->fields [j].field = &klass->fields [i];
142
143                 switch (layout) {
144                 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
145                 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
146                         size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
147                                                        &align, TRUE, klass->unicode);
148                         align = klass->packing_size ? MIN (klass->packing_size, align): align;  
149                         info->fields [j].offset = info->native_size;
150                         info->fields [j].offset += align - 1;
151                         info->fields [j].offset &= ~(align - 1);
152                         info->native_size = info->fields [j].offset + size;
153                         break;
154                 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
155                         /* FIXME: */
156                         info->fields [j].offset = klass->fields [i].offset - sizeof (MonoObject);
157                         info->native_size = klass->instance_size - sizeof (MonoObject);
158                         break;
159                 }       
160                 j++;
161         }
162
163         if (info->native_size & (klass->min_align - 1)) {
164                 info->native_size += klass->min_align - 1;
165                 info->native_size &= ~(klass->min_align - 1);
166         }
167
168         return klass->marshal_info;
169 }
170
171 /** 
172  * class_compute_field_layout:
173  * @m: pointer to the metadata.
174  * @class: The class to initialize
175  *
176  * Initializes the class->fields.
177  *
178  * Currently we only support AUTO_LAYOUT, and do not even try to do
179  * a good job at it.  This is temporary to get the code for Paolo.
180  */
181 static void
182 class_compute_field_layout (MonoClass *class)
183 {
184         MonoImage *m = class->image; 
185         const int top = class->field.count;
186         guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
187         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
188         int i, blittable = TRUE;
189         guint32 rva;
190         guint32 packing_size = 0;
191
192         if (class->size_inited)
193                 return;
194
195         if (class->parent) {
196                 if (!class->parent->size_inited)
197                         class_compute_field_layout (class->parent);
198                 class->instance_size += class->parent->instance_size;
199                 class->class_size += class->parent->class_size;
200                 class->min_align = class->parent->min_align;
201         } else {
202                 class->instance_size = sizeof (MonoObject);
203                 class->min_align = 1;
204         }
205
206         if (mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &class->instance_size)) {
207                 class->instance_size += sizeof (MonoObject);
208         }
209
210         g_assert ((packing_size & 0xfffffff0) == 0);
211         class->packing_size = packing_size;
212
213         if (!top) {
214                 class->size_inited = 1;
215                 return;
216         }
217
218         class->fields = g_new0 (MonoClassField, top);
219
220         /*
221          * Fetch all the field information.
222          */
223         for (i = 0; i < top; i++){
224                 const char *sig;
225                 guint32 cols [MONO_FIELD_SIZE];
226                 int idx = class->field.first + i;
227                 
228                 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
229                 /* The name is needed for fieldrefs */
230                 class->fields [i].name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]);
231                 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
232                 mono_metadata_decode_value (sig, &sig);
233                 /* FIELD signature == 0x06 */
234                 g_assert (*sig == 0x06);
235                 class->fields [i].type = mono_metadata_parse_field_type (
236                         m, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
237
238                 if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) {
239                         if (class->fields [i].type->byref) {
240                                 blittable = FALSE;
241                         } else {
242                                 MonoClass *field_class = mono_class_from_mono_type (class->fields [i].type);
243                                 if (!field_class->blittable)
244                                         blittable = FALSE;
245                         }
246                 }
247
248                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
249                         mono_metadata_field_info (m, idx, NULL, &rva, NULL);
250                         if (!rva)
251                                 g_warning ("field %s in %s should have RVA data, but hasn't", class->fields [i].name, class->name);
252                         class->fields [i].data = mono_cli_rva_map (class->image->image_info, rva);
253                 }
254
255                 if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC)) {
256                         class->enum_basetype = class->fields [i].type;
257                         class->element_class = mono_class_from_mono_type (class->enum_basetype);
258                         blittable = class->element_class->blittable;
259                 }
260         }
261
262         if (class == mono_defaults.string_class)
263                 blittable = FALSE;
264
265         class->blittable = blittable;
266
267         if (class->enumtype && !class->enum_basetype) {
268                 if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
269                         G_BREAKPOINT ();
270         }
271         /*
272          * Compute field layout and total size (not considering static fields)
273          */
274         switch (layout) {
275         case TYPE_ATTRIBUTE_AUTO_LAYOUT:
276         case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
277                 for (i = 0; i < top; i++){
278                         int size, align;
279                         
280                         if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
281                                 continue;
282
283                         size = mono_type_size (class->fields [i].type, &align);
284                         
285                         /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
286                         align = class->packing_size ? MIN (class->packing_size, align): align;
287                         class->min_align = MAX (align, class->min_align);
288                         class->fields [i].offset = class->instance_size;
289                         class->fields [i].offset += align - 1;
290                         class->fields [i].offset &= ~(align - 1);
291                         class->instance_size = class->fields [i].offset + size;
292
293                 }
294        
295                 if (class->instance_size & (class->min_align - 1)) {
296                         class->instance_size += class->min_align - 1;
297                         class->instance_size &= ~(class->min_align - 1);
298                 }
299                 break;
300         case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
301                 for (i = 0; i < top; i++) {
302                         int size, align;
303                         int idx = class->field.first + i;
304
305                         /*
306                          * There must be info about all the fields in a type if it
307                          * uses explicit layout.
308                          */
309
310                         if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
311                                 continue;
312
313                         size = mono_type_size (class->fields [i].type, &align);
314                         
315                         mono_metadata_field_info (m, idx, &class->fields [i].offset, NULL, NULL);
316                         if (class->fields [i].offset == (guint32)-1)
317                                 g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, class->fields [i].name);
318                         /*
319                          * The offset is from the start of the object: this works for both
320                          * classes and valuetypes.
321                          */
322                         class->fields [i].offset += sizeof (MonoObject);
323                         /*
324                          * Calc max size.
325                          */
326                         class->instance_size = MAX (class->instance_size, size + class->fields [i].offset);
327                 }
328                 break;
329         }
330
331         class->size_inited = 1;
332
333         /*
334          * Compute static field layout and size
335          */
336         switch (layout) {
337         case TYPE_ATTRIBUTE_AUTO_LAYOUT:
338         case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
339                 for (i = 0; i < top; i++){
340                         int size, align;
341                         
342                         if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
343                                 continue;
344                         
345                         size = mono_type_size (class->fields [i].type, &align);
346                         class->fields [i].offset = class->class_size;
347                         class->fields [i].offset += align - 1;
348                         class->fields [i].offset &= ~(align - 1);
349                         class->class_size = class->fields [i].offset + size;
350                 }
351                 break;
352         case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
353                 for (i = 0; i < top; i++){
354                         int size, align;
355
356                         /*
357                          * There must be info about all the fields in a type if it
358                          * uses explicit layout.
359                          */
360
361                         
362                         if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
363                                 continue;
364
365                         size = mono_type_size (class->fields [i].type, &align);
366                         class->fields [i].offset = class->class_size;
367                         class->fields [i].offset += align - 1;
368                         class->fields [i].offset &= ~(align - 1);
369                         class->class_size = class->fields [i].offset + size;
370                 }
371                 break;
372         }
373 }
374
375 static void
376 init_properties (MonoClass *class)
377 {
378         guint startm, endm, i, j;
379         guint32 cols [MONO_PROPERTY_SIZE];
380         MonoTableInfo *pt = &class->image->tables [MONO_TABLE_PROPERTY];
381         MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
382
383         class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &class->property.last);
384         class->property.count = class->property.last - class->property.first;
385
386         class->properties = g_new0 (MonoProperty, class->property.count);
387         for (i = class->property.first; i < class->property.last; ++i) {
388                 mono_metadata_decode_row (pt, i, cols, MONO_PROPERTY_SIZE);
389                 class->properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
390                 class->properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
391
392                 startm = mono_metadata_methods_from_property (class->image, i, &endm);
393                 for (j = startm; j < endm; ++j) {
394                         mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
395                         switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
396                         case METHOD_SEMANTIC_SETTER:
397                                 class->properties [i - class->property.first].set = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
398                                 break;
399                         case METHOD_SEMANTIC_GETTER:
400                                 class->properties [i - class->property.first].get = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
401                                 break;
402                         default:
403                                 break;
404                         }
405                 }
406         }
407 }
408
409 static void
410 init_events (MonoClass *class)
411 {
412         guint startm, endm, i, j;
413         guint32 cols [MONO_EVENT_SIZE];
414         MonoTableInfo *pt = &class->image->tables [MONO_TABLE_EVENT];
415         MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
416
417         class->event.first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &class->event.last);
418         class->event.count = class->event.last - class->event.first;
419
420         class->events = g_new0 (MonoEvent, class->event.count);
421         for (i = class->event.first; i < class->event.last; ++i) {
422                 mono_metadata_decode_row (pt, i, cols, MONO_EVENT_SIZE);
423                 class->events [i - class->event.first].attrs = cols [MONO_EVENT_FLAGS];
424                 class->events [i - class->event.first].name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
425
426                 startm = mono_metadata_methods_from_event (class->image, i, &endm);
427                 for (j = startm; j < endm; ++j) {
428                         mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
429                         switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
430                         case METHOD_SEMANTIC_ADD_ON:
431                                 class->events [i - class->event.first].add = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
432                                 break;
433                         case METHOD_SEMANTIC_REMOVE_ON:
434                                 class->events [i - class->event.first].remove = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
435                                 break;
436                         case METHOD_SEMANTIC_FIRE:
437                                 class->events [i - class->event.first].raise = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
438                                 break;
439                         case METHOD_SEMANTIC_OTHER: /* don't care for now */
440                         default:
441                                 break;
442                         }
443                 }
444         }
445 }
446
447 static guint
448 mono_get_unique_iid (MonoClass *class)
449 {
450         static GHashTable *iid_hash = NULL;
451         static guint iid = 0;
452
453         char *str;
454         gpointer value;
455         
456         g_assert (class->flags & TYPE_ATTRIBUTE_INTERFACE);
457
458         if (!iid_hash)
459                 iid_hash = g_hash_table_new (g_str_hash, g_str_equal);
460
461         str = g_strdup_printf ("%s|%s.%s\n", class->image->name, class->name_space, class->name);
462
463         if (g_hash_table_lookup_extended (iid_hash, str, NULL, &value)) {
464                 g_free (str);
465                 return (guint)value;
466         } else {
467                 g_hash_table_insert (iid_hash, str, (gpointer)iid);
468                 ++iid;
469         }
470
471         return iid - 1;
472 }
473
474 void
475 mono_class_setup_vtable (MonoClass *class)
476 {
477         MonoClass *k, *ic;
478         MonoMethod **vtable;
479         int i, onum = 0, max_vtsize = 0, max_iid, cur_slot = 0;
480         MonoMethod **overrides;
481
482         for (i = 0; i < class->interface_count; i++) 
483                 max_vtsize += class->interfaces [i]->method.count;
484         
485         if (class->parent) {
486                 max_vtsize += class->parent->vtable_size;
487                 cur_slot = class->parent->vtable_size;
488         }
489
490         max_vtsize += class->method.count;
491
492         vtable = alloca (sizeof (gpointer) * max_vtsize);
493         memset (vtable, 0, sizeof (gpointer) * max_vtsize);
494
495         /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
496
497         /* compute maximum number of slots and maximum interface id */
498         max_iid = 0;
499         for (k = class; k ; k = k->parent) {
500                 for (i = 0; i < k->interface_count; i++) {
501                         ic = k->interfaces [i];
502
503                         if (!ic->inited)
504                                 mono_class_init (ic);
505
506                         if (max_iid < ic->interface_id)
507                                 max_iid = ic->interface_id;
508                 }
509         }
510         
511         class->max_interface_id = max_iid;
512         /* compute vtable offset for interfaces */
513         class->interface_offsets = g_malloc (sizeof (gpointer) * (max_iid + 1));
514
515         for (i = 0; i <= max_iid; i++)
516                 class->interface_offsets [i] = -1;
517
518         for (i = 0; i < class->interface_count; i++) {
519                 ic = class->interfaces [i];
520                 class->interface_offsets [ic->interface_id] = cur_slot;
521                 cur_slot += ic->method.count;
522         }
523
524         for (k = class->parent; k ; k = k->parent) {
525                 for (i = 0; i < k->interface_count; i++) {
526                         ic = k->interfaces [i]; 
527                         if (class->interface_offsets [ic->interface_id] == -1) {
528                                 int io = k->interface_offsets [ic->interface_id];
529
530                                 g_assert (io >= 0);
531                                 g_assert (io <= max_vtsize);
532
533                                 class->interface_offsets [ic->interface_id] = io;
534                         }
535                 }
536         }
537
538         if (class->parent && class->parent->vtable_size)
539                 memcpy (vtable, class->parent->vtable,  sizeof (gpointer) * class->parent->vtable_size);
540
541         overrides = mono_class_get_overrides (class->image, class->type_token, &onum);
542
543         /* override interface methods */
544         for (i = 0; i < onum; i++) {
545                 MonoMethod *decl = overrides [i*2];
546                 if (decl->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
547                         int dslot;
548                         g_assert (decl->slot != -1);
549                         dslot = decl->slot + class->interface_offsets [decl->klass->interface_id];
550                         vtable [dslot] = overrides [i*2 + 1];
551                 }
552         }
553
554         for (k = class; k ; k = k->parent) {
555                 for (i = 0; i < k->interface_count; i++) {
556                         int j, l, io;
557
558                         ic = k->interfaces [i];
559                         io = k->interface_offsets [ic->interface_id];
560                         
561                         g_assert (io >= 0);
562                         g_assert (io <= max_vtsize);
563
564                         if (k == class) {
565                                 for (l = 0; l < ic->method.count; l++) {
566                                         MonoMethod *im = ic->methods [l];                                               
567                                         for (j = 0; j < class->method.count; ++j) {
568                                                 MonoMethod *cm = class->methods [j];
569                                                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
570                                                     !(cm->flags & METHOD_ATTRIBUTE_PUBLIC) ||
571                                                     !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
572                                                         continue;
573                                                 if (!strcmp(cm->name, im->name) && 
574                                                     mono_metadata_signature_equal (cm->signature, im->signature)) {
575                                                         g_assert (io + l <= max_vtsize);
576                                                         vtable [io + l] = cm;
577                                                 }
578                                         }
579                                 }
580                         } else {
581                                 /* already implemented */
582                                 if (io >= k->vtable_size)
583                                         continue;
584                         }
585                                 
586                         for (l = 0; l < ic->method.count; l++) {
587                                 MonoMethod *im = ic->methods [l];                                               
588                                 MonoClass *k1;
589
590                                 g_assert (io + l <= max_vtsize);
591
592                                 if (vtable [io + l])
593                                         continue;
594                                         
595                                 for (k1 = class; k1; k1 = k1->parent) {
596                                         for (j = 0; j < k1->method.count; ++j) {
597                                                 MonoMethod *cm = k1->methods [j];
598
599                                                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
600                                                     !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
601                                                         continue;
602                                                 
603                                                 if (!strcmp(cm->name, im->name) && 
604                                                     mono_metadata_signature_equal (cm->signature, im->signature)) {
605                                                         g_assert (io + l <= max_vtsize);
606                                                         vtable [io + l] = cm;
607                                                         break;
608                                                 }
609                                                 
610                                         }
611                                         g_assert (io + l <= max_vtsize);
612                                         if (vtable [io + l])
613                                                 break;
614                                 }
615                         }
616
617                         for (l = 0; l < ic->method.count; l++) {
618                                 MonoMethod *im = ic->methods [l];                                               
619                                 char *qname, *fqname;
620                                 
621                                 qname = g_strconcat (ic->name, ".", im->name, NULL); 
622                                 if (ic->name_space && ic->name_space [0])
623                                         fqname = g_strconcat (ic->name_space, ".", ic->name, ".", im->name, NULL);
624                                 else
625                                         fqname = NULL;
626
627                                 for (j = 0; j < class->method.count; ++j) {
628                                         MonoMethod *cm = class->methods [j];
629
630                                         if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
631                                                 continue;
632                                         
633                                         if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
634                                             mono_metadata_signature_equal (cm->signature, im->signature)) {
635                                                 g_assert (io + l <= max_vtsize);
636                                                 vtable [io + l] = cm;
637                                                 break;
638                                         }
639                                 }
640                                 g_free (qname);
641                                 g_free (fqname);
642                         }
643
644                         
645                         if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
646                                 for (l = 0; l < ic->method.count; l++) {
647                                         char *msig;
648                                         MonoMethod *im = ic->methods [l];                                               
649                                         g_assert (io + l <= max_vtsize);
650                                         if (!(vtable [io + l])) {
651                                                 for (j = 0; j < onum; ++j) {
652                                                         g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name, 
653                                                                  overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
654                                                 }
655                                                 msig = mono_signature_get_desc (im->signature, FALSE);
656                                                 printf ("no implementation for interface method %s.%s::%s(%s) in class %s.%s\n",
657                                                         ic->name_space, ic->name, im->name, msig, class->name_space, class->name);
658                                                 g_free (msig);
659                                                 for (j = 0; j < class->method.count; ++j) {
660                                                         MonoMethod *cm = class->methods [j];
661                                                         msig = mono_signature_get_desc (cm->signature, FALSE);
662                                                         
663                                                         printf ("METHOD %s(%s)\n", cm->name, msig);
664                                                         g_free (msig);
665                                                 }
666                                                 g_assert_not_reached ();
667                                         }
668                                 }
669                         }
670                 
671                         for (l = 0; l < ic->method.count; l++) {
672                                 MonoMethod *im = vtable [io + l];
673
674                                 if (im) {
675                                         g_assert (io + l <= max_vtsize);
676                                         if (im->slot < 0) {
677                                                 /* FIXME: why do we need this ? */
678                                                 im->slot = io + l;
679                                                 /* g_assert_not_reached (); */
680                                         }
681                                 }
682                         }
683                 }
684         } 
685
686         for (i = 0; i < class->method.count; ++i) {
687                 MonoMethod *cm;
688                
689                 cm = class->methods [i];
690
691                 
692 #if 0
693                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
694                     (cm->slot >= 0))
695                         continue;
696 #else  /* EXT_VTABLE_HACK */
697                 if (cm->slot >= 0)
698                         continue;
699 #endif
700
701                 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && (cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
702                         for (k = class->parent; k ; k = k->parent) {
703                                 int j;
704                                 for (j = 0; j < k->method.count; ++j) {
705                                         MonoMethod *m1 = k->methods [j];
706                                         if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL))
707                                                 continue;
708                                         if (!strcmp(cm->name, m1->name) && 
709                                             mono_metadata_signature_equal (cm->signature, m1->signature)) {
710                                                 cm->slot = k->methods [j]->slot;
711                                                 g_assert (cm->slot < max_vtsize);
712                                                 break;
713                                         }
714                                 }
715                                 if (cm->slot >= 0) 
716                                         break;
717                         }
718                 }
719
720                 if (cm->slot < 0)
721                         cm->slot = cur_slot++;
722
723                 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
724                         vtable [cm->slot] = cm;
725         }
726
727         /* override non interface methods */
728         for (i = 0; i < onum; i++) {
729                 MonoMethod *decl = overrides [i*2];
730                 if (!(decl->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
731                         g_assert (decl->slot != -1);
732                         vtable [decl->slot] = overrides [i*2 + 1];
733                 }
734         }
735        
736         g_free (overrides);
737
738         class->vtable_size = cur_slot;
739         class->vtable = g_malloc0 (sizeof (gpointer) * class->vtable_size);
740         memcpy (class->vtable, vtable,  sizeof (gpointer) * class->vtable_size);
741
742         if (mono_print_vtable) {
743                 int icount = 0;
744
745                 for (i = 0; i <= max_iid; i++)
746                         if (class->interface_offsets [i] != -1)
747                                 icount++;
748
749                 printf ("VTable %s.%s (size = %d, interfaces = %d)\n", class->name_space, 
750                         class->name, class->vtable_size, icount); 
751
752                 for (i = 0; i < class->vtable_size; ++i) {
753                         MonoMethod *cm;
754                
755                         cm = vtable [i];
756                         if (cm) {
757                                 printf ("  slot %03d(%03d) %s.%s:%s\n", i, cm->slot,
758                                         cm->klass->name_space, cm->klass->name,
759                                         cm->name);
760                         }
761                 }
762
763
764                 if (icount) {
765                         printf ("Interfaces %s.%s (max_iid = %d)\n", class->name_space, 
766                                 class->name, max_iid);
767         
768                         for (i = 0; i < class->interface_count; i++) {
769                                 ic = class->interfaces [i];
770                                 printf ("  slot %03d(%03d) %s.%s\n",  
771                                         class->interface_offsets [ic->interface_id],
772                                         ic->method.count, ic->name_space, ic->name);
773                         }
774
775                         for (k = class->parent; k ; k = k->parent) {
776                                 for (i = 0; i < k->interface_count; i++) {
777                                         ic = k->interfaces [i]; 
778                                         printf ("  slot %03d(%03d) %s.%s\n", 
779                                                 class->interface_offsets [ic->interface_id],
780                                                 ic->method.count, ic->name_space, ic->name);
781                                 }
782                         }
783                 }
784         }
785
786 }
787
788 /**
789  * mono_class_init:
790  * @class: the class to initialize
791  *
792  * compute the instance_size, class_size and other infos that cannot be 
793  * computed at mono_class_get() time. Also compute a generic vtable and 
794  * the method slot numbers. We use this infos later to create a domain
795  * specific vtable.  
796  */
797 void
798 mono_class_init (MonoClass *class)
799 {
800         int i;
801         static MonoMethod *default_ghc = NULL;
802         static MonoMethod *default_finalize = NULL;
803         static int finalize_slot = -1;
804         static int ghc_slot = -1;
805
806         g_assert (class);
807
808         if (class->inited)
809                 return;
810
811         if (class->init_pending) {
812                 /* this indicates a cyclic dependency */
813                 g_error ("pending init %s.%s\n", class->name_space, class->name);
814         }
815
816         class->init_pending = 1;
817
818         mono_stats.initialized_class_count++;
819
820         if (class->parent && !class->parent->inited)
821                 mono_class_init (class->parent);
822
823         /*
824          * Computes the size used by the fields, and their locations
825          */
826         if (!class->size_inited)
827                 class_compute_field_layout (class);
828
829         /* initialize method pointers */
830         class->methods = g_new (MonoMethod*, class->method.count);
831         for (i = 0; i < class->method.count; ++i)
832                 class->methods [i] = mono_get_method (class->image,
833                         MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class);
834
835         init_properties (class);
836         init_events (class);
837
838         i = mono_metadata_nesting_typedef (class->image, class->type_token);
839         while (i) {
840                 MonoClass* nclass;
841                 guint32 cols [MONO_NESTED_CLASS_SIZE];
842                 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
843                 if (cols [MONO_NESTED_CLASS_ENCLOSING] != mono_metadata_token_index (class->type_token))
844                         break;
845                 nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
846                 class->nested_classes = g_list_prepend (class->nested_classes, nclass);
847                 ++i;
848         }
849
850         if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
851                 for (i = 0; i < class->method.count; ++i)
852                         class->methods [i]->slot = i;
853                 class->init_pending = 0;
854                 class->inited = 1;
855                 return;
856         }
857
858         mono_class_setup_vtable (class);
859
860         class->inited = 1;
861         class->init_pending = 0;
862
863         if (!default_ghc) {
864                 if (class == mono_defaults.object_class) { 
865                        
866                         for (i = 0; i < class->vtable_size; ++i) {
867                                 MonoMethod *cm = class->vtable [i];
868                
869                                 if (!strcmp (cm->name, "GetHashCode")) {
870                                         ghc_slot = i;
871                                         break;
872                                 }
873                         }
874
875                         g_assert (ghc_slot > 0);
876
877                         default_ghc = class->vtable [ghc_slot];
878                 }
879         }
880         
881         class->ghcimpl = 1;
882         if (class != mono_defaults.object_class) { 
883
884                 if (class->vtable [ghc_slot] == default_ghc) {
885                         class->ghcimpl = 0;
886                 }
887         }
888
889         if (!default_finalize) {
890                 if (class == mono_defaults.object_class) { 
891                        
892                         for (i = 0; i < class->vtable_size; ++i) {
893                                 MonoMethod *cm = class->vtable [i];
894                
895                                 if (!strcmp (cm->name, "Finalize")) {
896                                         finalize_slot = i;
897                                         break;
898                                 }
899                         }
900
901                         g_assert (finalize_slot > 0);
902
903                         default_finalize = class->vtable [finalize_slot];
904                 }
905         }
906
907         /* Object::Finalize should have empty implemenatation */
908         class->has_finalize = 0;
909         if (class != mono_defaults.object_class) { 
910                 if (class->vtable [finalize_slot] != default_finalize)
911                         class->has_finalize = 1;
912         }
913 }
914
915
916 /*
917  * Compute a relative numbering of the class hierarchy as described in
918  * "Java for Large-Scale Scientific Computations?"
919  */
920 static void
921 mono_compute_relative_numbering (MonoClass *class, int *c)
922 {
923         GList *s;
924
925         (*c)++;
926
927         class->baseval = *c;
928
929         for (s = class->subclasses; s; s = s->next)
930                 mono_compute_relative_numbering ((MonoClass *)s->data, c); 
931         
932         class->diffval = *c -  class->baseval;
933 }
934
935 void
936 mono_class_setup_mono_type (MonoClass *class)
937 {
938         const char *name = class->name;
939         const char *nspace = class->name_space;
940
941         class->this_arg.byref = 1;
942         class->this_arg.data.klass = class;
943         class->this_arg.type = MONO_TYPE_CLASS;
944         class->byval_arg.data.klass = class;
945         class->byval_arg.type = MONO_TYPE_CLASS;
946
947         if (!strcmp (nspace, "System")) {
948                 if (!strcmp (name, "ValueType")) {
949                         /*
950                          * do not set the valuetype bit for System.ValueType.
951                          * class->valuetype = 1;
952                          */
953                 } else if (!strcmp (name, "Enum")) {
954                         /*
955                          * do not set the valuetype bit for System.Enum.
956                          * class->valuetype = 1;
957                          */
958                         class->valuetype = 0;
959                         class->enumtype = 0;
960                 } else if (!strcmp (name, "Object")) {
961                         class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
962                 } else if (!strcmp (name, "String")) {
963                         class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
964                 }
965         }
966         
967         if (class->valuetype) {
968                 int t = MONO_TYPE_VALUETYPE;
969                 if (!strcmp (nspace, "System")) {
970                         switch (*name) {
971                         case 'B':
972                                 if (!strcmp (name, "Boolean")) {
973                                         t = MONO_TYPE_BOOLEAN;
974                                 } else if (!strcmp(name, "Byte")) {
975                                         t = MONO_TYPE_U1;
976                                         class->blittable = TRUE;                                                
977                                 }
978                                 break;
979                         case 'C':
980                                 if (!strcmp (name, "Char")) {
981                                         t = MONO_TYPE_CHAR;
982                                 }
983                                 break;
984                         case 'D':
985                                 if (!strcmp (name, "Double")) {
986                                         t = MONO_TYPE_R8;
987                                         class->blittable = TRUE;                                                
988                                 }
989                                 break;
990                         case 'I':
991                                 if (!strcmp (name, "Int32")) {
992                                         t = MONO_TYPE_I4;
993                                         class->blittable = TRUE;
994                                 } else if (!strcmp(name, "Int16")) {
995                                         t = MONO_TYPE_I2;
996                                         class->blittable = TRUE;
997                                 } else if (!strcmp(name, "Int64")) {
998                                         t = MONO_TYPE_I8;
999                                         class->blittable = TRUE;
1000                                 } else if (!strcmp(name, "IntPtr")) {
1001                                         t = MONO_TYPE_I;
1002                                         class->blittable = TRUE;
1003                                 }
1004                                 break;
1005                         case 'S':
1006                                 if (!strcmp (name, "Single")) {
1007                                         t = MONO_TYPE_R4;
1008                                         class->blittable = TRUE;                                                
1009                                 } else if (!strcmp(name, "SByte")) {
1010                                         t = MONO_TYPE_I1;
1011                                         class->blittable = TRUE;
1012                                 }
1013                                 break;
1014                         case 'U':
1015                                 if (!strcmp (name, "UInt32")) {
1016                                         t = MONO_TYPE_U4;
1017                                         class->blittable = TRUE;
1018                                 } else if (!strcmp(name, "UInt16")) {
1019                                         t = MONO_TYPE_U2;
1020                                         class->blittable = TRUE;
1021                                 } else if (!strcmp(name, "UInt64")) {
1022                                         t = MONO_TYPE_U8;
1023                                         class->blittable = TRUE;
1024                                 } else if (!strcmp(name, "UIntPtr")) {
1025                                         t = MONO_TYPE_U;
1026                                         class->blittable = TRUE;
1027                                 }
1028                                 break;
1029                         case 'V':
1030                                 if (!strcmp (name, "Void")) {
1031                                         t = MONO_TYPE_VOID;
1032                                 }
1033                                 break;
1034                         default:
1035                                 break;
1036                         }
1037                 }
1038                 class->this_arg.type = class->byval_arg.type = t;
1039         }
1040 }
1041
1042 void
1043 mono_class_setup_parent (MonoClass *class, MonoClass *parent)
1044 {
1045         gboolean system_namespace;
1046
1047         system_namespace = !strcmp (class->name_space, "System");
1048
1049         /* if root of the hierarchy */
1050         if (system_namespace && !strcmp (class->name, "Object")) {
1051                 class->parent = NULL;
1052                 class->instance_size = sizeof (MonoObject);
1053                 return;
1054         }
1055         if (!strcmp (class->name, "<Module>")) {
1056                 class->parent = NULL;
1057                 class->instance_size = 0;
1058                 return;
1059         }
1060
1061         if (!(class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1062                 int rnum = 0;
1063                 class->parent = parent;
1064
1065                 if (!parent)
1066                         g_assert_not_reached (); /* FIXME */
1067
1068                 class->marshalbyref = parent->marshalbyref;
1069                 class->contextbound  = parent->contextbound;
1070                 class->delegate  = parent->delegate;
1071                 
1072                 if (system_namespace) {
1073                         if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
1074                                 class->marshalbyref = 1;
1075
1076                         if (*class->name == 'C' && !strcmp (class->name, "ContextBoundObject")) 
1077                                 class->contextbound  = 1;
1078
1079                         if (*class->name == 'D' && !strcmp (class->name, "Delegate")) 
1080                                 class->delegate  = 1;
1081                 }
1082
1083                 if (class->parent->enumtype || ((strcmp (class->parent->name, "ValueType") == 0) && 
1084                                                 (strcmp (class->parent->name_space, "System") == 0)))
1085                         class->valuetype = 1;
1086                 if (((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) {
1087                         class->valuetype = class->enumtype = 1;
1088                 }
1089                 /*class->enumtype = class->parent->enumtype; */
1090                 class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
1091                 mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
1092         } else {
1093                 class->parent = NULL;
1094         }
1095
1096 }
1097
1098 /**
1099  * @image: context where the image is created
1100  * @type_token:  typedef token
1101  */
1102 static MonoClass *
1103 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
1104 {
1105         MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
1106         MonoClass *class, *parent = NULL;
1107         guint32 cols [MONO_TYPEDEF_SIZE];
1108         guint32 cols_next [MONO_TYPEDEF_SIZE];
1109         guint tidx = mono_metadata_token_index (type_token);
1110         const char *name, *nspace;
1111         guint icount = 0; 
1112         MonoClass **interfaces;
1113
1114         if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) 
1115                 return class;
1116
1117         g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
1118         
1119         mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
1120         
1121         name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
1122         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
1123
1124         if (cols [MONO_TYPEDEF_EXTENDS])
1125                 parent = mono_class_get (image, mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]));
1126         interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &icount);
1127
1128         class = g_malloc0 (sizeof (MonoClass));
1129                            
1130         g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
1131
1132         class->interfaces = interfaces;
1133         class->interface_count = icount;
1134
1135         class->name = name;
1136         class->name_space = nspace;
1137
1138         class->image = image;
1139         class->type_token = type_token;
1140         class->flags = cols [MONO_TYPEDEF_FLAGS];
1141
1142         if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
1143                 class->unicode = 1;
1144         /* fixme: maybe we must set this on windows 
1145         if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
1146                 class->unicode = 1;
1147         */
1148
1149         class->element_class = class;
1150
1151         /*g_print ("Init class %s\n", name);*/
1152
1153         mono_class_setup_parent (class, parent);
1154
1155         mono_class_setup_mono_type (class);
1156
1157         /*
1158          * Compute the field and method lists
1159          */
1160         class->field.first  = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
1161         class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
1162
1163         if (tt->rows > tidx){           
1164                 mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next));
1165                 class->field.last  = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
1166                 class->method.last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
1167         } else {
1168                 class->field.last  = image->tables [MONO_TABLE_FIELD].rows;
1169                 class->method.last = image->tables [MONO_TABLE_METHOD].rows;
1170         }
1171
1172         if (cols [MONO_TYPEDEF_FIELD_LIST] && 
1173             cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
1174                 class->field.count = class->field.last - class->field.first;
1175         else
1176                 class->field.count = 0;
1177
1178         if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
1179                 class->method.count = class->method.last - class->method.first;
1180         else
1181                 class->method.count = 0;
1182
1183         /* reserve space to store vector pointer in arrays */
1184         if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
1185                 class->instance_size += 2 * sizeof (gpointer);
1186                 g_assert (class->field.count == 0);
1187         }
1188
1189         if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
1190                 class->interface_id = mono_get_unique_iid (class);
1191
1192         /*class->interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &class->interface_count); */
1193
1194         if (class->enumtype)
1195                 class_compute_field_layout (class);
1196
1197         if ((type_token = mono_metadata_nested_in_typedef (image, type_token)))
1198                 class->nested_in = mono_class_create_from_typedef (image, type_token);
1199
1200         return class;
1201 }
1202
1203 MonoClass *
1204 mono_ptr_class_get (MonoType *type)
1205 {
1206         MonoClass *result;
1207         MonoClass *el_class;
1208         static GHashTable *ptr_hash = NULL;
1209
1210         if (!ptr_hash)
1211                 ptr_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
1212         el_class = mono_class_from_mono_type (type);
1213         if ((result = g_hash_table_lookup (ptr_hash, el_class)))
1214                 return result;
1215         result = g_new0 (MonoClass, 1);
1216
1217         result->parent = NULL; /* no parent for PTR types */
1218         result->name = "System";
1219         result->name_space = "MonoPtrFakeClass";
1220         result->image = el_class->image;
1221         result->inited = TRUE;
1222         /* Can pointers get boxed? */
1223         result->instance_size = sizeof (gpointer);
1224         /*
1225          * baseval, diffval: need them to allow casting ?
1226          */
1227         result->element_class = el_class;
1228         result->enum_basetype = &result->element_class->byval_arg;
1229
1230         result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
1231         result->this_arg.data.type = result->byval_arg.data.type = result->enum_basetype;
1232         result->this_arg.byref = TRUE;
1233
1234         g_hash_table_insert (ptr_hash, el_class, result);
1235
1236         return result;
1237 }
1238
1239 MonoClass *
1240 mono_class_from_mono_type (MonoType *type)
1241 {
1242         switch (type->type) {
1243         case MONO_TYPE_OBJECT:
1244                 return mono_defaults.object_class;
1245         case MONO_TYPE_VOID:
1246                 return mono_defaults.void_class;
1247         case MONO_TYPE_BOOLEAN:
1248                 return mono_defaults.boolean_class;
1249         case MONO_TYPE_CHAR:
1250                 return mono_defaults.char_class;
1251         case MONO_TYPE_I1:
1252                 return mono_defaults.sbyte_class;
1253         case MONO_TYPE_U1:
1254                 return mono_defaults.byte_class;
1255         case MONO_TYPE_I2:
1256                 return mono_defaults.int16_class;
1257         case MONO_TYPE_U2:
1258                 return mono_defaults.uint16_class;
1259         case MONO_TYPE_I4:
1260                 return mono_defaults.int32_class;
1261         case MONO_TYPE_U4:
1262                 return mono_defaults.uint32_class;
1263         case MONO_TYPE_I:
1264                 return mono_defaults.int_class;
1265         case MONO_TYPE_U:
1266                 return mono_defaults.uint_class;
1267         case MONO_TYPE_I8:
1268                 return mono_defaults.int64_class;
1269         case MONO_TYPE_U8:
1270                 return mono_defaults.uint64_class;
1271         case MONO_TYPE_R4:
1272                 return mono_defaults.single_class;
1273         case MONO_TYPE_R8:
1274                 return mono_defaults.double_class;
1275         case MONO_TYPE_STRING:
1276                 return mono_defaults.string_class;
1277         case MONO_TYPE_ARRAY:
1278                 return mono_array_class_get (type->data.array->type, type->data.array->rank);
1279         case MONO_TYPE_PTR:
1280                 return mono_ptr_class_get (type->data.type);
1281         case MONO_TYPE_SZARRAY:
1282                 return mono_array_class_get (type->data.type, 1);
1283         case MONO_TYPE_CLASS:
1284         case MONO_TYPE_VALUETYPE:
1285                 return type->data.klass;
1286         default:
1287                 g_warning ("implement me %02x\n", type->type);
1288                 g_assert_not_reached ();
1289         }
1290         
1291         return NULL;
1292 }
1293
1294 /**
1295  * @image: context where the image is created
1296  * @type_spec:  typespec token
1297  */
1298 static MonoClass *
1299 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec)
1300 {
1301         MonoType *type;
1302         MonoClass *class;
1303
1304         type = mono_type_create_from_typespec (image, type_spec);
1305
1306         switch (type->type) {
1307         case MONO_TYPE_ARRAY:
1308                 class = mono_array_class_get (type->data.array->type, type->data.array->rank);
1309                 break;
1310         case MONO_TYPE_SZARRAY:
1311                 class = mono_array_class_get (type->data.type, 1);
1312                 break;
1313         case MONO_TYPE_PTR:
1314                 class = mono_class_from_mono_type (type->data.type);
1315                 break;
1316         default:
1317                 /* it seems any type can be stored in TypeSpec as well */
1318                 class = mono_class_from_mono_type (type);
1319                 break;
1320         }
1321
1322         mono_metadata_free_type (type);
1323         
1324         return class;
1325 }
1326
1327 /**
1328  * mono_array_class_get:
1329  * @element_type: element type 
1330  * @rank: the dimension of the array class
1331  *
1332  * Returns: a class object describing the array with element type @element_type and 
1333  * dimension @rank. 
1334  */
1335 MonoClass *
1336 mono_array_class_get (MonoType *element_type, guint32 rank)
1337 {
1338         MonoClass *eclass;
1339         MonoImage *image;
1340         MonoClass *class;
1341         MonoClass *parent = NULL;
1342         GSList *list;
1343         int rnum = 0, nsize;
1344
1345         eclass = mono_class_from_mono_type (element_type);
1346         g_assert (rank <= 255);
1347
1348         parent = mono_defaults.array_class;
1349
1350         if (!parent->inited)
1351                 mono_class_init (parent);
1352
1353         image = eclass->image;
1354
1355         if ((list = g_hash_table_lookup (image->array_cache, element_type))) {
1356                 for (; list; list = list->next) {
1357                         class = list->data;
1358                         if (class->rank == rank)
1359                                 return class;
1360                 }
1361         }
1362         
1363         class = g_malloc0 (sizeof (MonoClass) + parent->vtable_size * sizeof (gpointer));
1364
1365         class->image = image;
1366         class->name_space = eclass->name_space;
1367         nsize = strlen (eclass->name);
1368         class->name = g_malloc (nsize + 2 + rank);
1369         memcpy (class->name, eclass->name, nsize);
1370         class->name [nsize] = '[';
1371         if (rank > 1)
1372                 memset (class->name + nsize + 1, ',', rank - 1);
1373         class->name [nsize + rank] = ']';
1374         class->name [nsize + rank + 1] = 0;
1375         class->type_token = 0;
1376         class->flags = TYPE_ATTRIBUTE_CLASS;
1377         class->parent = parent;
1378         class->instance_size = mono_class_instance_size (class->parent);
1379         class->class_size = 0;
1380         class->vtable_size = parent->vtable_size;
1381         class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
1382         mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
1383
1384         class->rank = rank;
1385         class->element_class = eclass;
1386         if (rank > 1) {
1387                 MonoArrayType *at = g_new0 (MonoArrayType, 1);
1388                 class->byval_arg.type = MONO_TYPE_ARRAY;
1389                 class->byval_arg.data.array = at;
1390                 at->type = &eclass->byval_arg;
1391                 at->rank = rank;
1392                 /* FIXME: complete.... */
1393         } else {
1394                 /* FIXME: this is not correct. the lbound could be >0 */
1395                 class->byval_arg.type = MONO_TYPE_SZARRAY;
1396                 class->byval_arg.data.type = &eclass->byval_arg;
1397         }
1398         class->this_arg = class->byval_arg;
1399         class->this_arg.byref = 1;
1400
1401         list = g_slist_append (list, class);
1402         g_hash_table_insert (image->array_cache, &class->element_class->byval_arg, list);
1403         return class;
1404 }
1405
1406 /**
1407  * mono_class_instance_size:
1408  * @klass: a class 
1409  * 
1410  * Returns: the size of an object instance
1411  */
1412 gint32
1413 mono_class_instance_size (MonoClass *klass)
1414 {
1415         
1416         if (!klass->size_inited)
1417                 mono_class_init (klass);
1418
1419         return klass->instance_size;
1420 }
1421
1422 /**
1423  * mono_class_native_size:
1424  * @klass: a class 
1425  * 
1426  * Returns: the native size of an object instance (when marshaled 
1427  * to unmanaged code) 
1428  */
1429 gint32
1430 mono_class_native_size (MonoClass *klass, guint32 *align)
1431 {
1432         
1433         if (!klass->marshal_info)
1434                 mono_marshal_load_type_info (klass);
1435
1436         if (align)
1437                 *align = klass->min_align;
1438
1439         return klass->marshal_info->native_size;
1440 }
1441
1442 /**
1443  * mono_class_min_align:
1444  * @klass: a class 
1445  * 
1446  * Returns: minimm alignment requirements 
1447  */
1448 gint32
1449 mono_class_min_align (MonoClass *klass)
1450 {
1451         
1452         if (!klass->size_inited)
1453                 mono_class_init (klass);
1454
1455         return klass->min_align;
1456 }
1457
1458 /**
1459  * mono_class_value_size:
1460  * @klass: a class 
1461  *
1462  * This function is used for value types, and return the
1463  * space and the alignment to store that kind of value object.
1464  *
1465  * Returns: the size of a value of kind @klass
1466  */
1467 gint32
1468 mono_class_value_size      (MonoClass *klass, guint32 *align)
1469 {
1470         gint32 size;
1471
1472         /* fixme: check disable, because we still have external revereces to
1473          * mscorlib and Dummy Objects 
1474          */
1475         /*g_assert (klass->valuetype);*/
1476
1477         size = mono_class_instance_size (klass) - sizeof (MonoObject);
1478
1479         if (align)
1480                 *align = klass->min_align;
1481
1482         return size;
1483 }
1484
1485 /**
1486  * mono_class_data_size:
1487  * @klass: a class 
1488  * 
1489  * Returns: the size of the static class data
1490  */
1491 gint32
1492 mono_class_data_size (MonoClass *klass)
1493 {
1494         
1495         if (!klass->inited)
1496                 mono_class_init (klass);
1497
1498         return klass->class_size;
1499 }
1500
1501 /*
1502  * Auxiliary routine to mono_class_get_field
1503  *
1504  * Takes a field index instead of a field token.
1505  */
1506 static MonoClassField *
1507 mono_class_get_field_idx (MonoClass *class, int idx)
1508 {
1509         if (class->field.count){
1510                 if ((idx >= class->field.first) && (idx < class->field.last)){
1511                         return &class->fields [idx - class->field.first];
1512                 }
1513         }
1514
1515         if (!class->parent)
1516                 return NULL;
1517         
1518         return mono_class_get_field_idx (class->parent, idx);
1519 }
1520
1521 /**
1522  * mono_class_get_field:
1523  * @class: the class to lookup the field.
1524  * @field_token: the field token
1525  *
1526  * Returns: A MonoClassField representing the type and offset of
1527  * the field, or a NULL value if the field does not belong to this
1528  * class.
1529  */
1530 MonoClassField *
1531 mono_class_get_field (MonoClass *class, guint32 field_token)
1532 {
1533         int idx = mono_metadata_token_index (field_token);
1534
1535         g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
1536
1537         return mono_class_get_field_idx (class, idx - 1);
1538 }
1539
1540 MonoClassField *
1541 mono_class_get_field_from_name (MonoClass *klass, const char *name)
1542 {
1543         int i;
1544
1545         while (klass) {
1546                 for (i = 0; i < klass->field.count; ++i) {
1547                         if (strcmp (name, klass->fields [i].name) == 0)
1548                                 return &klass->fields [i];
1549                 }
1550                 klass = klass->parent;
1551         }
1552         return NULL;
1553 }
1554
1555 MonoProperty*
1556 mono_class_get_property_from_name (MonoClass *klass, const char *name)
1557 {
1558         int i;
1559
1560         while (klass) {
1561                 for (i = 0; i < klass->property.count; ++i) {
1562                         if (strcmp (name, klass->properties [i].name) == 0)
1563                                 return &klass->properties [i];
1564                 }
1565                 klass = klass->parent;
1566         }
1567         return NULL;
1568 }
1569
1570 /**
1571  * mono_class_get:
1572  * @image: the image where the class resides
1573  * @type_token: the token for the class
1574  * @at: an optional pointer to return the array element type
1575  *
1576  * Returns: the MonoClass that represents @type_token in @image
1577  */
1578 MonoClass *
1579 mono_class_get (MonoImage *image, guint32 type_token)
1580 {
1581         MonoClass *class;
1582
1583         switch (type_token & 0xff000000){
1584         case MONO_TOKEN_TYPE_DEF:
1585                 class = mono_class_create_from_typedef (image, type_token);
1586                 break;          
1587         case MONO_TOKEN_TYPE_REF:
1588                 class = mono_class_from_typeref (image, type_token);
1589                 break;
1590         case MONO_TOKEN_TYPE_SPEC:
1591                 class = mono_class_create_from_typespec (image, type_token);
1592                 break;
1593         default:
1594                 g_warning ("unknown token type %x", type_token & 0xff000000);
1595                 g_assert_not_reached ();
1596         }
1597
1598         if (!class)
1599                 g_warning ("Could not load class from token 0x%08x in %s", type_token, image->name);
1600
1601         return class;
1602 }
1603
1604 MonoClass *
1605 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
1606 {
1607         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
1608         guint32 cols [MONO_TYPEDEF_SIZE];
1609         const char *n;
1610         const char *nspace;
1611         guint32 i, visib;
1612
1613         /* add a cache if needed */
1614         for (i = 1; i <= t->rows; ++i) {
1615                 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
1616                 /* nested types are accessed from the nesting name */
1617                 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1618                 if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY)
1619                         continue;
1620                 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
1621                 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
1622                 if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0)
1623                         return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
1624         }
1625         return NULL;
1626 }
1627
1628 MonoClass *
1629 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
1630 {
1631         GHashTable *nspace_table;
1632         guint32 token;
1633
1634         nspace_table = g_hash_table_lookup (image->name_cache, name_space);
1635         if (!nspace_table)
1636                 return 0;
1637         token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
1638         
1639         if (!token) {
1640                 /*g_warning ("token not found for %s.%s in image %s", name_space, name, image->name);*/
1641                 return NULL;
1642         }
1643
1644         token = MONO_TOKEN_TYPE_DEF | token;
1645
1646         return mono_class_get (image, token);
1647 }
1648
1649 /**
1650  * mono_array_element_size:
1651  * @ac: pointer to a #MonoArrayClass
1652  *
1653  * Returns: the size of single array element.
1654  */
1655 gint32
1656 mono_array_element_size (MonoClass *ac)
1657 {
1658         if (ac->element_class->valuetype)
1659                 return mono_class_instance_size (ac->element_class) - sizeof (MonoObject);
1660         else
1661                 return sizeof (gpointer);
1662 }
1663
1664 gpointer
1665 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class)
1666 {
1667         switch (token & 0xff000000) {
1668         case MONO_TOKEN_TYPE_DEF:
1669         case MONO_TOKEN_TYPE_REF: {
1670                 MonoClass *class;
1671                 if (handle_class)
1672                         *handle_class = mono_defaults.typehandle_class;
1673                 class = mono_class_get (image, token);
1674                 mono_class_init (class);
1675                 /* We return a MonoType* as handle */
1676                 return &class->byval_arg;
1677         }
1678         case MONO_TOKEN_TYPE_SPEC: {
1679                 MonoClass *class;
1680                 if (handle_class)
1681                         *handle_class = mono_defaults.typehandle_class;
1682                 class = mono_class_create_from_typespec (image, token);
1683                 mono_class_init (class);
1684                 return &class->byval_arg;
1685         }
1686         case MONO_TOKEN_FIELD_DEF: {
1687                 MonoClass *class;
1688                 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
1689                 class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
1690                 mono_class_init (class);
1691                 if (handle_class)
1692                                 *handle_class = mono_class_from_name (mono_defaults.corlib, "System", "RuntimeFieldHandle");
1693                 return mono_class_get_field (class, token);
1694         }
1695         case MONO_TOKEN_METHOD_DEF:
1696         case MONO_TOKEN_MEMBER_REF:
1697         default:
1698                 g_warning ("Unknown token 0x%08x in ldtoken", token);
1699                 break;
1700         }
1701         return NULL;
1702 }
1703