Sat Jan 5 15:48:04 CET 2002 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, MonoMethodSignature *sig)
204 {
205         char *buf;
206         char *p;
207         int i;
208         guint32 nparams =  sig->param_count;
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         /*
216          * FIXME: vararg, explicit_this, differenc call_conv values...
217          */
218         *p = sig->call_convention;
219         if (sig->hasthis)
220                 *p |= 0x20; /* hasthis */
221         p++;
222         mono_metadata_encode_value (nparams, p, &p);
223         encode_type (sig->ret, p, &p);
224         for (i = 0; i < nparams; ++i)
225                 encode_type (sig->params [i], p, &p);
226         /* store length */
227         mono_metadata_encode_value (p-buf, b, &b);
228         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
229         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
230         g_free (buf);
231         return idx;
232 }
233
234 static guint32
235 method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
236 {
237         /*
238          * FIXME: reuse code from method_encode_signature().
239          */
240         char *buf;
241         char *p;
242         int i;
243         guint32 nparams =  mb->parameters ? mono_array_length (mb->parameters): 0;
244         guint32 size = 10 + nparams * 10;
245         guint32 idx;
246         char blob_size [6];
247         char *b = blob_size;
248         
249         p = buf = g_malloc (size);
250         /* LAMESPEC: all the call conv spec is foobared */
251         *p = mb->call_conv & 0x60; /* has-this, explicit-this */
252         if (mb->call_conv & 2)
253                 *p |= 0x5; /* vararg */
254         if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
255                 *p |= 0x20; /* hasthis */
256         p++;
257         mono_metadata_encode_value (nparams, p, &p);
258         encode_type (mb->rtype->type, p, &p);
259         for (i = 0; i < nparams; ++i) {
260                 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
261                 encode_type (pt->type, p, &p);
262         }
263         /* store length */
264         mono_metadata_encode_value (p-buf, b, &b);
265         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
266         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
267         g_free (buf);
268         return idx;
269 }
270
271 static guint32
272 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
273 {
274         MonoDynamicTable *table;
275         guint32 *values;
276         char *p;
277         guint32 idx, sig_idx;
278         guint nl = mono_array_length (ilgen->locals);
279         char *buf;
280         char blob_size [6];
281         char *b = blob_size;
282         int i;
283
284         p = buf = g_malloc (10 + nl * 10);
285         table = &assembly->tables [MONO_TABLE_STANDALONESIG];
286         idx = table->next_idx ++;
287         table->rows ++;
288         alloc_table (table, table->rows);
289         values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
290
291         mono_metadata_encode_value (0x07, p, &p);
292         mono_metadata_encode_value (nl, p, &p);
293         for (i = 0; i < nl; ++i) {
294                 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
295                 encode_type (lb->type->type, p, &p);
296         }
297         mono_metadata_encode_value (p-buf, b, &b);
298         sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
299         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
300         g_free (buf);
301
302         values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
303
304         return idx;
305 }
306
307 static guint32
308 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
309 {
310         /* we use only tiny formats now: need  to implement ILGenerator */
311         char flags = 0;
312         guint32 idx;
313         guint32 code_size;
314         gint32 max_stack;
315         gint32 num_locals = 0;
316         gint32 num_exception = 0;
317         gint maybe_small;
318         guint32 fat_flags;
319         char fat_header [12];
320         guint32 *intp;
321         guint16 *shortp;
322         guint32 local_sig = 0;
323         MonoArray *code;
324
325         if (mb->ilgen) {
326                 code = mb->ilgen->code;
327                 code_size = mb->ilgen->code_len;
328                 max_stack = mb->ilgen->max_stack;
329                 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
330         } else {
331                 code = mb->code;
332                 code_size = mono_array_length (code);
333                 max_stack = 8; /* we probably need to run a verifier on the code... */
334         }
335
336         /* check for exceptions, maxstack, locals */
337         maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
338         if (maybe_small) {
339                 if (code_size < 64 && !(code_size & 1)) {
340                         flags = (code_size << 2) | 0x2;
341                 } else if (code_size < 32 && (code_size & 1)) {
342                         flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
343                 } else {
344                         goto fat_header;
345                 }
346                 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
347                 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
348                 return assembly->text_rva + idx + CLI_H_SIZE;
349         } 
350 fat_header:
351         if (num_locals)
352                 local_sig = encode_locals (assembly, mb->ilgen);
353         /* 
354          * FIXME: need to set also the header size in fat_flags.
355          * (and more sects and init locals flags)
356          */
357         fat_flags =  0x03;
358         shortp = (guint16*)(fat_header);
359         *shortp = fat_flags;
360         shortp = (guint16*)(fat_header + 2);
361         *shortp = max_stack;
362         intp = (guint32*)(fat_header + 4);
363         *intp = code_size;
364         intp = (guint32*)(fat_header + 8);
365         *intp = local_sig;
366         idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
367         mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
368         return assembly->text_rva + idx + CLI_H_SIZE;
369 }
370
371 static guint32
372 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index)
373 {
374         int i;
375         MonoDynamicTable *table;
376         guint32 *values;
377         
378         table = &assembly->tables [table_idx];
379
380         g_assert (col < table->columns);
381
382         values = table->values + table->columns;
383         for (i = 1; i <= table->rows; ++i) {
384                 if (values [col] == index)
385                         return i;
386         }
387         return 0;
388 }
389
390 static void
391 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
392 {
393         MonoDynamicTable *table;
394         guint32 *values;
395         char *name;
396
397         table = &assembly->tables [MONO_TABLE_METHOD];
398         *mb->table_idx = table->next_idx ++;
399         values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
400         if (mb->name) {
401                 name = mono_string_to_utf8 (mb->name);
402                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
403                 g_free (name);
404         } else { /* a constructor */
405                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
406         }
407         values [MONO_METHOD_FLAGS] = mb->attrs;
408         values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
409         values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
410         values [MONO_METHOD_PARAMLIST] = 0; /* FIXME: add support later */
411         values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
412 }
413
414 static void
415 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
416 {
417         MonoDynamicTable *table;
418         guint32 *values;
419         char *name;
420         ReflectionMethodBuilder rmb;
421
422         rmb.ilgen = mb->ilgen;
423         rmb.rtype = mb->rtype;
424         rmb.parameters = mb->parameters;
425         rmb.attrs = mb->attrs;
426         rmb.iattrs = mb->iattrs;
427         rmb.call_conv = mb->call_conv;
428         rmb.code = mb->code;
429         rmb.type = mb->type;
430         rmb.name = mb->name;
431         rmb.table_idx = &mb->table_idx;
432
433         mono_image_basic_method (&rmb, assembly);
434
435         if (mb->dll) { /* It's a P/Invoke method */
436                 guint32 moduleref;
437                 table = &assembly->tables [MONO_TABLE_IMPLMAP];
438                 table->rows ++;
439                 alloc_table (table, table->rows);
440                 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
441                 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
442                 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
443                 name = mono_string_to_utf8 (mb->dllentry);
444                 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
445                 g_free (name);
446                 name = mono_string_to_utf8 (mb->dll);
447                 moduleref = string_heap_insert (&assembly->sheap, name);
448                 g_free (name);
449                 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
450                         table = &assembly->tables [MONO_TABLE_MODULEREF];
451                         table->rows ++;
452                         alloc_table (table, table->rows);
453                         table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
454                         values [MONO_IMPLMAP_SCOPE] = table->rows;
455                 }
456         }
457 }
458
459 static void
460 mono_image_get_ctor_info (MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
461 {
462         ReflectionMethodBuilder rmb;
463
464         rmb.ilgen = mb->ilgen;
465         rmb.rtype = mono_type_get_object (&mono_defaults.void_class->byval_arg);
466         rmb.parameters = mb->parameters;
467         rmb.attrs = mb->attrs;
468         rmb.iattrs = mb->iattrs;
469         rmb.call_conv = mb->call_conv;
470         rmb.code = NULL;
471         rmb.type = mb->type;
472         rmb.name = NULL;
473         rmb.table_idx = &mb->table_idx;
474
475         mono_image_basic_method (&rmb, assembly);
476
477 }
478
479 static guint32
480 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
481 {
482         char blob_size [64];
483         char *b = blob_size;
484         char *p;
485         char* buf;
486         guint32 idx;
487         
488         p = buf = g_malloc (64);
489         
490         mono_metadata_encode_value (0x06, p, &p);
491         /* encode custom attributes before the type */
492         encode_type (fb->type->type, p, &p);
493         g_assert (p-buf < 64);
494         mono_metadata_encode_value (p-buf, b, &b);
495         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
496         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
497         g_free (buf);
498         return idx;
499 }
500
501 static void
502 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
503 {
504         MonoDynamicTable *table;
505         guint32 *values;
506         char *name;
507
508         table = &assembly->tables [MONO_TABLE_FIELD];
509         fb->table_idx = table->next_idx ++;
510         values = table->values + fb->table_idx * MONO_FIELD_SIZE;
511         name = mono_string_to_utf8 (fb->name);
512         values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
513         g_free (name);
514         values [MONO_FIELD_FLAGS] = fb->attrs;
515         values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
516
517         if (fb->offset != -1) {
518                 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
519                 table->rows ++;
520                 alloc_table (table, table->rows);
521                 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
522                 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
523                 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
524         }
525 }
526
527 static guint32
528 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
529 {
530         char *buf, *p;
531         char blob_size [6];
532         char *b = blob_size;
533         guint32 nparams = 0;
534         MonoReflectionMethodBuilder *mb = fb->get_method;
535         guint32 idx, i;
536
537         if (mb && mb->parameters)
538                 nparams = mono_array_length (mb->parameters);
539         buf = p = g_malloc (24 + nparams * 10);
540         *p = 0x08;
541         p++;
542         mono_metadata_encode_value (nparams, p, &p);
543         if (mb) {
544                 encode_type (mb->rtype->type, p, &p);
545                 for (i = 0; i < nparams; ++i) {
546                         MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
547                         encode_type (pt->type, p, &p);
548                 }
549         } else {
550                 *p++ = 1; /* void: a property should probably not be allowed without a getter */
551         }
552         /* store length */
553         mono_metadata_encode_value (p-buf, b, &b);
554         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
555         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
556         g_free (buf);
557         return idx;
558 }
559
560 static void
561 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
562 {
563         MonoDynamicTable *table;
564         guint32 *values;
565         char *name;
566         guint num_methods = 0;
567         guint32 semaidx;
568
569         /* 
570          * we need to set things in the following tables:
571          * PROPERTYMAP (info already filled in _get_type_info ())
572          * PROPERTY    (rows already preallocated in _get_type_info ())
573          * METHOD      (method info already done with the generic method code)
574          * METHODSEMANTICS
575          */
576         table = &assembly->tables [MONO_TABLE_PROPERTY];
577         pb->table_idx = table->next_idx ++;
578         values = table->values + pb->table_idx * MONO_FIELD_SIZE;
579         name = mono_string_to_utf8 (pb->name);
580         values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
581         g_free (name);
582         values [MONO_PROPERTY_FLAGS] = pb->attrs;
583         values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
584
585         /* FIXME: we still don't handle 'other' methods */
586         if (pb->get_method) num_methods ++;
587         if (pb->set_method) num_methods ++;
588
589         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
590         table->rows += num_methods;
591         alloc_table (table, table->rows);
592
593         if (pb->get_method) {
594                 semaidx = table->next_idx ++;
595                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
596                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
597                 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
598                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 1;
599         }
600         if (pb->set_method) {
601                 semaidx = table->next_idx ++;
602                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
603                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
604                 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
605                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 0;
606         }
607 }
608
609 static guint32
610 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
611 {
612         if (image != mono_defaults.corlib)
613                 g_error ("multiple assemblyref not yet supported");
614         /* first row in assemblyref */
615         return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF;
616 }
617
618 static guint32
619 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
620 {
621         MonoDynamicTable *table;
622         guint32 *values;
623         guint32 token;
624         MonoClass *klass;
625
626         if (!assembly->typeref)
627                 assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal);
628         
629         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
630         if (token)
631                 return token;
632         klass = type->data.klass;
633         /*
634          * If it's in the same module:
635          * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS)
636          */
637
638         table = &assembly->tables [MONO_TABLE_TYPEREF];
639         alloc_table (table, table->rows + 1);
640         values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
641         values [MONO_TYPEREF_SCOPE] = resolution_scope_from_image (assembly, klass->image);
642         values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
643         values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
644         token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
645         g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
646         table->next_idx ++;
647         return token;
648 }
649
650 static guint32
651 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method)
652 {
653         MonoDynamicTable *table;
654         guint32 *values;
655         guint32 token, pclass;
656         guint32 parent;
657
658         /*
659          * FIXME: we need to cache the token.
660          */
661         parent = mono_image_typedef_or_ref (assembly, &method->klass->byval_arg);
662         switch (parent & TYPEDEFORREF_MASK) {
663         case TYPEDEFORREF_TYPEREF:
664                 pclass = MEMBERREF_PARENT_TYPEREF;
665                 break;
666         case TYPEDEFORREF_TYPESPEC:
667                 pclass = MEMBERREF_PARENT_TYPESPEC;
668                 break;
669         case TYPEDEFORREF_TYPEDEF:
670                 /* should never get here */
671         default:
672                 g_error ("unknow typeref or def token");
673         }
674         /* extract the index */
675         parent >>= TYPEDEFORREF_BITS;
676
677         table = &assembly->tables [MONO_TABLE_MEMBERREF];
678         alloc_table (table, table->rows + 1);
679         values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
680         values [MONO_MEMBERREF_CLASS] = pclass | (parent << MEMBERREF_PARENT_BITS);
681         values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, method->name);
682         values [MONO_MEMBERREF_SIGNATURE] = method_encode_signature (assembly, method->signature);
683         token = MONO_TOKEN_MEMBER_REF | table->next_idx;
684         table->next_idx ++;
685
686         return token;
687 }
688
689 static void
690 mono_image_get_type_info (MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
691 {
692         MonoDynamicTable *table;
693         guint *values;
694         int i;
695         char *n;
696
697         table = &assembly->tables [MONO_TABLE_TYPEDEF];
698         tb->table_idx = table->next_idx ++;
699         values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
700         values [MONO_TYPEDEF_FLAGS] = tb->attrs;
701         values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
702         n = mono_string_to_utf8 (tb->name);
703         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
704         g_free (n);
705         n = mono_string_to_utf8 (tb->nspace);
706         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
707         g_free (n);
708         values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
709         values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
710
711         /*
712          * FIXME: constructors and methods need to be output in the same order
713          * as they are defined (according to table_idx).
714          */
715
716         /* handle constructors */
717         if (tb->ctors) {
718                 table = &assembly->tables [MONO_TABLE_METHOD];
719                 table->rows += mono_array_length (tb->ctors);
720                 alloc_table (table, table->rows);
721                 for (i = 0; i < mono_array_length (tb->ctors); ++i)
722                         mono_image_get_ctor_info (
723                                 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
724         }
725
726         /* handle methods */
727         if (tb->methods) {
728                 table = &assembly->tables [MONO_TABLE_METHOD];
729                 table->rows += mono_array_length (tb->methods);
730                 alloc_table (table, table->rows);
731                 for (i = 0; i < mono_array_length (tb->methods); ++i)
732                         mono_image_get_method_info (
733                                 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
734         }
735
736         /* handle fields */
737         if (tb->fields) {
738                 table = &assembly->tables [MONO_TABLE_FIELD];
739                 table->rows += mono_array_length (tb->fields);
740                 alloc_table (table, table->rows);
741                 for (i = 0; i < mono_array_length (tb->fields); ++i)
742                         mono_image_get_field_info (
743                                 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
744         }
745
746         /* Do the same with properties etc.. */
747         if (tb->properties && mono_array_length (tb->properties)) {
748                 table = &assembly->tables [MONO_TABLE_PROPERTY];
749                 table->rows += mono_array_length (tb->properties);
750                 alloc_table (table, table->rows);
751                 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
752                 table->rows ++;
753                 alloc_table (table, table->rows);
754                 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
755                 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
756                 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
757                 for (i = 0; i < mono_array_length (tb->properties); ++i)
758                         mono_image_get_property_info (
759                                 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
760         }
761 }
762
763 static void
764 mono_image_fill_module_table (MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
765 {
766         MonoDynamicTable *table;
767         int i;
768         char *name;
769
770         table = &assembly->tables [MONO_TABLE_MODULE];
771         mb->table_idx = table->next_idx ++;
772         name = mono_string_to_utf8 (mb->module.name);
773         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
774         g_free (name);
775         /* need to set mvid? */
776
777         /*
778          * fill-in info in other tables as well.
779          */
780         table = &assembly->tables [MONO_TABLE_TYPEDEF];
781         table->rows += mono_array_length (mb->types);
782         alloc_table (table, table->rows);
783         for (i = 0; i < mono_array_length (mb->types); ++i)
784                 mono_image_get_type_info (mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
785 }
786
787 #define align_pointer(base,p)\
788         do {\
789                 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
790                 if (__diff & 3)\
791                         (p) += 4 - (__diff & 3);\
792         } while (0)
793
794 static void
795 build_compressed_metadata (MonoDynamicAssembly *assembly)
796 {
797         int i;
798         guint64 valid_mask = 0;
799         guint32 heapt_size = 0;
800         guint32 meta_size = 256; /* allow for header and other stuff */
801         guint32 table_offset;
802         guint32 ntables = 0;
803         guint64 *int64val;
804         guint32 *int32val;
805         guint16 *int16val;
806         MonoImage *meta;
807         unsigned char *p;
808         char *version = "mono" VERSION;
809         
810         /* Compute table sizes */
811         meta = assembly->assembly.image = g_new0 (MonoImage, 1);
812         
813         /* Setup the info used by compute_sizes () */
814         meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
815         meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
816         meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
817
818         meta_size += assembly->blob.index;
819         meta_size += assembly->guid.index;
820         meta_size += assembly->sheap.index;
821         meta_size += assembly->us.index;
822
823         for (i=0; i < 64; ++i)
824                 meta->tables [i].rows = assembly->tables [i].rows;
825         
826         for (i = 0; i < 64; i++){
827                 if (meta->tables [i].rows == 0)
828                         continue;
829                 valid_mask |= (guint64)1 << i;
830                 ntables ++;
831                 meta->tables [i].row_size = mono_metadata_compute_size (
832                         meta, i, &meta->tables [i].size_bitfield);
833                 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
834         }
835         heapt_size += 24; /* #~ header size */
836         heapt_size += ntables * 4;
837         meta_size += heapt_size;
838         meta->raw_metadata = g_malloc0 (meta_size);
839         p = meta->raw_metadata;
840         /* the metadata signature */
841         *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
842         /* version numbers and 4 bytes reserved */
843         int16val = (guint16*)p;
844         *int16val++ = 1;
845         *int16val = 1;
846         p += 8;
847         /* version string */
848         int32val = (guint32*)p;
849         *int32val = strlen (version);
850         p += 4;
851         memcpy (p, version, *int32val);
852         p += *int32val;
853         align_pointer (meta->raw_metadata, p);
854         int16val = (guint16*)p;
855         *int16val++ = 0; /* flags must be 0 */
856         *int16val = 5; /* number of streams */
857         p += 4;
858
859         /*
860          * write the stream info.
861          */
862         table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
863         
864         int32val = (guint32*)p;
865         *int32val++ = assembly->tstream.offset = table_offset;
866         *int32val = heapt_size;
867         table_offset += *int32val;
868         p += 8;
869         strcpy (p, "#~");
870         p += 3;
871         align_pointer (meta->raw_metadata, p);
872
873         int32val = (guint32*)p;
874         *int32val++ = assembly->sheap.offset = table_offset;
875         *int32val = assembly->sheap.index;
876         table_offset += *int32val;
877         p += 8;
878         strcpy (p, "#Strings");
879         p += 9;
880         align_pointer (meta->raw_metadata, p);
881
882         int32val = (guint32*)p;
883         *int32val++ = assembly->us.offset = table_offset;
884         *int32val = assembly->us.index;
885         table_offset += *int32val;
886         p += 8;
887         strcpy (p, "#US");
888         p += 4;
889         align_pointer (meta->raw_metadata, p);
890
891         int32val = (guint32*)p;
892         *int32val++ = assembly->blob.offset = table_offset;
893         *int32val = assembly->blob.index;
894         table_offset += *int32val;
895         p += 8;
896         strcpy (p, "#Blob");
897         p += 6;
898         align_pointer (meta->raw_metadata, p);
899
900         int32val = (guint32*)p;
901         *int32val++ = assembly->guid.offset = table_offset;
902         *int32val = assembly->guid.index;
903         table_offset += *int32val;
904         p += 8;
905         strcpy (p, "#GUID");
906         p += 6;
907         align_pointer (meta->raw_metadata, p);
908
909         /* 
910          * now copy the data, the table stream header and contents goes first.
911          */
912         g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
913         p = meta->raw_metadata + assembly->tstream.offset;
914         int32val = (guint32*)p;
915         *int32val = 0; /* reserved */
916         p += 4;
917         *p++ = 1; /* version */
918         *p++ = 0;
919         if (meta->idx_string_wide)
920                 *p |= 0x01;
921         if (meta->idx_guid_wide)
922                 *p |= 0x02;
923         if (meta->idx_blob_wide)
924                 *p |= 0x04;
925         ++p;
926         *p++ = 0; /* reserved */
927         int64val = (guint64*)p;
928         *int64val++ = valid_mask;
929         *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now  */
930         p += 16;
931         int32val = (guint32*)p;
932         for (i = 0; i < 64; i++){
933                 if (meta->tables [i].rows == 0)
934                         continue;
935                 *int32val++ = meta->tables [i].rows;
936         }
937         p = (unsigned char*)int32val;
938         /* compress the tables */
939         for (i = 0; i < 64; i++){
940                 int row, col;
941                 guint32 *values;
942                 guint32 bitfield = meta->tables [i].size_bitfield;
943                 if (!meta->tables [i].rows)
944                         continue;
945                 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
946                         g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
947                 meta->tables [i].base = p;
948                 for (row = 1; row <= meta->tables [i].rows; ++row) {
949                         values = assembly->tables [i].values + row * assembly->tables [i].columns;
950                         for (col = 0; col < assembly->tables [i].columns; ++col) {
951                                 switch (mono_metadata_table_size (bitfield, col)) {
952                                 case 1:
953                                         *p++ = values [col];
954                                         break;
955                                 case 2:
956                                         int16val = (guint16*)p;
957                                         *int16val = values [col];
958                                         p += 2;
959                                         break;
960                                 case 4:
961                                         int32val = (guint32*)p;
962                                         *int32val = values [col];
963                                         p += 4;
964                                         break;
965                                 default:
966                                         g_assert_not_reached ();
967                                 }
968                         }
969                 }
970                 g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
971         }
972         
973         g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
974         memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
975         memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
976         memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
977         memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
978
979         assembly->meta_size = assembly->guid.offset + assembly->guid.index;
980 }
981
982 static void
983 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
984 {
985         MonoDynamicTable *table;
986         MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
987         guint32 len;
988         guint32 *values;
989         char *name;
990         int i;
991         
992         assembly->text_rva =  0x00002000;
993
994         table = &assembly->tables [MONO_TABLE_ASSEMBLY];
995         alloc_table (table, 1);
996         values = table->values + MONO_ASSEMBLY_SIZE;
997         values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
998         name = mono_string_to_utf8 (assemblyb->name);
999         values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
1000         g_free (name);
1001         values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
1002         values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
1003         values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1004         values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1005         values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1006         values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1007
1008         assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
1009         assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
1010
1011         len = mono_array_length (assemblyb->modules);
1012         table = &assembly->tables [MONO_TABLE_MODULE];
1013         alloc_table (table, len);
1014         for (i = 0; i < len; ++i)
1015                 mono_image_fill_module_table (mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
1016
1017         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1018         /* 
1019          * table->rows is already set above and in mono_image_fill_module_table.
1020          */
1021         alloc_table (table, table->rows);
1022         /*
1023          * Set the first entry.
1024          */
1025         values = table->values + table->columns;
1026         values [MONO_TYPEDEF_FLAGS] = 0;
1027         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
1028         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
1029         values [MONO_TYPEDEF_EXTENDS] = 0;
1030         values [MONO_TYPEDEF_FIELD_LIST] = 1;
1031         values [MONO_TYPEDEF_METHOD_LIST] = 1;
1032
1033         /* later include all the assemblies referenced */
1034         table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
1035         alloc_table (table, 1);
1036         values = table->values + table->columns;
1037         values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib");
1038
1039         build_compressed_metadata (assembly);
1040 }
1041
1042 guint32
1043 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
1044 {
1045         guint32 index;
1046         char buf [16];
1047         char *b = buf;
1048         
1049         if (!assembly->dynamic_assembly)
1050                 mono_image_basic_init (assembly);
1051         mono_metadata_encode_value (str->length, b, &b);
1052         index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
1053         /* FIXME: ENOENDIAN */
1054         mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2);
1055         return index;
1056 }
1057
1058 /*
1059  * Get a token to insert in the IL code stream for the given MemberInfo.
1060  * obj can be:
1061  *      ConstructorBuilder
1062  *      MethodBuilder
1063  *      FieldBuilder
1064  *      MonoCMethod
1065  *      MonoMethod
1066  *      MonoField
1067  */
1068 guint32
1069 mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj)
1070 {
1071         MonoClass *klass = obj->klass;
1072         guint32 token;
1073
1074         mono_image_basic_init (assembly);
1075
1076         if (strcmp (klass->name, "MethodBuilder") == 0) {
1077                 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
1078                 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
1079                 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
1080                 return token;
1081         }
1082         if (strcmp (klass->name, "FieldBuilder") == 0) {
1083                 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
1084                 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
1085         }
1086         if (strcmp (klass->name, "MonoCMethod") == 0) {
1087                 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
1088                 token = mono_image_get_methodref_token (assembly->dynamic_assembly, m->method);
1089                 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
1090                 return token;
1091         }
1092         g_print ("requested token for %s\n", klass->name);
1093         return 0;
1094 }
1095
1096 void
1097 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
1098 {
1099         MonoDynamicAssembly *assembly;
1100         int i;
1101         
1102         if (assemblyb->dynamic_assembly)
1103                 return;
1104
1105         assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
1106
1107         string_heap_init (&assembly->sheap);
1108         mono_image_add_stream_data (&assembly->us, "", 1);
1109         mono_image_add_stream_data (&assembly->blob, "", 1);
1110
1111         for (i=0; i < 64; ++i) {
1112                 assembly->tables [i].next_idx = 1;
1113                 assembly->tables [i].columns = table_sizes [i];
1114         }
1115         
1116 }
1117
1118 int
1119 mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize)
1120 {
1121         MonoMSDOSHeader *msdos;
1122         MonoDotNetHeader *header;
1123         MonoSectionTable *section;
1124         MonoCLIHeader *cli_header;
1125         guint32 header_size =  TEXT_OFFSET + CLI_H_SIZE;
1126         MonoDynamicAssembly *assembly;
1127
1128         static const unsigned char msheader[] = {
1129                 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,  0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1130                 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1132                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
1133                 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,  0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
1134                 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,  0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
1135                 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,  0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
1136                 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1137         };
1138
1139         if (maxsize < header_size)
1140                 return -1;
1141
1142         mono_image_basic_init (assemblyb);
1143         assembly = assemblyb->dynamic_assembly;
1144
1145         mono_image_build_metadata (assemblyb);
1146
1147         memset (buffer, 0, header_size);
1148         memcpy (buffer, msheader, sizeof (MonoMSDOSHeader));
1149
1150         msdos = (MonoMSDOSHeader *)buffer;
1151         header = (MonoDotNetHeader *)(buffer + sizeof (MonoMSDOSHeader));
1152         section = (MonoSectionTable*) (buffer + sizeof (MonoMSDOSHeader) + sizeof (MonoDotNetHeader));
1153
1154         /* FIXME: ENDIAN problem: byteswap as needed */
1155         msdos->pe_offset = sizeof (MonoMSDOSHeader);
1156
1157         header->pesig [0] = 'P';
1158         header->pesig [1] = 'E';
1159         header->pesig [2] = header->pesig [3] = 0;
1160
1161         header->coff.coff_machine = 0x14c;
1162         header->coff.coff_sections = 1; /* only .text supported now */
1163         header->coff.coff_time = time (NULL);
1164         header->coff.coff_opt_header_size = sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4;
1165         /* it's an exe */
1166         header->coff.coff_attributes = 0x010e;
1167         /* it's a dll */
1168         //header->coff.coff_attributes = 0x210e;
1169         header->pe.pe_magic = 0x10B;
1170         header->pe.pe_major = 6;
1171         header->pe.pe_minor = 0;
1172         /* need to set: pe_code_size pe_data_size pe_rva_entry_point pe_rva_code_base pe_rva_data_base */
1173
1174         header->nt.pe_image_base = 0x400000;
1175         header->nt.pe_section_align = 8192;
1176         header->nt.pe_file_alignment = FILE_ALIGN;
1177         header->nt.pe_os_major = 4;
1178         header->nt.pe_os_minor = 0;
1179         header->nt.pe_subsys_major = 4;
1180         /* need to set pe_image_size, pe_header_size */
1181         header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */
1182         header->nt.pe_stack_reserve = 0x00100000;
1183         header->nt.pe_stack_commit = 0x00001000;
1184         header->nt.pe_heap_reserve = 0x00100000;
1185         header->nt.pe_heap_commit = 0x00001000;
1186         header->nt.pe_loader_flags = 1;
1187         header->nt.pe_data_dir_count = 16;
1188
1189 #if 0
1190         /* set: */
1191         header->datadir.pe_import_table
1192         pe_resource_table
1193         pe_reloc_table
1194         pe_iat  
1195 #endif
1196         header->datadir.pe_cli_header.size = CLI_H_SIZE;
1197         header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */
1198
1199         /* Write section tables */
1200         strcpy (section->st_name, ".text");
1201         section->st_virtual_size = 1024; /* FIXME */
1202         section->st_virtual_address = assembly->text_rva;
1203         section->st_raw_data_size = 1024; /* FIXME */
1204         section->st_raw_data_ptr = TEXT_OFFSET;
1205         section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
1206
1207         /* 
1208          * align: build_compressed_metadata () assumes metadata is aligned 
1209          * see below:
1210          * cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1211          */
1212         assembly->code.index += 3;
1213         assembly->code.index &= ~3;
1214
1215         /*
1216          * Write the MonoCLIHeader header 
1217          */
1218         cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET);
1219         cli_header->ch_size = CLI_H_SIZE;
1220         cli_header->ch_runtime_major = 2;
1221         cli_header->ch_flags = CLI_FLAGS_ILONLY;
1222         if (assemblyb->entry_point) 
1223                 cli_header->ch_entry_point = assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF;
1224         else
1225                 cli_header->ch_entry_point = 0;
1226         cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1227         cli_header->ch_metadata.size = assembly->meta_size;
1228         
1229         return header_size;
1230 }
1231
1232 /*
1233  * We need to return always the same object for Type, MethodInfo, FieldInfo etc..
1234  */
1235 static GHashTable *object_cache = NULL;
1236
1237 #define CHECK_OBJECT(t,p)       \
1238         do {    \
1239                 t _obj; \
1240                 if (!object_cache)      \
1241                         object_cache = g_hash_table_new (g_direct_hash, g_direct_equal);        \
1242                 if ((_obj = g_hash_table_lookup (object_cache, (p))))   \
1243                         return _obj;    \
1244         } while (0)
1245
1246 #define CACHE_OBJECT(p,o)       \
1247         do {    \
1248                 g_hash_table_insert (object_cache, p,o);        \
1249         } while (0)
1250         
1251 MonoReflectionAssembly*
1252 mono_assembly_get_object (MonoAssembly *assembly)
1253 {
1254         MonoClass *klass;
1255         MonoReflectionAssembly *res;
1256         
1257         CHECK_OBJECT (MonoReflectionAssembly *, assembly);
1258         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "Assembly");
1259         res = (MonoReflectionAssembly *)mono_object_new (klass);
1260         res->assembly = assembly;
1261         CACHE_OBJECT (assembly, res);
1262         return res;
1263 }
1264
1265 MonoReflectionType*
1266 mono_type_get_object (MonoType *type)
1267 {
1268         MonoReflectionType *res;
1269
1270         CHECK_OBJECT (MonoReflectionType *, type);
1271         res = (MonoReflectionType *)mono_object_new (mono_defaults.monotype_class);
1272         res->type = type;
1273         CACHE_OBJECT (type, res);
1274         return res;
1275 }
1276
1277 MonoReflectionMethod*
1278 mono_method_get_object (MonoMethod *method)
1279 {
1280         /*
1281          * We use the same C representation for methods and constructors, but the type 
1282          * name in C# is different.
1283          */
1284         char *cname;
1285         MonoClass *klass;
1286         MonoReflectionMethod *ret;
1287
1288         CHECK_OBJECT (MonoReflectionMethod *, method);
1289         if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
1290                 cname = "MonoCMethod";
1291         else
1292                 cname = "MonoMethod";
1293         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
1294
1295         ret = (MonoReflectionMethod*)mono_object_new (klass);
1296         ret->method = method;
1297         CACHE_OBJECT (method, ret);
1298         return ret;
1299 }
1300
1301 MonoReflectionField*
1302 mono_field_get_object (MonoClass *klass, MonoClassField *field)
1303 {
1304         MonoReflectionField *res;
1305         MonoClass *oklass;
1306
1307         CHECK_OBJECT (MonoReflectionField *, field);
1308         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
1309         res = (MonoReflectionField *)mono_object_new (oklass);
1310         res->klass = klass;
1311         res->field = field;
1312         CACHE_OBJECT (field, res);
1313         return res;
1314 }
1315
1316 MonoReflectionProperty*
1317 mono_property_get_object (MonoClass *klass, MonoProperty *property)
1318 {
1319         MonoReflectionProperty *res;
1320         MonoClass *oklass;
1321
1322         CHECK_OBJECT (MonoReflectionProperty *, property);
1323         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
1324         res = (MonoReflectionProperty *)mono_object_new (oklass);
1325         res->klass = klass;
1326         res->property = property;
1327         CACHE_OBJECT (property, res);
1328         return res;
1329 }
1330
1331 MonoReflectionParameter**
1332 mono_param_get_objects (MonoMethod *method)
1333 {
1334         MonoReflectionParameter **res;
1335         MonoReflectionMethod *member;
1336         MonoClass *oklass;
1337         char **names;
1338         int i;
1339
1340         if (!method->signature->param_count)
1341                 return NULL;
1342
1343         member = mono_method_get_object (method);
1344         names = g_new (char*, method->signature->param_count);
1345         mono_method_get_param_names (method, names);
1346         
1347         /* Note: the cache is based on the address of the signature into the method
1348          * since we already cache MethodInfos with the method as keys.
1349          */
1350         CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
1351         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
1352         res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
1353         for (i = 0; i < method->signature->param_count; ++i) {
1354                 res [i] = (MonoReflectionParameter *)mono_object_new (oklass);
1355                 res [i]->ClassImpl = mono_type_get_object (method->signature->params [i]);
1356                 res [i]->DefaultValueImpl = NULL; /* FIXME */
1357                 res [i]->MemberImpl = (MonoObject*)member;
1358                 res [i]->NameImpl = mono_string_new (names [i]);
1359                 res [i]->PositionImpl = i + 1;
1360                 res [i]->AttrsImpl = method->signature->params [i]->attrs;
1361         }
1362         g_free (names);
1363         CACHE_OBJECT (&(method->signature), res);
1364         return res;
1365 }
1366