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