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