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