Mon Dec 24 17:23:45 CET 2001 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / reflection.c
1
2 /*
3  * reflection.c: Routines for creating an image at runtime.
4  * 
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.  http://www.ximian.com
9  *
10  */
11 #include <config.h>
12 #include "mono/metadata/reflection.h"
13 #include "mono/metadata/tabledefs.h"
14 #include "mono/metadata/tokentype.h"
15 #include <stdio.h>
16 #include <glib.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <string.h>
20 #include "image.h"
21 #include "cil-coff.h"
22 #include "rawbuffer.h"
23 #include "mono-endian.h"
24 #include "private.h"
25
26 #define TEXT_OFFSET 512
27 #define CLI_H_SIZE 136
28 #define FILE_ALIGN 512
29
30 typedef struct {
31         MonoReflectionILGen *ilgen;
32         MonoReflectionType *rtype;
33         MonoArray *parameters;
34         guint32 attrs;
35         guint32 iattrs;
36         guint32 call_conv;
37         guint32 *table_idx; /* note: it's a pointer */
38         MonoArray *code;
39         MonoObject *type;
40         MonoString *name;
41 } ReflectionMethodBuilder;
42
43 const unsigned char table_sizes [64] = {
44         MONO_MODULE_SIZE,
45         MONO_TYPEREF_SIZE,
46         MONO_TYPEDEF_SIZE,
47         0,
48         MONO_FIELD_SIZE,
49         0,
50         MONO_METHOD_SIZE,
51         0,
52         MONO_PARAM_SIZE,
53         MONO_INTERFACEIMPL_SIZE,
54         MONO_MEMBERREF_SIZE,    /* 0x0A */
55         MONO_CONSTANT_SIZE,
56         MONO_CUSTOM_ATTR_SIZE,
57         MONO_FIELD_MARSHAL_SIZE,
58         MONO_DECL_SECURITY_SIZE,
59         MONO_CLASS_LAYOUT_SIZE,
60         MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
61         MONO_STAND_ALONE_SIGNATURE_SIZE,
62         MONO_EVENT_MAP_SIZE,
63         0,
64         MONO_EVENT_SIZE,
65         MONO_PROPERTY_MAP_SIZE,
66         0,
67         MONO_PROPERTY_SIZE,
68         MONO_METHOD_SEMA_SIZE,
69         MONO_MTHODIMPL_SIZE,
70         MONO_MODULEREF_SIZE,    /* 0x1A */
71         MONO_TYPESPEC_SIZE,
72         MONO_IMPLMAP_SIZE,      
73         MONO_FIELD_RVA_SIZE,
74         0,
75         0,
76         MONO_ASSEMBLY_SIZE,     /* 0x20 */
77         MONO_ASSEMBLY_PROCESSOR_SIZE,
78         MONO_ASSEMBLYOS_SIZE,
79         MONO_ASSEMBLYREF_SIZE,
80         MONO_ASSEMBLYREFPROC_SIZE,
81         MONO_ASSEMBLYREFOS_SIZE,
82         MONO_FILE_SIZE,
83         MONO_EXP_TYPE_SIZE,
84         MONO_MANIFEST_SIZE,
85         MONO_NESTED_CLASS_SIZE,
86         0       /* 0x2A */
87 };
88
89 static void
90 alloc_table (MonoDynamicTable *table, guint nrows)
91 {
92         table->rows = nrows;
93         g_assert (table->columns);
94         table->values = g_realloc (table->values, (1 + table->rows) * table->columns * sizeof (guint32));
95 }
96
97 static guint32
98 string_heap_insert (MonoStringHeap *sh, const char *str)
99 {
100         guint32 idx;
101         guint32 len;
102         gpointer oldkey, oldval;
103
104         if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
105                 return GPOINTER_TO_UINT (oldval);
106
107         len = strlen (str) + 1;
108         idx = sh->index;
109         if (idx + len > sh->alloc_size) {
110                 sh->alloc_size += len + 4096;
111                 sh->data = g_realloc (sh->data, sh->alloc_size);
112         }
113         /*
114          * We strdup the string even if we already copy them in sh->data
115          * so that the string pointers in the hash remain valid even if
116          * we need to realloc sh->data. We may want to avoid that later.
117          */
118         g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
119         memcpy (sh->data + idx, str, len);
120         sh->index += len;
121         return idx;
122 }
123
124 static void
125 string_heap_init (MonoStringHeap *sh)
126 {
127         sh->index = 0;
128         sh->alloc_size = 4096;
129         sh->data = g_malloc (4096);
130         sh->hash = g_hash_table_new (g_str_hash, g_str_equal);
131         string_heap_insert (sh, "");
132 }
133
134 static void
135 string_heap_free (MonoStringHeap *sh)
136 {
137         g_free (sh->data);
138         g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL);
139         g_hash_table_destroy (sh->hash);
140 }
141
142 static guint32
143 mono_image_add_stream_data (MonoDynamicStream *stream, char *data, guint32 len)
144 {
145         guint32 idx;
146         if (stream->alloc_size < stream->index + len) {
147                 stream->alloc_size += len + 4096;
148                 stream->data = g_realloc (stream->data, stream->alloc_size);
149         }
150         memcpy (stream->data + stream->index, data, len);
151         idx = stream->index;
152         stream->index += len;
153         /* 
154          * align index? Not without adding an additional param that controls it since
155          * we may store a blob value in pieces.
156          */
157         return idx;
158 }
159
160 static void
161 encode_type (MonoType *type, char *p, char **endbuf)
162 {
163         if (!type) {
164                 mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf);
165                 return;
166         }
167                 
168         switch (type->type){
169         case MONO_TYPE_VOID:
170         case MONO_TYPE_BOOLEAN:
171         case MONO_TYPE_CHAR:
172         case MONO_TYPE_I1:
173         case MONO_TYPE_U1:
174         case MONO_TYPE_I2:
175         case MONO_TYPE_U2:
176         case MONO_TYPE_I4:
177         case MONO_TYPE_U4:
178         case MONO_TYPE_I8:
179         case MONO_TYPE_U8:
180         case MONO_TYPE_R4:
181         case MONO_TYPE_R8:
182         case MONO_TYPE_I:
183         case MONO_TYPE_U:
184         case MONO_TYPE_STRING:
185         case MONO_TYPE_OBJECT:
186         case MONO_TYPE_TYPEDBYREF:
187                 mono_metadata_encode_value (type->type, p, endbuf);
188                 break;
189         case MONO_TYPE_SZARRAY:
190                 mono_metadata_encode_value (type->type, p, endbuf);
191                 encode_type (type->data.type, p, endbuf);
192                 break;
193         case MONO_TYPE_CLASS:
194                 mono_metadata_encode_value (type->type, p, endbuf);
195                 g_warning ("need to encode class %s", type->data.klass->name);
196                 break;
197         default:
198                 g_error ("need to encode type %x", type->type);
199         }
200 }
201
202 static guint32
203 method_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
204 {
205         char *buf;
206         char *p;
207         int i;
208         guint32 nparams =  mb->parameters ? mono_array_length (mb->parameters): 0;
209         guint32 size = 10 + nparams * 10;
210         guint32 idx;
211         char blob_size [6];
212         char *b = blob_size;
213         
214         p = buf = g_malloc (size);
215         /* LAMESPEC: all the call conv spec is foobared */
216         *p = mb->call_conv & 0x60; /* has-this, explicit-this */
217         if (mb->call_conv & 2)
218                 *p |= 0x5; /* vararg */
219         if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
220                 *p |= 0x20; /* hasthis */
221         p++;
222         mono_metadata_encode_value (nparams, p, &p);
223         encode_type (mb->rtype->type, p, &p);
224         for (i = 0; i < nparams; ++i) {
225                 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
226                 encode_type (pt->type, p, &p);
227         }
228         /* store length */
229         mono_metadata_encode_value (p-buf, b, &b);
230         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
231         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
232         g_free (buf);
233         return idx;
234 }
235
236 static guint32
237 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
238 {
239         MonoDynamicTable *table;
240         guint32 *values;
241         char *p;
242         guint32 idx, sig_idx;
243         guint nl = mono_array_length (ilgen->locals);
244         char *buf;
245         char blob_size [6];
246         char *b = blob_size;
247         int i;
248
249         p = buf = g_malloc (10 + nl * 10);
250         table = &assembly->tables [MONO_TABLE_STANDALONESIG];
251         idx = table->next_idx ++;
252         table->rows ++;
253         alloc_table (table, table->rows);
254         values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
255
256         mono_metadata_encode_value (0x07, p, &p);
257         mono_metadata_encode_value (nl, p, &p);
258         for (i = 0; i < nl; ++i) {
259                 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
260                 encode_type (lb->type->type, p, &p);
261         }
262         mono_metadata_encode_value (p-buf, b, &b);
263         sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
264         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
265         g_free (buf);
266
267         values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
268
269         return idx;
270 }
271
272 static guint32
273 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
274 {
275         /* we use only tiny formats now: need  to implement ILGenerator */
276         char flags = 0;
277         guint32 idx;
278         guint32 code_size;
279         gint32 max_stack;
280         gint32 num_locals = 0;
281         gint32 num_exception = 0;
282         gint maybe_small;
283         guint32 fat_flags;
284         char fat_header [12];
285         guint32 *intp;
286         guint16 *shortp;
287         guint32 local_sig = 0;
288         MonoArray *code;
289
290         if (mb->ilgen) {
291                 code = mb->ilgen->code;
292                 code_size = mb->ilgen->code_len;
293                 max_stack = mb->ilgen->max_stack;
294                 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
295         } else {
296                 code = mb->code;
297                 code_size = mono_array_length (code);
298                 max_stack = 8; /* we probably need to run a verifier on the code... */
299         }
300
301         /* check for exceptions, maxstack, locals */
302         maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
303         if (maybe_small) {
304                 if (code_size < 64 && !(code_size & 1)) {
305                         flags = (code_size << 2) | 0x2;
306                 } else if (code_size < 32 && (code_size & 1)) {
307                         flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
308                 } else {
309                         goto fat_header;
310                 }
311                 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
312                 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
313                 return assembly->text_rva + idx + CLI_H_SIZE;
314         } 
315 fat_header:
316         if (num_locals)
317                 local_sig = encode_locals (assembly, mb->ilgen);
318         /* 
319          * FIXME: need to set also the header size in fat_flags.
320          * (and more sects and init locals flags)
321          */
322         fat_flags =  0x03;
323         shortp = (guint16*)(fat_header);
324         *shortp = fat_flags;
325         shortp = (guint16*)(fat_header + 2);
326         *shortp = max_stack;
327         intp = (guint32*)(fat_header + 4);
328         *intp = code_size;
329         intp = (guint32*)(fat_header + 8);
330         *intp = local_sig;
331         idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
332         mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
333         return assembly->text_rva + idx + CLI_H_SIZE;
334 }
335
336 static guint32
337 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index)
338 {
339         int i;
340         MonoDynamicTable *table;
341         guint32 *values;
342         
343         table = &assembly->tables [table_idx];
344
345         g_assert (col < table->columns);
346
347         values = table->values + table->columns;
348         for (i = 1; i <= table->rows; ++i) {
349                 if (values [col] == index)
350                         return i;
351         }
352         return 0;
353 }
354
355 static void
356 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
357 {
358         MonoDynamicTable *table;
359         guint32 *values;
360         char *name;
361
362         table = &assembly->tables [MONO_TABLE_METHOD];
363         *mb->table_idx = table->next_idx ++;
364         values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
365         if (mb->name) {
366                 name = mono_string_to_utf8 (mb->name);
367                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
368                 g_free (name);
369         } else { /* a constructor */
370                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
371         }
372         values [MONO_METHOD_FLAGS] = mb->attrs;
373         values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
374         values [MONO_METHOD_SIGNATURE] = method_encode_signature (assembly, mb);
375         values [MONO_METHOD_PARAMLIST] = 0; /* FIXME: add support later */
376         values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
377 }
378
379 static void
380 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
381 {
382         MonoDynamicTable *table;
383         guint32 *values;
384         char *name;
385         ReflectionMethodBuilder rmb;
386
387         rmb.ilgen = mb->ilgen;
388         rmb.rtype = mb->rtype;
389         rmb.parameters = mb->parameters;
390         rmb.attrs = mb->attrs;
391         rmb.iattrs = mb->iattrs;
392         rmb.call_conv = mb->call_conv;
393         rmb.code = mb->code;
394         rmb.type = mb->type;
395         rmb.name = mb->name;
396         rmb.table_idx = &mb->table_idx;
397
398         mono_image_basic_method (&rmb, assembly);
399
400         if (mb->dll) { /* It's a P/Invoke method */
401                 guint32 moduleref;
402                 table = &assembly->tables [MONO_TABLE_IMPLMAP];
403                 table->rows ++;
404                 alloc_table (table, table->rows);
405                 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
406                 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
407                 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
408                 name = mono_string_to_utf8 (mb->dllentry);
409                 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
410                 g_free (name);
411                 name = mono_string_to_utf8 (mb->dll);
412                 moduleref = string_heap_insert (&assembly->sheap, name);
413                 g_free (name);
414                 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
415                         table = &assembly->tables [MONO_TABLE_MODULEREF];
416                         table->rows ++;
417                         alloc_table (table, table->rows);
418                         table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
419                         values [MONO_IMPLMAP_SCOPE] = table->rows;
420                 }
421         }
422 }
423
424 static void
425 mono_image_get_ctor_info (MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
426 {
427         ReflectionMethodBuilder rmb;
428
429         rmb.ilgen = mb->ilgen;
430         rmb.rtype = NULL;
431         rmb.parameters = mb->parameters;
432         rmb.attrs = mb->attrs;
433         rmb.iattrs = mb->iattrs;
434         rmb.call_conv = mb->call_conv;
435         rmb.code = NULL;
436         rmb.type = mb->type;
437         rmb.name = NULL;
438         rmb.table_idx = &mb->table_idx;
439
440         mono_image_basic_method (&rmb, assembly);
441
442 }
443
444 static guint32
445 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
446 {
447         char blob_size [64];
448         char *b = blob_size;
449         char *p;
450         char* buf;
451         guint32 idx;
452         
453         p = buf = g_malloc (64);
454         
455         mono_metadata_encode_value (0x06, p, &p);
456         /* encode custom attributes before the type */
457         encode_type (fb->type->type, p, &p);
458         g_assert (p-buf < 64);
459         mono_metadata_encode_value (p-buf, b, &b);
460         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
461         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
462         g_free (buf);
463         return idx;
464 }
465
466 static void
467 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
468 {
469         MonoDynamicTable *table;
470         guint32 *values;
471         char *name;
472
473         table = &assembly->tables [MONO_TABLE_FIELD];
474         fb->table_idx = table->next_idx ++;
475         values = table->values + fb->table_idx * MONO_FIELD_SIZE;
476         name = mono_string_to_utf8 (fb->name);
477         values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
478         g_free (name);
479         values [MONO_FIELD_FLAGS] = fb->attrs;
480         values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
481
482         if (fb->offset != -1) {
483                 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
484                 table->rows ++;
485                 alloc_table (table, table->rows);
486                 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
487                 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
488                 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
489         }
490 }
491
492 static guint32
493 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
494 {
495         char *buf, *p;
496         char blob_size [6];
497         char *b = blob_size;
498         guint32 nparams = 0;
499         MonoReflectionMethodBuilder *mb = fb->get_method;
500         guint32 idx, i;
501
502         if (mb && mb->parameters)
503                 nparams = mono_array_length (mb->parameters);
504         buf = p = g_malloc (24 + nparams * 10);
505         *p = 0x08;
506         p++;
507         mono_metadata_encode_value (nparams, p, &p);
508         if (mb) {
509                 encode_type (mb->rtype->type, p, &p);
510                 for (i = 0; i < nparams; ++i) {
511                         MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
512                         encode_type (pt->type, p, &p);
513                 }
514         } else {
515                 *p++ = 1; /* void: a property should probably not be allowed without a getter */
516         }
517         /* store length */
518         mono_metadata_encode_value (p-buf, b, &b);
519         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
520         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
521         g_free (buf);
522         return idx;
523 }
524
525 static void
526 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
527 {
528         MonoDynamicTable *table;
529         guint32 *values;
530         char *name;
531         guint num_methods = 0;
532         guint32 semaidx;
533
534         /* 
535          * we need to set things in the following tables:
536          * PROPERTYMAP (info already filled in _get_type_info ())
537          * PROPERTY    (rows already preallocated in _get_type_info ())
538          * METHOD      (method info already done with the generic method code)
539          * METHODSEMANTICS
540          */
541         table = &assembly->tables [MONO_TABLE_PROPERTY];
542         pb->table_idx = table->next_idx ++;
543         values = table->values + pb->table_idx * MONO_FIELD_SIZE;
544         name = mono_string_to_utf8 (pb->name);
545         values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
546         g_free (name);
547         values [MONO_PROPERTY_FLAGS] = pb->attrs;
548         values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
549
550         /* FIXME: we still don't handle 'other' methods */
551         if (pb->get_method) num_methods ++;
552         if (pb->set_method) num_methods ++;
553
554         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
555         table->rows += num_methods;
556         alloc_table (table, table->rows);
557
558         if (pb->get_method) {
559                 semaidx = table->next_idx ++;
560                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
561                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
562                 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
563                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 1;
564         }
565         if (pb->set_method) {
566                 semaidx = table->next_idx ++;
567                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
568                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
569                 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
570                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 0;
571         }
572 }
573
574 static guint32
575 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
576 {
577         if (image != mono_defaults.corlib)
578                 g_error ("multiple assemblyref not yet supported");
579         /* first row in assemblyref */
580         return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF;
581 }
582
583 static guint32
584 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
585 {
586         MonoDynamicTable *table;
587         guint32 *values;
588         guint32 token;
589         MonoClass *klass;
590
591         if (!assembly->typeref)
592                 assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal);
593         
594         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
595         if (token)
596                 return token;
597         klass = type->data.klass;
598         /*
599          * If it's in the same module:
600          * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS)
601          */
602
603         table = &assembly->tables [MONO_TABLE_TYPEREF];
604         alloc_table (table, table->rows + 1);
605         values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
606         values [MONO_TYPEREF_SCOPE] = resolution_scope_from_image (assembly, klass->image);
607         values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
608         values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
609         token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
610         g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
611         table->next_idx ++;
612         return token;
613 }
614
615 static void
616 mono_image_get_type_info (MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
617 {
618         MonoDynamicTable *table;
619         guint *values;
620         int i;
621         char *n;
622
623         table = &assembly->tables [MONO_TABLE_TYPEDEF];
624         tb->table_idx = table->next_idx ++;
625         values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
626         values [MONO_TYPEDEF_FLAGS] = tb->attrs;
627         values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
628         n = mono_string_to_utf8 (tb->name);
629         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
630         g_free (n);
631         n = mono_string_to_utf8 (tb->nspace);
632         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
633         g_free (n);
634         values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
635         values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
636
637         /* handle methods */
638         if (tb->methods) {
639                 table = &assembly->tables [MONO_TABLE_METHOD];
640                 table->rows += mono_array_length (tb->methods);
641                 alloc_table (table, table->rows);
642                 for (i = 0; i < mono_array_length (tb->methods); ++i)
643                         mono_image_get_method_info (
644                                 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
645         }
646
647         /* handle constructors */
648         if (tb->ctors) {
649                 table = &assembly->tables [MONO_TABLE_METHOD];
650                 table->rows += mono_array_length (tb->ctors);
651                 alloc_table (table, table->rows);
652                 for (i = 0; i < mono_array_length (tb->ctors); ++i)
653                         mono_image_get_ctor_info (
654                                 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
655         }
656
657         /* handle fields */
658         if (tb->fields) {
659                 table = &assembly->tables [MONO_TABLE_FIELD];
660                 table->rows += mono_array_length (tb->fields);
661                 alloc_table (table, table->rows);
662                 for (i = 0; i < mono_array_length (tb->fields); ++i)
663                         mono_image_get_field_info (
664                                 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
665         }
666
667         /* Do the same with properties etc.. */
668         if (tb->properties && mono_array_length (tb->properties)) {
669                 table = &assembly->tables [MONO_TABLE_PROPERTY];
670                 table->rows += mono_array_length (tb->properties);
671                 alloc_table (table, table->rows);
672                 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
673                 table->rows ++;
674                 alloc_table (table, table->rows);
675                 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
676                 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
677                 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
678                 for (i = 0; i < mono_array_length (tb->properties); ++i)
679                         mono_image_get_property_info (
680                                 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
681         }
682 }
683
684 static void
685 mono_image_fill_module_table (MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
686 {
687         MonoDynamicTable *table;
688         int i;
689         char *name;
690
691         table = &assembly->tables [MONO_TABLE_MODULE];
692         mb->table_idx = table->next_idx ++;
693         name = mono_string_to_utf8 (mb->module.name);
694         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
695         g_free (name);
696         /* need to set mvid? */
697
698         /*
699          * fill-in info in other tables as well.
700          */
701         table = &assembly->tables [MONO_TABLE_TYPEDEF];
702         table->rows += mono_array_length (mb->types);
703         alloc_table (table, table->rows);
704         for (i = 0; i < mono_array_length (mb->types); ++i)
705                 mono_image_get_type_info (mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
706 }
707
708 #define align_pointer(base,p)\
709         do {\
710                 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
711                 if (__diff & 3)\
712                         (p) += 4 - (__diff & 3);\
713         } while (0)
714
715 static void
716 build_compressed_metadata (MonoDynamicAssembly *assembly)
717 {
718         int i;
719         guint64 valid_mask = 0;
720         guint32 heapt_size = 0;
721         guint32 meta_size = 256; /* allow for header and other stuff */
722         guint32 table_offset;
723         guint32 ntables = 0;
724         guint64 *int64val;
725         guint32 *int32val;
726         guint16 *int16val;
727         MonoImage *meta;
728         unsigned char *p;
729         char *version = "mono" VERSION;
730         
731         /* Compute table sizes */
732         meta = assembly->assembly.image = g_new0 (MonoImage, 1);
733         
734         /* Setup the info used by compute_sizes () */
735         meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
736         meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
737         meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
738
739         meta_size += assembly->blob.index;
740         meta_size += assembly->guid.index;
741         meta_size += assembly->sheap.index;
742         meta_size += assembly->us.index;
743
744         for (i=0; i < 64; ++i)
745                 meta->tables [i].rows = assembly->tables [i].rows;
746         
747         for (i = 0; i < 64; i++){
748                 if (meta->tables [i].rows == 0)
749                         continue;
750                 valid_mask |= (guint64)1 << i;
751                 ntables ++;
752                 meta->tables [i].row_size = mono_metadata_compute_size (
753                         meta, i, &meta->tables [i].size_bitfield);
754                 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
755         }
756         heapt_size += 24; /* #~ header size */
757         heapt_size += ntables * 4;
758         meta_size += heapt_size;
759         meta->raw_metadata = g_malloc0 (meta_size);
760         p = meta->raw_metadata;
761         /* the metadata signature */
762         *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
763         /* version numbers and 4 bytes reserved */
764         int16val = (guint16*)p;
765         *int16val++ = 1;
766         *int16val = 1;
767         p += 8;
768         /* version string */
769         int32val = (guint32*)p;
770         *int32val = strlen (version);
771         p += 4;
772         memcpy (p, version, *int32val);
773         p += *int32val;
774         align_pointer (meta->raw_metadata, p);
775         int16val = (guint16*)p;
776         *int16val++ = 0; /* flags must be 0 */
777         *int16val = 5; /* number of streams */
778         p += 4;
779
780         /*
781          * write the stream info.
782          */
783         table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
784         
785         int32val = (guint32*)p;
786         *int32val++ = assembly->tstream.offset = table_offset;
787         *int32val = heapt_size;
788         table_offset += *int32val;
789         p += 8;
790         strcpy (p, "#~");
791         p += 3;
792         align_pointer (meta->raw_metadata, p);
793
794         int32val = (guint32*)p;
795         *int32val++ = assembly->sheap.offset = table_offset;
796         *int32val = assembly->sheap.index;
797         table_offset += *int32val;
798         p += 8;
799         strcpy (p, "#Strings");
800         p += 9;
801         align_pointer (meta->raw_metadata, p);
802
803         int32val = (guint32*)p;
804         *int32val++ = assembly->us.offset = table_offset;
805         *int32val = assembly->us.index;
806         table_offset += *int32val;
807         p += 8;
808         strcpy (p, "#US");
809         p += 4;
810         align_pointer (meta->raw_metadata, p);
811
812         int32val = (guint32*)p;
813         *int32val++ = assembly->blob.offset = table_offset;
814         *int32val = assembly->blob.index;
815         table_offset += *int32val;
816         p += 8;
817         strcpy (p, "#Blob");
818         p += 6;
819         align_pointer (meta->raw_metadata, p);
820
821         int32val = (guint32*)p;
822         *int32val++ = assembly->guid.offset = table_offset;
823         *int32val = assembly->guid.index;
824         table_offset += *int32val;
825         p += 8;
826         strcpy (p, "#GUID");
827         p += 6;
828         align_pointer (meta->raw_metadata, p);
829
830         /* 
831          * now copy the data, the table stream header and contents goes first.
832          */
833         g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
834         p = meta->raw_metadata + assembly->tstream.offset;
835         int32val = (guint32*)p;
836         *int32val = 0; /* reserved */
837         p += 4;
838         *p++ = 1; /* version */
839         *p++ = 0;
840         if (meta->idx_string_wide)
841                 *p |= 0x01;
842         if (meta->idx_guid_wide)
843                 *p |= 0x02;
844         if (meta->idx_blob_wide)
845                 *p |= 0x04;
846         ++p;
847         *p++ = 0; /* reserved */
848         int64val = (guint64*)p;
849         *int64val++ = valid_mask;
850         *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now  */
851         p += 16;
852         int32val = (guint32*)p;
853         for (i = 0; i < 64; i++){
854                 if (meta->tables [i].rows == 0)
855                         continue;
856                 *int32val++ = meta->tables [i].rows;
857         }
858         p = (unsigned char*)int32val;
859         /* compress the tables */
860         for (i = 0; i < 64; i++){
861                 int row, col;
862                 guint32 *values;
863                 guint32 bitfield = meta->tables [i].size_bitfield;
864                 if (!meta->tables [i].rows)
865                         continue;
866                 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
867                         g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
868                 meta->tables [i].base = p;
869                 for (row = 1; row <= meta->tables [i].rows; ++row) {
870                         values = assembly->tables [i].values + row * assembly->tables [i].columns;
871                         for (col = 0; col < assembly->tables [i].columns; ++col) {
872                                 switch (mono_metadata_table_size (bitfield, col)) {
873                                 case 1:
874                                         *p++ = values [col];
875                                         break;
876                                 case 2:
877                                         int16val = (guint16*)p;
878                                         *int16val = values [col];
879                                         p += 2;
880                                         break;
881                                 case 4:
882                                         int32val = (guint32*)p;
883                                         *int32val = values [col];
884                                         p += 4;
885                                         break;
886                                 default:
887                                         g_assert_not_reached ();
888                                 }
889                         }
890                 }
891                 g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
892         }
893         
894         g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
895         memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
896         memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
897         memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
898         memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
899
900         assembly->meta_size = assembly->guid.offset + assembly->guid.index;
901 }
902
903 static void
904 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
905 {
906         MonoDynamicTable *table;
907         MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
908         guint32 len;
909         guint32 *values;
910         char *name;
911         int i;
912         
913         assembly->text_rva =  0x00002000;
914
915         table = &assembly->tables [MONO_TABLE_ASSEMBLY];
916         alloc_table (table, 1);
917         values = table->values + MONO_ASSEMBLY_SIZE;
918         values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
919         name = mono_string_to_utf8 (assemblyb->name);
920         values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
921         g_free (name);
922         values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
923         values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
924         values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
925         values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
926         values [MONO_ASSEMBLY_REV_NUMBER] = 0;
927         values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
928
929         assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
930         assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
931
932         len = mono_array_length (assemblyb->modules);
933         table = &assembly->tables [MONO_TABLE_MODULE];
934         alloc_table (table, len);
935         for (i = 0; i < len; ++i)
936                 mono_image_fill_module_table (mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
937
938         table = &assembly->tables [MONO_TABLE_TYPEDEF];
939         /* 
940          * table->rows is already set above and in mono_image_fill_module_table.
941          */
942         alloc_table (table, table->rows);
943         /*
944          * Set the first entry.
945          */
946         values = table->values + table->columns;
947         values [MONO_TYPEDEF_FLAGS] = 0;
948         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
949         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
950         values [MONO_TYPEDEF_EXTENDS] = 0;
951         values [MONO_TYPEDEF_FIELD_LIST] = 1;
952         values [MONO_TYPEDEF_METHOD_LIST] = 1;
953
954         /* later include all the assemblies referenced */
955         table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
956         alloc_table (table, 1);
957         values = table->values + table->columns;
958         values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib");
959
960         build_compressed_metadata (assembly);
961 }
962
963 guint32
964 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
965 {
966         guint32 index;
967         char buf [16];
968         char *b = buf;
969         
970         if (!assembly->dynamic_assembly)
971                 mono_image_basic_init (assembly);
972         mono_metadata_encode_value (str->length, b, &b);
973         index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
974         /* FIXME: ENOENDIAN */
975         mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2);
976         return index;
977 }
978
979 /*
980  * Get a token to insert in the IL code stream for the given MemberInfo.
981  * obj can be:
982  *      ConstructorBuilder
983  *      MethodBuilder
984  *      FieldBuilder
985  *      MonoCMethod
986  *      MonoMethod
987  *      MonoField
988  */
989 guint32
990 mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj)
991 {
992         MonoClass *klass = obj->klass;
993
994         g_print ("requested token for %s\n", klass->name);
995         
996         if (strcmp (klass->name, "MethodBuilder") == 0) {
997                 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
998                 return mb->table_idx | MONO_TOKEN_METHOD_DEF;
999         }
1000         if (strcmp (klass->name, "FieldBuilder") == 0) {
1001                 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
1002                 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
1003         }
1004         return 0;
1005 }
1006
1007 void
1008 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
1009 {
1010         MonoDynamicAssembly *assembly;
1011         int i;
1012         
1013         if (assemblyb->dynamic_assembly)
1014                 return;
1015
1016         assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
1017
1018         string_heap_init (&assembly->sheap);
1019         mono_image_add_stream_data (&assembly->us, "", 1);
1020         mono_image_add_stream_data (&assembly->blob, "", 1);
1021
1022         for (i=0; i < 64; ++i) {
1023                 assembly->tables [i].next_idx = 1;
1024                 assembly->tables [i].columns = table_sizes [i];
1025         }
1026         
1027 }
1028
1029 int
1030 mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize)
1031 {
1032         MonoMSDOSHeader *msdos;
1033         MonoDotNetHeader *header;
1034         MonoSectionTable *section;
1035         MonoCLIHeader *cli_header;
1036         guint32 header_size =  TEXT_OFFSET + CLI_H_SIZE;
1037         MonoDynamicAssembly *assembly;
1038
1039         static const unsigned char msheader[] = {
1040                 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,  0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1041                 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
1044                 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,  0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
1045                 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,  0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
1046                 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,  0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
1047                 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1048         };
1049
1050         if (maxsize < header_size)
1051                 return -1;
1052
1053         mono_image_basic_init (assemblyb);
1054         assembly = assemblyb->dynamic_assembly;
1055
1056         mono_image_build_metadata (assemblyb);
1057
1058         memset (buffer, 0, header_size);
1059         memcpy (buffer, msheader, sizeof (MonoMSDOSHeader));
1060
1061         msdos = (MonoMSDOSHeader *)buffer;
1062         header = (MonoDotNetHeader *)(buffer + sizeof (MonoMSDOSHeader));
1063         section = (MonoSectionTable*) (buffer + sizeof (MonoMSDOSHeader) + sizeof (MonoDotNetHeader));
1064
1065         /* FIXME: ENDIAN problem: byteswap as needed */
1066         msdos->pe_offset = sizeof (MonoMSDOSHeader);
1067
1068         header->pesig [0] = 'P';
1069         header->pesig [1] = 'E';
1070         header->pesig [2] = header->pesig [3] = 0;
1071
1072         header->coff.coff_machine = 0x14c;
1073         header->coff.coff_sections = 1; /* only .text supported now */
1074         header->coff.coff_time = time (NULL);
1075         header->coff.coff_opt_header_size = sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4;
1076         /* it's an exe */
1077         header->coff.coff_attributes = 0x010e;
1078         /* it's a dll */
1079         //header->coff.coff_attributes = 0x210e;
1080         header->pe.pe_magic = 0x10B;
1081         header->pe.pe_major = 6;
1082         header->pe.pe_minor = 0;
1083         /* need to set: pe_code_size pe_data_size pe_rva_entry_point pe_rva_code_base pe_rva_data_base */
1084
1085         header->nt.pe_image_base = 0x400000;
1086         header->nt.pe_section_align = 8192;
1087         header->nt.pe_file_alignment = FILE_ALIGN;
1088         header->nt.pe_os_major = 4;
1089         header->nt.pe_os_minor = 0;
1090         header->nt.pe_subsys_major = 4;
1091         /* need to set pe_image_size, pe_header_size */
1092         header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */
1093         header->nt.pe_stack_reserve = 0x00100000;
1094         header->nt.pe_stack_commit = 0x00001000;
1095         header->nt.pe_heap_reserve = 0x00100000;
1096         header->nt.pe_heap_commit = 0x00001000;
1097         header->nt.pe_loader_flags = 1;
1098         header->nt.pe_data_dir_count = 16;
1099
1100 #if 0
1101         /* set: */
1102         header->datadir.pe_import_table
1103         pe_resource_table
1104         pe_reloc_table
1105         pe_iat  
1106 #endif
1107         header->datadir.pe_cli_header.size = CLI_H_SIZE;
1108         header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */
1109
1110         /* Write section tables */
1111         strcpy (section->st_name, ".text");
1112         section->st_virtual_size = 1024; /* FIXME */
1113         section->st_virtual_address = assembly->text_rva;
1114         section->st_raw_data_size = 1024; /* FIXME */
1115         section->st_raw_data_ptr = TEXT_OFFSET;
1116         section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
1117
1118         /* 
1119          * align: build_compressed_metadata () assumes metadata is aligned 
1120          * see below:
1121          * cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1122          */
1123         assembly->code.index += 3;
1124         assembly->code.index &= ~3;
1125
1126         /*
1127          * Write the MonoCLIHeader header 
1128          */
1129         cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET);
1130         cli_header->ch_size = CLI_H_SIZE;
1131         cli_header->ch_runtime_major = 2;
1132         cli_header->ch_flags = CLI_FLAGS_ILONLY;
1133         if (assemblyb->entry_point) 
1134                 cli_header->ch_entry_point = assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF;
1135         else
1136                 cli_header->ch_entry_point = 0;
1137         cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1138         cli_header->ch_metadata.size = assembly->meta_size;
1139         
1140         return header_size;
1141 }
1142
1143 /*
1144  * We need to return always the same object for Type, MethodInfo, FieldInfo etc..
1145  */
1146 static GHashTable *object_cache = NULL;
1147
1148 #define CHECK_OBJECT(t,p)       \
1149         do {    \
1150                 t _obj; \
1151                 if (!object_cache)      \
1152                         object_cache = g_hash_table_new (g_direct_hash, g_direct_equal);        \
1153                 if ((_obj = g_hash_table_lookup (object_cache, (p))))   \
1154                         return _obj;    \
1155         } while (0)
1156
1157 #define CACHE_OBJECT(p,o)       \
1158         do {    \
1159                 g_hash_table_insert (object_cache, p,o);        \
1160         } while (0)
1161         
1162 MonoReflectionAssembly*
1163 mono_assembly_get_object (MonoAssembly *assembly)
1164 {
1165         MonoClass *klass;
1166         MonoReflectionAssembly *res;
1167         
1168         CHECK_OBJECT (MonoReflectionAssembly *, assembly);
1169         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "Assembly");
1170         res = (MonoReflectionAssembly *)mono_object_new (klass);
1171         res->assembly = assembly;
1172         CACHE_OBJECT (assembly, res);
1173         return res;
1174 }
1175
1176 MonoReflectionType*
1177 mono_type_get_object (MonoType *type)
1178 {
1179         MonoReflectionType *res;
1180
1181         CHECK_OBJECT (MonoReflectionType *, type);
1182         res = (MonoReflectionType *)mono_object_new (mono_defaults.monotype_class);
1183         res->type = type;
1184         CACHE_OBJECT (type, res);
1185         return res;
1186 }
1187
1188 MonoReflectionMethod*
1189 mono_method_get_object (MonoMethod *method)
1190 {
1191         /*
1192          * We use the same C representation for methods and constructors, but the type 
1193          * name in C# is different.
1194          */
1195         char *cname;
1196         MonoClass *klass;
1197         MonoReflectionMethod *ret;
1198
1199         CHECK_OBJECT (MonoReflectionMethod *, method);
1200         if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
1201                 cname = "MonoCMethod";
1202         else
1203                 cname = "MonoMethod";
1204         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
1205
1206         ret = (MonoReflectionMethod*)mono_object_new (klass);
1207         ret->method = method;
1208         CACHE_OBJECT (method, ret);
1209         return ret;
1210 }
1211
1212 MonoReflectionField*
1213 mono_field_get_object (MonoClass *klass, MonoClassField *field)
1214 {
1215         MonoReflectionField *res;
1216         MonoClass *oklass;
1217
1218         CHECK_OBJECT (MonoReflectionField *, field);
1219         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
1220         res = (MonoReflectionField *)mono_object_new (oklass);
1221         res->klass = klass;
1222         res->field = field;
1223         CACHE_OBJECT (field, res);
1224         return res;
1225 }
1226
1227 MonoReflectionProperty*
1228 mono_property_get_object (MonoClass *klass, MonoProperty *property)
1229 {
1230         MonoReflectionProperty *res;
1231         MonoClass *oklass;
1232
1233         CHECK_OBJECT (MonoReflectionProperty *, property);
1234         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
1235         res = (MonoReflectionProperty *)mono_object_new (oklass);
1236         res->klass = klass;
1237         res->property = property;
1238         CACHE_OBJECT (property, res);
1239         return res;
1240 }
1241
1242 MonoReflectionParameter**
1243 mono_param_get_objects (MonoMethod *method)
1244 {
1245         MonoReflectionParameter **res;
1246         MonoReflectionMethod *member;
1247         MonoClass *oklass;
1248         char **names;
1249         int i;
1250
1251         if (!method->signature->param_count)
1252                 return NULL;
1253
1254         member = mono_method_get_object (method);
1255         names = g_new (char*, method->signature->param_count);
1256         
1257         /* Note: the cache is based on the address of the signature into the method
1258          * since we already cache MethodInfos with the method as keys.
1259          */
1260         CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
1261         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
1262         res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
1263         for (i = 0; i < method->signature->param_count; ++i) {
1264                 res [i] = (MonoReflectionParameter *)mono_object_new (oklass);
1265                 res [i]->ClassImpl = mono_type_get_object (method->signature->params [i]);
1266                 res [i]->DefaultValueImpl = NULL; /* FIXME */
1267                 res [i]->MemberImpl = (MonoObject*)member;
1268                 res [i]->NameImpl = mono_string_new (names [i]);
1269                 res [i]->PositionImpl = i + 1;
1270                 res [i]->AttrsImpl = method->signature->params [i]->attrs;
1271         }
1272         g_free (names);
1273         CACHE_OBJECT (&(method->signature), res);
1274         return res;
1275 }
1276