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