Update web page directory
[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
30 #define CSIZE(x) (sizeof (x) / 4)
31
32 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
33
34 static gpointer
35 default_trampoline (MonoMethod *method)
36 {
37         return method;
38 }
39
40 static void
41 default_runtime_class_init (MonoClass *klass)
42 {
43         return;
44 }
45
46 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
47 static MonoRuntimeClassInit mono_runtime_class_init = default_runtime_class_init;
48
49 void
50 mono_install_trampoline (MonoTrampoline func) 
51 {
52         arch_create_jit_trampoline = func? func: default_trampoline;
53 }
54
55 void
56 mono_install_runtime_class_init (MonoRuntimeClassInit func)
57 {
58         mono_runtime_class_init = func? func: default_runtime_class_init;
59 }
60
61 static MonoClass *
62 mono_class_create_from_typeref (MonoImage *image, guint32 type_token)
63 {
64         guint32 cols [MONO_TYPEREF_SIZE];
65         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
66         guint32 idx;
67         const char *name, *nspace;
68         MonoClass *res;
69
70         mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
71         g_assert ((cols [MONO_TYPEREF_SCOPE] & 0x3) == 2);
72         idx = cols [MONO_TYPEREF_SCOPE] >> 2;
73
74         if (!image->references ||  !image->references [idx-1]) {
75                 /* 
76                  * detected a reference to mscorlib, we simply return a reference to a dummy 
77                  * until we have a better solution.
78                  */
79                 /* 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]));  */
80                 
81                 res = mono_class_from_name (image, "System", "MonoDummy");
82                 /* prevent method loading */
83                 res->dummy = 1;
84                 /* some storage if the type is used  - very ugly hack */
85                 res->instance_size = 2*sizeof (gpointer);
86                 return res;
87         }       
88
89         name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
90         nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
91         
92         /* load referenced assembly */
93         image = image->references [idx-1]->image;
94
95         return mono_class_from_name (image, nspace, name);
96 }
97
98 /** 
99  * class_compute_field_layout:
100  * @m: pointer to the metadata.
101  * @class: The class to initialize
102  *
103  * Initializes the class->fields.
104  *
105  * Currently we only support AUTO_LAYOUT, and do not even try to do
106  * a good job at it.  This is temporary to get the code for Paolo.
107  */
108 static void
109 class_compute_field_layout (MonoClass *class)
110 {
111         MonoImage *m = class->image; 
112         const int top = class->field.count;
113         guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
114         MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
115         int i;
116
117         /*
118          * Fetch all the field information.
119          */
120         for (i = 0; i < top; i++){
121                 const char *sig;
122                 guint32 cols [MONO_FIELD_SIZE];
123                 int idx = class->field.first + i;
124                 
125                 mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
126                 /* The name is needed for fieldrefs */
127                 class->fields [i].name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]);
128                 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
129                 mono_metadata_decode_value (sig, &sig);
130                 /* FIELD signature == 0x06 */
131                 g_assert (*sig == 0x06);
132                 class->fields [i].type = mono_metadata_parse_field_type (
133                         m, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
134                 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
135                         mono_metadata_field_info (m, idx, NULL, &class->fields [i].data, NULL);
136                         if (!class->fields [i].data)
137                                 g_warning ("field %s in %s should have RVA data, but hasn't", class->fields [i].name, class->name);
138                 }
139                 if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC)) {
140                         class->enum_basetype = class->fields [i].type;
141                         class->element_class = mono_class_from_mono_type (class->enum_basetype);
142                 }
143         }
144         if (class->enumtype && !class->enum_basetype) {
145                 if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
146                         G_BREAKPOINT ();
147         }
148         /*
149          * Compute field layout and total size.
150          */
151         switch (layout){
152         case TYPE_ATTRIBUTE_AUTO_LAYOUT:
153         case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
154                 for (i = 0; i < top; i++){
155                         int size, align;
156                         
157                         size = mono_type_size (class->fields [i].type, &align);
158                         if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) {
159                                 class->fields [i].offset = class->class_size;
160                                 class->class_size += (class->class_size % align);
161                                 class->class_size += size;
162                         } else {
163                                 class->min_align = MAX (align, class->min_align);
164                                 class->fields [i].offset = class->instance_size;
165                                 class->instance_size += (class->instance_size % align);
166                                 class->instance_size += size;
167                         }
168                 }
169                 if (class->instance_size & (class->min_align - 1)) {
170                         class->instance_size += class->min_align - 1;
171                         class->instance_size &= ~(class->min_align - 1);
172                 }
173                 break;
174         case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
175                 for (i = 0; i < top; i++){
176                         int size, align;
177                         int idx = class->field.first + i;
178
179                         /*
180                          * There must be info about all the fields in a type if it
181                          * uses explicit layout.
182                          */
183
184                         size = mono_type_size (class->fields [i].type, &align);
185                         if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) {
186                                 class->fields [i].offset = class->class_size;
187                                 class->class_size += (class->class_size % align);
188                                 class->class_size += size;
189                         } else {
190                                 mono_metadata_field_info (m, idx, &class->fields [i].offset, NULL, NULL);
191                                 if (class->fields [i].offset == (guint32)-1)
192                                                 g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, class->fields [i].name);
193                                 /*
194                                  * The offset is from the start of the object: this works for both
195                                  * classes and valuetypes.
196                                  */
197                                 class->fields [i].offset += sizeof (MonoObject);
198                                 /*
199                                  * Calc max size.
200                                  */
201                                 size += class->fields [i].offset;
202                                 class->instance_size = MAX (class->instance_size, size);
203                         }
204                 }
205                 break;
206         }
207 }
208
209 static void
210 init_properties (MonoClass *class)
211 {
212         guint startm, endm, i, j;
213         guint32 cols [MONO_PROPERTY_SIZE];
214         MonoTableInfo *pt = &class->image->tables [MONO_TABLE_PROPERTY];
215         MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
216
217         class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &class->property.last);
218         class->property.count = class->property.last - class->property.first;
219
220         class->properties = g_new0 (MonoProperty, class->property.count);
221         for (i = class->property.first; i < class->property.last; ++i) {
222                 mono_metadata_decode_row (pt, i, cols, MONO_PROPERTY_SIZE);
223                 class->properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
224                 class->properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
225
226                 startm = mono_metadata_methods_from_property (class->image, i, &endm);
227                 for (j = startm; j < endm; ++j) {
228                         mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
229                         switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
230                         case 1: /* set */
231                                 class->properties [i - class->property.first].set = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
232                                 break;
233                         case 2: /* get */
234                                 class->properties [i - class->property.first].get = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
235                                 break;
236                         default:
237                                 break;
238                         }
239                 }
240         }
241 }
242
243 void
244 mono_class_init (MonoClass *class)
245 {
246         MonoClass *k, *ic;
247         MonoMethod **tmp_vtable, **vtable = (MonoMethod **)class->vtable;
248         int i, max_iid, cur_slot = 0;
249
250         g_assert (class);
251
252         if (class->inited)
253                 return;
254         class->inited = 1;
255
256         if (class->parent) {
257                 if (!class->parent->inited)
258                         mono_class_init (class->parent);
259                 class->instance_size += class->parent->instance_size;
260                 class->class_size += class->parent->class_size;
261                 class->min_align = class->parent->min_align;
262                 cur_slot = class->parent->vtable_size;
263         } else
264                 class->min_align = 1;
265
266         /*
267          * Computes the size used by the fields, and their locations
268          */
269         if (class->field.count > 0){
270                 class->fields = g_new0 (MonoClassField, class->field.count);
271                 class_compute_field_layout (class);
272         }
273
274         if (class->class_size)
275                 class->data = g_malloc0 (class->class_size);
276
277         /* initialize method pointers */
278         class->methods = g_new (MonoMethod*, class->method.count);
279         for (i = 0; i < class->method.count; ++i)
280                 class->methods [i] = mono_get_method (class->image,
281                         MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class);
282
283         if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
284                 for (i = 0; i < class->method.count; ++i)
285                         class->methods [i]->slot = i;
286                 return;
287         }
288
289         //printf ("METAINIT %s.%s\n", class->name_space, class->name);
290
291         /* compute maximum number of slots and maximum interface id */
292         max_iid = 0;
293         for (k = class; k ; k = k->parent) {
294                 for (i = 0; i < k->interface_count; i++) {
295                         ic = k->interfaces [i];
296
297                         if (!ic->inited)
298                                 mono_class_init (ic);
299
300                         if (max_iid < ic->interface_id)
301                                 max_iid = ic->interface_id;
302                 }
303         }
304         
305         class->max_interface_id = max_iid;
306         /* compute vtable offset for interfaces */
307         class->interface_offsets = g_malloc (sizeof (gpointer) * (max_iid + 1));
308
309         for (i = 0; i <= max_iid; i++)
310                 class->interface_offsets [i] = NULL;
311
312         for (i = 0; i < class->interface_count; i++) {
313                 ic = class->interfaces [i];
314                 class->interface_offsets [ic->interface_id] = &class->vtable [cur_slot];
315                 cur_slot += ic->method.count;
316         }
317
318         for (k = class->parent; k ; k = k->parent) {
319                 for (i = 0; i < k->interface_count; i++) {
320                         ic = k->interfaces [i]; 
321                         if (class->interface_offsets [ic->interface_id] == NULL) {
322                                 int io = (k->interface_offsets [ic->interface_id] - (gpointer)k->vtable)>>2;
323
324                                 g_assert (io >= 0);
325                                 g_assert (io <= class->vtable_size);
326
327                                 class->interface_offsets [ic->interface_id] = &class->vtable [io];
328                         }
329                 }
330         }
331
332         if (class->parent && class->parent->vtable_size)
333                 memcpy (class->vtable, class->parent->vtable,  sizeof (gpointer) * class->parent->vtable_size);
334  
335         tmp_vtable = alloca (class->vtable_size * sizeof (gpointer));
336         memset (tmp_vtable, 0, class->vtable_size * sizeof (gpointer));
337
338         for (k = class; k ; k = k->parent) {
339                 for (i = 0; i < k->interface_count; i++) {
340                         int j, l, io;
341                         ic = k->interfaces [i];
342
343                         io = (k->interface_offsets [ic->interface_id] - (gpointer)k->vtable)>>2;
344                         
345                         g_assert (io >= 0);
346                         g_assert (io <= class->vtable_size);
347
348                         if (k == class) {
349                                 for (l = 0; l < ic->method.count; l++) {
350                                         MonoMethod *im = ic->methods [l];                                               
351                                         for (j = 0; j < class->method.count; ++j) {
352                                                 MonoMethod *cm = class->methods [j];
353                                                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
354                                                     !(cm->flags & METHOD_ATTRIBUTE_PUBLIC) ||
355                                                     !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
356                                                         continue;
357                                                 if (!strcmp(cm->name, im->name) && 
358                                                     mono_metadata_signature_equal (cm->signature, im->signature)) {
359                                                         g_assert (io + l <= class->vtable_size);
360                                                         tmp_vtable [io + l] = cm;
361                                                 }
362                                         }
363                                 }
364                         } else {
365                                 /* already implemented */
366                                 if (io >= k->vtable_size)
367                                         continue;
368                         }
369                                 
370                         for (l = 0; l < ic->method.count; l++) {
371                                 MonoMethod *im = ic->methods [l];                                               
372                                 MonoClass *k1;
373
374                                 g_assert (io + l <= class->vtable_size);
375
376                                 if (tmp_vtable [io + l] || vtable [io + l])
377                                         continue;
378                                         
379                                 for (k1 = class; k1; k1 = k1->parent) {
380                                         for (j = 0; j < k1->method.count; ++j) {
381                                                 MonoMethod *cm = k1->methods [j];
382
383                                                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
384                                                     !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
385                                                         continue;
386                                                 
387                                                 if (!strcmp(cm->name, im->name) && 
388                                                     mono_metadata_signature_equal (cm->signature, im->signature)) {
389                                                         g_assert (io + l <= class->vtable_size);
390                                                         tmp_vtable [io + l] = cm;
391                                                         break;
392                                                 }
393                                                 
394                                         }
395                                         g_assert (io + l <= class->vtable_size);
396                                         if (tmp_vtable [io + l])
397                                                 break;
398                                 }
399                         }
400
401                         for (l = 0; l < ic->method.count; l++) {
402                                 MonoMethod *im = ic->methods [l];                                               
403                                 char *qname;
404                                 if (ic->name_space && ic->name_space [0])
405                                         qname = g_strconcat (ic->name_space, ".", ic->name, ".", im->name, NULL);
406                                 else
407                                         qname = g_strconcat (ic->name, ".", im->name, NULL); 
408
409                                 for (j = 0; j < class->method.count; ++j) {
410                                         MonoMethod *cm = class->methods [j];
411
412                                         if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
413                                                 continue;
414                                         
415                                         if (!strcmp (cm->name, qname) &&
416                                             mono_metadata_signature_equal (cm->signature, im->signature)) {
417                                                 g_assert (io + l <= class->vtable_size);
418                                                 tmp_vtable [io + l] = cm;
419                                                 break;
420                                         }
421                                 }
422                                 g_free (qname);
423                         }
424
425                         
426                         if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
427                                 for (l = 0; l < ic->method.count; l++) {
428                                         MonoMethod *im = ic->methods [l];                                               
429                                         g_assert (io + l <= class->vtable_size);
430                                         if (!(tmp_vtable [io + l] || vtable [io + l])) {
431                                                 printf ("no implementation for interface method %s.%s::%s in class %s.%s\n",
432                                                         ic->name_space, ic->name, im->name, class->name_space, class->name);
433                                                 
434                                                 for (j = 0; j < class->method.count; ++j) {
435                                                         MonoMethod *cm = class->methods [j];
436                                                         
437                                                         printf ("METHOD %s\n", cm->name);
438                                                 }
439                                                 g_assert_not_reached ();
440                                         }
441                                 }
442                         }
443                 
444                         for (l = 0; l < ic->method.count; l++) {
445                                 MonoMethod *im = tmp_vtable [io + l];
446
447                                 if (im) {
448                                         g_assert (io + l <= class->vtable_size);
449                                         if (im->slot < 0)
450                                                 im->slot = io + l;
451                                         if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
452                                                 //printf ("  ASLOT%d %s.%s:%s %s.%s:%s\n", io + l, ic->name_space, ic->name, 
453                                                 // im->name, im->klass->name_space,  im->klass->name, im->name);
454                                                 vtable [io + l] = arch_create_jit_trampoline (im);
455                                         }
456                                 }
457                         }
458                 }
459         } 
460
461         for (i = 0; i < class->method.count; ++i) {
462                 MonoMethod *cm;
463                
464                 cm = class->methods [i];
465
466                 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
467                     (cm->slot >= 0))
468                         continue;
469                 
470                 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
471                         for (k = class->parent; k ; k = k->parent) {
472                                 int j;
473                                 for (j = 0; j < k->method.count; ++j) {
474                                         MonoMethod *m1 = k->methods [j];
475                                         if (!(m1->flags & METHOD_ATTRIBUTE_VIRTUAL))
476                                                 continue;
477                                         if (!strcmp(cm->name, m1->name) && 
478                                             mono_metadata_signature_equal (cm->signature, m1->signature)) {
479                                                 cm->slot = k->methods [j]->slot;
480                                                 g_assert (cm->slot < class->vtable_size);
481                                                 break;
482                                         }
483                                 }
484                                 if (cm->slot >= 0) 
485                                         break;
486                         }
487                 }
488
489                 if (cm->slot < 0)
490                         cm->slot = cur_slot++;
491
492                 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
493                         vtable [cm->slot] = arch_create_jit_trampoline (cm);
494         }
495
496         init_properties (class);
497
498         i = mono_metadata_nesting_typedef (class->image, class->type_token);
499         while (i) {
500                 MonoClass* nclass;
501                 guint32 cols [MONO_NESTED_CLASS_SIZE];
502                 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
503                 if (cols [MONO_NESTED_CLASS_ENCLOSING] != mono_metadata_token_index (class->type_token))
504                         break;
505                 nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
506                 class->nested_classes = g_list_prepend (class->nested_classes, nclass);
507                 ++i;
508         }
509
510         mono_runtime_class_init (class);
511
512         /*
513         printf ("VTABLE %s.%s\n", class->name_space, class->name); 
514
515         for (i = 0; i < class->vtable_size; ++i) {
516                 MonoMethod *cm;
517                
518                 cm = vtable [i];
519                 if (cm) {
520                         printf ("  METH%d %p %s %d\n", i, cm, cm->name, cm->slot);
521                 }
522         }
523         
524         printf ("METAEND %s.%s\n", class->name_space, class->name); 
525         */
526 }
527
528 /*
529  * Compute a relative numbering of the class hierarchy as described in
530  * "Java for Large-Scale Scientific Computations?"
531  */
532 static void
533 mono_compute_relative_numbering (MonoClass *class, int *c)
534 {
535         GList *s;
536
537         (*c)++;
538
539         class->baseval = *c;
540
541         for (s = class->subclasses; s; s = s->next)
542                 mono_compute_relative_numbering ((MonoClass *)s->data, c); 
543         
544         class->diffval = *c -  class->baseval;
545 }
546
547 /**
548  * @image: context where the image is created
549  * @type_token:  typedef token
550  */
551 static MonoClass *
552 mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
553 {
554         MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
555         MonoClass *class, *parent = NULL;
556         guint32 cols [MONO_TYPEDEF_SIZE];
557         guint32 cols_next [MONO_TYPEDEF_SIZE];
558         guint tidx = mono_metadata_token_index (type_token);
559         const char *name, *nspace;
560         guint vtsize = 0, icount = 0; 
561         static guint interface_id = 0;
562         MonoClass **interfaces;
563         int i;
564
565         if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token))))
566                 return class;
567
568         g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
569         
570         mono_metadata_decode_row (tt, tidx - 1, cols, CSIZE (cols));
571         
572         if (tt->rows > tidx) {          
573                 mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next));
574                 vtsize += cols_next [MONO_TYPEDEF_METHOD_LIST] - cols [MONO_TYPEDEF_METHOD_LIST];
575         } else {
576                 vtsize += image->tables [MONO_TABLE_METHOD].rows - cols [MONO_TYPEDEF_METHOD_LIST] + 1;
577         }
578
579         name = mono_metadata_string_heap (image, cols[1]);
580         nspace = mono_metadata_string_heap (image, cols[2]);
581
582         if (!(!strcmp (nspace, "System") && !strcmp (name, "Object")) &&
583             !(cols [0] & TYPE_ATTRIBUTE_INTERFACE)) {
584                 parent = mono_class_get (image, mono_metadata_token_from_dor (cols [3]));
585         }
586         interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &icount);
587
588         for (i = 0; i < icount; i++) 
589                 vtsize += interfaces [i]->method.count;
590         
591         if (parent)
592                 vtsize += parent->vtable_size;
593
594         if (cols [0] & TYPE_ATTRIBUTE_INTERFACE)
595                 vtsize = 0;
596
597         class = g_malloc0 (sizeof (MonoClass) + vtsize * sizeof (gpointer));
598         
599         g_hash_table_insert (image->class_cache, GUINT_TO_POINTER (type_token), class);
600
601         class->parent = parent;
602         class->interfaces = interfaces;
603         class->interface_count = icount;
604         class->vtable_size = vtsize;
605
606         class->this_arg.byref = 1;
607         class->this_arg.data.klass = class;
608         class->this_arg.type = MONO_TYPE_CLASS;
609         class->byval_arg.data.klass = class;
610         class->byval_arg.type = MONO_TYPE_CLASS;
611
612         class->name = name;
613         class->name_space = nspace;
614
615         class->image = image;
616         class->type_token = type_token;
617         class->flags = cols [0];
618
619         class->element_class = class;
620
621         /*g_print ("Init class %s\n", name);*/
622
623         /* if root of the hierarchy */
624         if (!strcmp (nspace, "System") && !strcmp (name, "Object")) {
625                 class->parent = NULL;
626                 class->instance_size = sizeof (MonoObject);
627         } else if (!(cols [0] & TYPE_ATTRIBUTE_INTERFACE)) {
628                 int rnum = 0;
629                 class->parent = mono_class_get (image,  mono_metadata_token_from_dor (cols [3]));
630                 if (class->parent->enumtype || (strcmp (class->parent->name, "ValueType") == 0) && (strcmp (class->parent->name_space, "System") == 0))
631                         class->valuetype = 1;
632                 class->enumtype = class->parent->enumtype;
633                 class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
634                 mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
635         }
636
637         if (!strcmp (nspace, "System")) {
638                 if (!strcmp (name, "ValueType")) {
639                         /*
640                          * do not set the valuetype bit for System.ValueType.
641                          * class->valuetype = 1;
642                          */
643                 } else if (!strcmp (name, "Enum")) {
644                         /*
645                          * do not set the valuetype bit for System.Enum.
646                          * class->valuetype = 1;
647                          */
648                         class->valuetype = 0;
649                         class->enumtype = 1;
650                 } else if (!strcmp (name, "Object")) {
651                         class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
652                 } else if (!strcmp (name, "String")) {
653                         class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
654                 }
655         }
656         
657         if (class->valuetype) {
658                 int t = MONO_TYPE_VALUETYPE;
659                 if (!strcmp (nspace, "System")) {
660                         switch (*name) {
661                         case 'B':
662                                 if (!strcmp (name, "Boolean")) {
663                                         t = MONO_TYPE_BOOLEAN;
664                                 } else if (!strcmp(name, "Byte")) {
665                                         t = MONO_TYPE_U1;
666                                 }
667                                 break;
668                         case 'C':
669                                 if (!strcmp (name, "Char")) {
670                                         t = MONO_TYPE_CHAR;
671                                 }
672                                 break;
673                         case 'D':
674                                 if (!strcmp (name, "Double")) {
675                                         t = MONO_TYPE_R8;
676                                 }
677                                 break;
678                         case 'I':
679                                 if (!strcmp (name, "Int32")) {
680                                         t = MONO_TYPE_I4;
681                                 } else if (!strcmp(name, "Int16")) {
682                                         t = MONO_TYPE_I2;
683                                 } else if (!strcmp(name, "Int64")) {
684                                         t = MONO_TYPE_I8;
685                                 } else if (!strcmp(name, "IntPtr")) {
686                                         t = MONO_TYPE_I;
687                                 }
688                                 break;
689                         case 'S':
690                                 if (!strcmp (name, "Single")) {
691                                         t = MONO_TYPE_R4;
692                                 } else if (!strcmp(name, "SByte")) {
693                                         t = MONO_TYPE_I1;
694                                 }
695                                 break;
696                         case 'U':
697                                 if (!strcmp (name, "UInt32")) {
698                                         t = MONO_TYPE_U4;
699                                 } else if (!strcmp(name, "UInt16")) {
700                                         t = MONO_TYPE_U2;
701                                 } else if (!strcmp(name, "UInt64")) {
702                                         t = MONO_TYPE_U8;
703                                 } else if (!strcmp(name, "UIntPtr")) {
704                                         t = MONO_TYPE_U;
705                                 }
706                                 break;
707                         case 'V':
708                                 if (!strcmp (name, "Void")) {
709                                         t = MONO_TYPE_VOID;
710                                 }
711                                 break;
712                         default:
713                                 break;
714                         }
715                 }
716                 class->this_arg.type = class->byval_arg.type = t;
717         }
718
719         /*
720          * Compute the field and method lists
721          */
722         class->field.first  = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
723         class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
724
725         if (tt->rows > tidx){           
726                 mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next));
727                 class->field.last  = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
728                 class->method.last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
729         } else {
730                 class->field.last  = image->tables [MONO_TABLE_FIELD].rows;
731                 class->method.last = image->tables [MONO_TABLE_METHOD].rows;
732         }
733
734         if (cols [MONO_TYPEDEF_FIELD_LIST] && 
735             cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
736                 class->field.count = class->field.last - class->field.first;
737         else
738                 class->field.count = 0;
739
740         if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
741                 class->method.count = class->method.last - class->method.first;
742         else
743                 class->method.count = 0;
744
745         /* reserve space to store vector pointer in arrays */
746         if (!strcmp (nspace, "System") && !strcmp (name, "Array")) {
747                 class->instance_size += 2 * sizeof (gpointer);
748                 g_assert (class->field.count == 0);
749         }
750
751         if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
752                 class->interface_id = interface_id++;
753
754         //class->interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &class->interface_count);
755
756         if (class->enumtype)
757                 mono_class_init (class);
758
759         if ((type_token = mono_metadata_nested_in_typedef (image, type_token)))
760                 class->nested_in = mono_class_create_from_typedef (image, type_token);
761         return class;
762 }
763
764 MonoClass *
765 mono_class_from_mono_type (MonoType *type)
766 {
767         switch (type->type) {
768         case MONO_TYPE_OBJECT:
769                 return mono_defaults.object_class;
770         case MONO_TYPE_VOID:
771                 return mono_defaults.void_class;
772         case MONO_TYPE_BOOLEAN:
773                 return mono_defaults.boolean_class;
774         case MONO_TYPE_CHAR:
775                 return mono_defaults.char_class;
776         case MONO_TYPE_I1:
777                 return mono_defaults.byte_class;
778         case MONO_TYPE_U1:
779                 return mono_defaults.sbyte_class;
780         case MONO_TYPE_I2:
781                 return mono_defaults.int16_class;
782         case MONO_TYPE_U2:
783                 return mono_defaults.uint16_class;
784         case MONO_TYPE_I4:
785                 return mono_defaults.int32_class;
786         case MONO_TYPE_U4:
787                 return mono_defaults.uint32_class;
788         case MONO_TYPE_I:
789                 return mono_defaults.int_class;
790         case MONO_TYPE_U:
791                 return mono_defaults.uint_class;
792         case MONO_TYPE_I8:
793                 return mono_defaults.int64_class;
794         case MONO_TYPE_U8:
795                 return mono_defaults.uint64_class;
796         case MONO_TYPE_R4:
797                 return mono_defaults.single_class;
798         case MONO_TYPE_R8:
799                 return mono_defaults.double_class;
800         case MONO_TYPE_STRING:
801                 return mono_defaults.string_class;
802         case MONO_TYPE_ARRAY:
803                 return mono_defaults.array_class;
804         case MONO_TYPE_PTR:
805                 /* FIXME: this is wrong. Need to handle PTR types */
806                 return mono_class_from_mono_type (type->data.type);
807         case MONO_TYPE_SZARRAY:
808                 return mono_array_class_get (mono_class_from_mono_type (type->data.type), 1);
809         case MONO_TYPE_CLASS:
810         case MONO_TYPE_VALUETYPE:
811                 return type->data.klass;
812         default:
813                 g_warning ("implement me %02x\n", type->type);
814                 g_assert_not_reached ();
815         }
816         
817         return NULL;
818 }
819
820 /**
821  * @image: context where the image is created
822  * @type_spec:  typespec token
823  * @at: an optional pointer to return the array type
824  */
825 static MonoClass *
826 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec)
827 {
828         guint32 idx = mono_metadata_token_index (type_spec);
829         MonoTableInfo *t;
830         guint32 cols [MONO_TYPESPEC_SIZE];       
831         const char *ptr;
832         guint32 len;
833         MonoType *type;
834         MonoClass *class, *eclass;
835
836         t = &image->tables [MONO_TABLE_TYPESPEC];
837         
838         mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
839         ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
840         len = mono_metadata_decode_value (ptr, &ptr);
841         type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
842
843         switch (type->type) {
844         case MONO_TYPE_ARRAY:
845                 eclass = mono_class_from_mono_type (type->data.array->type);
846                 class = mono_array_class_get (eclass, type->data.array->rank);
847                 break;
848         case MONO_TYPE_SZARRAY:
849                 eclass = mono_class_from_mono_type (type->data.type);
850                 class = mono_array_class_get (eclass, 1);
851                 break;
852         default:
853                 g_warning ("implement me: %08x", type->type);
854                 g_assert_not_reached ();                
855         }
856
857         mono_metadata_free_type (type);
858         
859         return class;
860 }
861
862 /**
863  * mono_array_class_get:
864  * @eclass: element type class
865  * @rank: the dimension of the array class
866  *
867  * Returns: a class object describing the array with element type @etype and 
868  * dimension @rank. 
869  */
870 MonoClass *
871 mono_array_class_get (MonoClass *eclass, guint32 rank)
872 {
873         MonoImage *image;
874         MonoClass *class;
875         static MonoClass *parent = NULL;
876         guint32 key;
877         int rnum = 0;
878
879         g_assert (rank <= 255);
880
881         if (!parent)
882                 parent = mono_defaults.array_class;
883
884         if (!parent->inited)
885                 mono_class_init (parent);
886
887         image = eclass->image;
888
889         g_assert (!eclass->type_token ||
890                   mono_metadata_token_table (eclass->type_token) == MONO_TABLE_TYPEDEF);
891
892         key = ((rank & 0xff) << 24) | (eclass->type_token & 0xffffff);
893         if ((class = g_hash_table_lookup (image->array_cache, GUINT_TO_POINTER (key))))
894                 return class;
895         
896         class = g_malloc0 (sizeof (MonoClass) + parent->vtable_size * sizeof (gpointer));
897
898         class->image = image;
899         class->name_space = "System";
900         class->name = "Array";
901         class->type_token = 0;
902         class->flags = TYPE_ATTRIBUTE_CLASS;
903         class->parent = parent;
904         class->instance_size = mono_class_instance_size (class->parent);
905         class->class_size = 0;
906         class->vtable_size = parent->vtable_size;
907         class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
908         mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
909
910         class->rank = rank;
911         class->element_class = eclass;
912         if (rank > 1) {
913                 class->byval_arg.type = MONO_TYPE_ARRAY;
914                 /* FIXME: complete.... */
915         } else {
916                 class->byval_arg.type = MONO_TYPE_SZARRAY;
917                 class->byval_arg.data.type = &eclass->byval_arg;
918         }
919         class->this_arg = class->byval_arg;
920         class->this_arg.byref = 1;
921         
922         g_hash_table_insert (image->array_cache, GUINT_TO_POINTER (key), class);
923         return class;
924 }
925
926 /**
927  * mono_class_instance_size:
928  * @klass: a class 
929  * 
930  * Returns: the size of an object instance
931  */
932 gint32
933 mono_class_instance_size (MonoClass *klass)
934 {
935         
936         if (!klass->inited)
937                 mono_class_init (klass);
938
939         return klass->instance_size;
940 }
941
942 /**
943  * mono_class_value_size:
944  * @klass: a class 
945  *
946  * This function is used for value types, and return the
947  * space and the alignment to store that kind of value object.
948  *
949  * Returns: the size of a value of kind @klass
950  */
951 gint32
952 mono_class_value_size      (MonoClass *klass, guint32 *align)
953 {
954         gint32 size;
955
956         /* fixme: check disable, because we still have external revereces to
957          * mscorlib and Dummy Objects 
958          */
959         /*g_assert (klass->valuetype);*/
960
961         size = mono_class_instance_size (klass) - sizeof (MonoObject);
962
963         if (align)
964                 *align = klass->min_align;
965
966         return size;
967 }
968
969 /**
970  * mono_class_data_size:
971  * @klass: a class 
972  * 
973  * Returns: the size of the static class data
974  */
975 gint32
976 mono_class_data_size (MonoClass *klass)
977 {
978         
979         if (!klass->inited)
980                 mono_class_init (klass);
981
982         return klass->class_size;
983 }
984
985 /*
986  * Auxiliary routine to mono_class_get_field
987  *
988  * Takes a field index instead of a field token.
989  */
990 static MonoClassField *
991 mono_class_get_field_idx (MonoClass *class, int idx)
992 {
993         if (class->field.count){
994                 if ((idx >= class->field.first) && (idx < class->field.last)){
995                         return &class->fields [idx - class->field.first];
996                 }
997         }
998
999         if (!class->parent)
1000                 return NULL;
1001         
1002         return mono_class_get_field_idx (class->parent, idx);
1003 }
1004
1005 /**
1006  * mono_class_get_field:
1007  * @class: the class to lookup the field.
1008  * @field_token: the field token
1009  *
1010  * Returns: A MonoClassField representing the type and offset of
1011  * the field, or a NULL value if the field does not belong to this
1012  * class.
1013  */
1014 MonoClassField *
1015 mono_class_get_field (MonoClass *class, guint32 field_token)
1016 {
1017         int idx = mono_metadata_token_index (field_token);
1018
1019         g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
1020
1021         return mono_class_get_field_idx (class, idx - 1);
1022 }
1023
1024 MonoClassField *
1025 mono_class_get_field_from_name (MonoClass *klass, const char *name)
1026 {
1027         int i;
1028         guint32 token;
1029         MonoTableInfo *t = &klass->image->tables [MONO_TABLE_FIELD];
1030
1031         for (i = 0; i < klass->field.count; ++i) {
1032                 token = mono_metadata_decode_row_col (t, klass->field.first + i, MONO_FIELD_NAME);
1033                 if (strcmp (name, mono_metadata_string_heap (klass->image, token)) == 0)
1034                         return &klass->fields [i];
1035         }
1036         return NULL;
1037 }
1038
1039 /**
1040  * mono_class_get:
1041  * @image: the image where the class resides
1042  * @type_token: the token for the class
1043  * @at: an optional pointer to return the array element type
1044  *
1045  * Returns: the MonoClass that represents @type_token in @image
1046  */
1047 MonoClass *
1048 mono_class_get (MonoImage *image, guint32 type_token)
1049 {
1050         MonoClass *class;
1051
1052         switch (type_token & 0xff000000){
1053         case MONO_TOKEN_TYPE_DEF:
1054                 class = mono_class_create_from_typedef (image, type_token);
1055                 break;          
1056         case MONO_TOKEN_TYPE_REF:
1057                 return mono_class_create_from_typeref (image, type_token);
1058         case MONO_TOKEN_TYPE_SPEC:
1059                 class = mono_class_create_from_typespec (image, type_token);
1060                 break;
1061         default:
1062                 g_warning ("unknown token type %x", type_token & 0xff000000);
1063                 g_assert_not_reached ();
1064         }
1065
1066         return class;
1067 }
1068
1069 MonoClass *
1070 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
1071 {
1072         GHashTable *nspace_table;
1073         guint32 token;
1074
1075         nspace_table = g_hash_table_lookup (image->name_cache, name_space);
1076         if (!nspace_table)
1077                 return 0;
1078         token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
1079         
1080         if (!token) {
1081                 /*g_warning ("token not found for %s.%s in image %s", name_space, name, image->name);*/
1082                 return NULL;
1083         }
1084
1085         token = MONO_TOKEN_TYPE_DEF | token;
1086
1087         return mono_class_get (image, token);
1088 }
1089
1090 /**
1091  * mono_array_element_size:
1092  * @ac: pointer to a #MonoArrayClass
1093  *
1094  * Returns: the size of single array element.
1095  */
1096 gint32
1097 mono_array_element_size (MonoClass *ac)
1098 {
1099         if (ac->element_class->valuetype)
1100                 return mono_class_instance_size (ac->element_class) - sizeof (MonoObject);
1101         else
1102                 return sizeof (gpointer);
1103 }
1104
1105 gpointer
1106 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class)
1107 {
1108         switch (token & 0xff000000) {
1109         case MONO_TOKEN_TYPE_DEF:
1110         case MONO_TOKEN_TYPE_REF: {
1111                 MonoClass *class;
1112                 if (handle_class)
1113                         *handle_class = mono_defaults.typehandle_class;
1114                 class = mono_class_get (image, token);
1115                 /* We return a MonoType* as handle */
1116                 return &class->byval_arg;
1117         }
1118         case MONO_TOKEN_TYPE_SPEC: {
1119                 MonoClass *class;
1120                 if (handle_class)
1121                         *handle_class = mono_defaults.typehandle_class;
1122                 class = mono_class_create_from_typespec (image, token);
1123                 return &class->byval_arg;
1124         }
1125         case MONO_TOKEN_FIELD_DEF: {
1126                 MonoClass *class;
1127                 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
1128                 class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
1129                 mono_class_init (class);
1130                 if (handle_class)
1131                                 *handle_class = mono_class_from_name (mono_defaults.corlib, "System", "RuntimeFieldHandle");
1132                 return mono_class_get_field (class, token);
1133         }
1134         case MONO_TOKEN_METHOD_DEF:
1135         case MONO_TOKEN_MEMBER_REF:
1136         default:
1137                 g_warning ("Unknown token 0x%08x in ldtoken", token);
1138                 break;
1139         }
1140         return NULL;
1141 }
1142