aeafc20277b69b8ecdbdb8d7c6e72d28728915e4
[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, 2002 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 "mono/metadata/appdomain.h"
16 #include "mono/metadata/opcodes.h"
17 #include <stdio.h>
18 #include <glib.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <string.h>
22 #include "image.h"
23 #include "cil-coff.h"
24 #include "rawbuffer.h"
25 #include "mono-endian.h"
26 #include "private.h"
27 #if HAVE_BOEHM_GC
28 #include <gc/gc.h>
29 #endif
30
31 #define TEXT_OFFSET 512
32 #define CLI_H_SIZE 136
33 #define FILE_ALIGN 512
34 #define VIRT_ALIGN 8192
35 #define START_TEXT_RVA  0x00002000
36
37 typedef struct {
38         MonoReflectionILGen *ilgen;
39         MonoReflectionType *rtype;
40         MonoArray *parameters;
41         MonoArray *pinfo;
42         guint32 attrs;
43         guint32 iattrs;
44         guint32 call_conv;
45         guint32 *table_idx; /* note: it's a pointer */
46         MonoArray *code;
47         MonoObject *type;
48         MonoString *name;
49         MonoBoolean init_locals;
50 } ReflectionMethodBuilder;
51
52 const unsigned char table_sizes [64] = {
53         MONO_MODULE_SIZE,
54         MONO_TYPEREF_SIZE,
55         MONO_TYPEDEF_SIZE,
56         0,
57         MONO_FIELD_SIZE,
58         0,
59         MONO_METHOD_SIZE,
60         0,
61         MONO_PARAM_SIZE,
62         MONO_INTERFACEIMPL_SIZE,
63         MONO_MEMBERREF_SIZE,    /* 0x0A */
64         MONO_CONSTANT_SIZE,
65         MONO_CUSTOM_ATTR_SIZE,
66         MONO_FIELD_MARSHAL_SIZE,
67         MONO_DECL_SECURITY_SIZE,
68         MONO_CLASS_LAYOUT_SIZE,
69         MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
70         MONO_STAND_ALONE_SIGNATURE_SIZE,
71         MONO_EVENT_MAP_SIZE,
72         0,
73         MONO_EVENT_SIZE,
74         MONO_PROPERTY_MAP_SIZE,
75         0,
76         MONO_PROPERTY_SIZE,
77         MONO_METHOD_SEMA_SIZE,
78         MONO_MTHODIMPL_SIZE,
79         MONO_MODULEREF_SIZE,    /* 0x1A */
80         MONO_TYPESPEC_SIZE,
81         MONO_IMPLMAP_SIZE,      
82         MONO_FIELD_RVA_SIZE,
83         0,
84         0,
85         MONO_ASSEMBLY_SIZE,     /* 0x20 */
86         MONO_ASSEMBLY_PROCESSOR_SIZE,
87         MONO_ASSEMBLYOS_SIZE,
88         MONO_ASSEMBLYREF_SIZE,
89         MONO_ASSEMBLYREFPROC_SIZE,
90         MONO_ASSEMBLYREFOS_SIZE,
91         MONO_FILE_SIZE,
92         MONO_EXP_TYPE_SIZE,
93         MONO_MANIFEST_SIZE,
94         MONO_NESTED_CLASS_SIZE,
95         0       /* 0x2A */
96 };
97
98 static guint32 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type);
99 static guint32 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method);
100 static guint32 encode_marshal_blob (MonoDynamicAssembly *assembly, MonoReflectionMarshal *minfo);
101
102 static void
103 alloc_table (MonoDynamicTable *table, guint nrows)
104 {
105         table->rows = nrows;
106         g_assert (table->columns);
107         table->values = g_realloc (table->values, (1 + table->rows) * table->columns * sizeof (guint32));
108 }
109
110 static guint32
111 string_heap_insert (MonoDynamicStream *sh, const char *str)
112 {
113         guint32 idx;
114         guint32 len;
115         gpointer oldkey, oldval;
116
117         if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
118                 return GPOINTER_TO_UINT (oldval);
119
120         len = strlen (str) + 1;
121         idx = sh->index;
122         if (idx + len > sh->alloc_size) {
123                 sh->alloc_size += len + 4096;
124                 sh->data = g_realloc (sh->data, sh->alloc_size);
125         }
126         /*
127          * We strdup the string even if we already copy them in sh->data
128          * so that the string pointers in the hash remain valid even if
129          * we need to realloc sh->data. We may want to avoid that later.
130          */
131         g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
132         memcpy (sh->data + idx, str, len);
133         sh->index += len;
134         return idx;
135 }
136
137 static void
138 string_heap_init (MonoDynamicStream *sh)
139 {
140         sh->index = 0;
141         sh->alloc_size = 4096;
142         sh->data = g_malloc (4096);
143         sh->hash = g_hash_table_new (g_str_hash, g_str_equal);
144         string_heap_insert (sh, "");
145 }
146
147 #if 0 /* never used */
148 static void
149 string_heap_free (MonoDynamicStream *sh)
150 {
151         g_free (sh->data);
152         g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL);
153         g_hash_table_destroy (sh->hash);
154 }
155 #endif
156
157 static guint32
158 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
159 {
160         guint32 idx;
161         if (stream->alloc_size < stream->index + len) {
162                 stream->alloc_size += len + 4096;
163                 stream->data = g_realloc (stream->data, stream->alloc_size);
164         }
165         memcpy (stream->data + stream->index, data, len);
166         idx = stream->index;
167         stream->index += len;
168         /* 
169          * align index? Not without adding an additional param that controls it since
170          * we may store a blob value in pieces.
171          */
172         return idx;
173 }
174
175 static guint32
176 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
177 {
178         guint32 idx;
179         if (stream->alloc_size < stream->index + len) {
180                 stream->alloc_size += len + 4096;
181                 stream->data = g_realloc (stream->data, stream->alloc_size);
182         }
183         memset (stream->data + stream->index, 0, len);
184         idx = stream->index;
185         stream->index += len;
186         return idx;
187 }
188
189 static void
190 stream_data_align (MonoDynamicStream *stream)
191 {
192         char buf [4] = {0};
193         guint32 count = stream->index % 4;
194
195         /* we assume the stream data will be aligned */
196         if (count)
197                 mono_image_add_stream_data (stream, buf, 4 - count);
198 }
199
200 static void
201 encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endbuf)
202 {
203         if (!type) {
204                 g_assert_not_reached ();
205                 return;
206         }
207                 
208         if (type->byref)
209                 mono_metadata_encode_value (MONO_TYPE_BYREF, p, &p);
210
211         switch (type->type){
212         case MONO_TYPE_VOID:
213         case MONO_TYPE_BOOLEAN:
214         case MONO_TYPE_CHAR:
215         case MONO_TYPE_I1:
216         case MONO_TYPE_U1:
217         case MONO_TYPE_I2:
218         case MONO_TYPE_U2:
219         case MONO_TYPE_I4:
220         case MONO_TYPE_U4:
221         case MONO_TYPE_I8:
222         case MONO_TYPE_U8:
223         case MONO_TYPE_R4:
224         case MONO_TYPE_R8:
225         case MONO_TYPE_I:
226         case MONO_TYPE_U:
227         case MONO_TYPE_STRING:
228         case MONO_TYPE_OBJECT:
229         case MONO_TYPE_TYPEDBYREF:
230                 mono_metadata_encode_value (type->type, p, &p);
231                 break;
232         case MONO_TYPE_PTR:
233         case MONO_TYPE_SZARRAY:
234                 mono_metadata_encode_value (type->type, p, &p);
235                 encode_type (assembly, type->data.type, p, &p);
236                 break;
237         case MONO_TYPE_VALUETYPE:
238         case MONO_TYPE_CLASS:
239                 mono_metadata_encode_value (type->type, p, &p);
240                 mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, type), p, &p);
241                 break;
242 #if 0
243         case MONO_TYPE_VALUETYPE:
244         case MONO_TYPE_CLASS: {
245                 MonoClass *k = mono_class_from_mono_type (type);
246                 mono_metadata_encode_value (type->type, p, &p);
247                 /* ensure only non-byref gets passed to mono_image_typedef_or_ref() */
248                 mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, &k->byval_arg), p, &p);
249                 break;
250         }
251 #endif
252         case MONO_TYPE_ARRAY:
253                 mono_metadata_encode_value (type->type, p, &p);
254                 encode_type (assembly, type->data.array->type, p, &p);
255                 mono_metadata_encode_value (type->data.array->rank, p, &p);
256                 mono_metadata_encode_value (0, p, &p); /* FIXME: set to 0 for now */
257                 mono_metadata_encode_value (0, p, &p);
258                 break;
259         default:
260                 g_error ("need to encode type %x", type->type);
261         }
262         *endbuf = p;
263 }
264
265 static void
266 encode_reflection_type (MonoDynamicAssembly *assembly, MonoReflectionType *type, char *p, char **endbuf)
267 {
268         if (!type) {
269                 mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf);
270                 return;
271         }
272         if (type->type) {
273                 encode_type (assembly, type->type, p, endbuf);
274                 return;
275         }
276
277         g_assert_not_reached ();
278
279 }
280
281 static guint32
282 method_encode_signature (MonoDynamicAssembly *assembly, MonoMethodSignature *sig)
283 {
284         char *buf;
285         char *p;
286         int i;
287         guint32 nparams =  sig->param_count;
288         guint32 size = 10 + nparams * 10;
289         guint32 idx;
290         char blob_size [6];
291         char *b = blob_size;
292         
293         p = buf = g_malloc (size);
294         /*
295          * FIXME: vararg, explicit_this, differenc call_conv values...
296          */
297         *p = sig->call_convention;
298         if (sig->hasthis)
299                 *p |= 0x20; /* hasthis */
300         p++;
301         mono_metadata_encode_value (nparams, p, &p);
302         encode_type (assembly, sig->ret, p, &p);
303         for (i = 0; i < nparams; ++i)
304                 encode_type (assembly, sig->params [i], p, &p);
305         /* store length */
306         g_assert (p - buf < size);
307         mono_metadata_encode_value (p-buf, b, &b);
308         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
309         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
310         g_free (buf);
311         return idx;
312 }
313
314 static guint32
315 method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
316 {
317         /*
318          * FIXME: reuse code from method_encode_signature().
319          */
320         char *buf;
321         char *p;
322         int i;
323         guint32 nparams =  mb->parameters ? mono_array_length (mb->parameters): 0;
324         guint32 size = 10 + nparams * 10;
325         guint32 idx;
326         char blob_size [6];
327         char *b = blob_size;
328         
329         p = buf = g_malloc (size);
330         /* LAMESPEC: all the call conv spec is foobared */
331         *p = mb->call_conv & 0x60; /* has-this, explicit-this */
332         if (mb->call_conv & 2)
333                 *p |= 0x5; /* vararg */
334         if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
335                 *p |= 0x20; /* hasthis */
336         p++;
337         mono_metadata_encode_value (nparams, p, &p);
338         encode_reflection_type (assembly, mb->rtype, p, &p);
339         for (i = 0; i < nparams; ++i) {
340                 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
341                 encode_reflection_type (assembly, pt, p, &p);
342         }
343         /* store length */
344         g_assert (p - buf < size);
345         mono_metadata_encode_value (p-buf, b, &b);
346         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
347         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
348         g_free (buf);
349         return idx;
350 }
351
352 static guint32
353 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
354 {
355         MonoDynamicTable *table;
356         guint32 *values;
357         char *p;
358         guint32 idx, sig_idx, size;
359         guint nl = mono_array_length (ilgen->locals);
360         char *buf;
361         char blob_size [6];
362         char *b = blob_size;
363         int i;
364
365         size = 10 + nl * 10;
366         p = buf = g_malloc (size);
367         table = &assembly->tables [MONO_TABLE_STANDALONESIG];
368         idx = table->next_idx ++;
369         table->rows ++;
370         alloc_table (table, table->rows);
371         values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
372
373         mono_metadata_encode_value (0x07, p, &p);
374         mono_metadata_encode_value (nl, p, &p);
375         for (i = 0; i < nl; ++i) {
376                 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
377                 encode_reflection_type (assembly, lb->type, p, &p);
378         }
379         g_assert (p - buf < size);
380         mono_metadata_encode_value (p-buf, b, &b);
381         sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
382         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
383         g_free (buf);
384
385         values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
386
387         return idx;
388 }
389
390 static guint32
391 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
392 {
393         char flags = 0;
394         guint32 idx;
395         guint32 code_size;
396         gint32 max_stack, i;
397         gint32 num_locals = 0;
398         gint32 num_exception = 0;
399         gint maybe_small;
400         guint32 fat_flags;
401         char fat_header [12];
402         guint32 *intp;
403         guint16 *shortp;
404         guint32 local_sig = 0;
405         guint32 header_size = 12;
406         MonoArray *code;
407
408         if ((mb->attrs & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
409                         (mb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
410                         (mb->iattrs & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
411                         (mb->attrs & METHOD_ATTRIBUTE_ABSTRACT))
412                 return 0;
413
414         /*if (mb->name)
415                 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
416         if (mb->ilgen) {
417                 code = mb->ilgen->code;
418                 code_size = mb->ilgen->code_len;
419                 max_stack = mb->ilgen->max_stack;
420                 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
421                 if (mb->ilgen->ex_handlers) {
422                         MonoILExceptionInfo *ex_info;
423                         for (i = 0; i < mono_array_length (mb->ilgen->ex_handlers); ++i) {
424                                 ex_info = (MonoILExceptionInfo*)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
425                                 if (ex_info->handlers)
426                                         num_exception += mono_array_length (ex_info->handlers);
427                                 else
428                                         num_exception++;
429                         }
430                 }
431         } else {
432                 code = mb->code;
433                 code_size = mono_array_length (code);
434                 max_stack = 8; /* we probably need to run a verifier on the code... */
435         }
436
437         /* check for exceptions, maxstack, locals */
438         maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
439         if (maybe_small) {
440                 if (code_size < 64 && !(code_size & 1)) {
441                         flags = (code_size << 2) | 0x2;
442                 } else if (code_size < 32 && (code_size & 1)) {
443                         flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
444                 } else {
445                         goto fat_header;
446                 }
447                 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
448                 /* add to the fixup todo list */
449                 if (mb->ilgen && mb->ilgen->num_token_fixups)
450                         mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
451                 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
452                 return assembly->text_rva + idx;
453         } 
454 fat_header:
455         if (num_locals)
456                 local_sig = MONO_TOKEN_SIGNATURE | encode_locals (assembly, mb->ilgen);
457         /* 
458          * FIXME: need to set also the header size in fat_flags.
459          * (and more sects and init locals flags)
460          */
461         fat_flags =  0x03;
462         if (num_exception)
463                 fat_flags |= METHOD_HEADER_MORE_SECTS;
464         if (mb->init_locals)
465                 fat_flags |= METHOD_HEADER_INIT_LOCALS;
466         fat_header [0] = fat_flags;
467         fat_header [1] = (header_size / 4 ) << 4;
468         shortp = (guint16*)(fat_header + 2);
469         *shortp = GUINT16_TO_LE (max_stack);
470         intp = (guint32*)(fat_header + 4);
471         *intp = GUINT32_TO_LE (code_size);
472         intp = (guint32*)(fat_header + 8);
473         *intp = GUINT32_TO_LE (local_sig);
474         idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
475         /* add to the fixup todo list */
476         if (mb->ilgen && mb->ilgen->num_token_fixups)
477                 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
478         
479         mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
480         if (num_exception) {
481                 unsigned char sheader [4];
482                 MonoExceptionClause clause;
483                 MonoILExceptionInfo * ex_info;
484                 MonoILExceptionBlock * ex_block;
485                 int j;
486
487                 stream_data_align (&assembly->code);
488                 /* always use fat format for now */
489                 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
490                 num_exception *= sizeof (MonoExceptionClause);
491                 sheader [1] = num_exception & 0xff;
492                 sheader [2] = (num_exception >> 8) & 0xff;
493                 sheader [3] = (num_exception >> 16) & 0xff;
494                 mono_image_add_stream_data (&assembly->code, sheader, 4);
495                 /* fat header, so we are already aligned */
496                 /* reverse order */
497                 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
498                         ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
499                         if (ex_info->handlers) {
500                                 int finally_start = ex_info->start + ex_info->len;
501                                 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
502                                         ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
503                                         clause.flags = GUINT32_TO_LE (ex_block->type);
504                                         clause.try_offset = GUINT32_TO_LE (ex_info->start);
505                                         /* need fault, too, probably */
506                                         if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
507                                                 clause.try_len = GUINT32_TO_LE (finally_start - ex_info->start);
508                                         else
509                                                 clause.try_len = GUINT32_TO_LE (ex_info->len);
510                                         clause.handler_offset = GUINT32_TO_LE (ex_block->start);
511                                         clause.handler_len = GUINT32_TO_LE (ex_block->len);
512                                         finally_start = clause.handler_offset + clause.handler_len;
513                                         clause.token_or_filter = ex_block->extype ? mono_metadata_token_from_dor (
514                                                         mono_image_typedef_or_ref (assembly, ex_block->extype->type)): 0;
515                                         clause.token_or_filter = GUINT32_TO_LE (clause.token_or_filter);
516                                         /*g_print ("out clause %d: from %d len=%d, handler at %d, %d, finally_start=%d, ex_info->start=%d, ex_info->len=%d, ex_block->type=%d, j=%d, i=%d\n", 
517                                                         clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len, finally_start, ex_info->start, ex_info->len, ex_block->type, j, i);*/
518                                         mono_image_add_stream_data (&assembly->code, (char*)&clause, sizeof (clause));
519                                 }
520                         } else {
521                                 g_error ("No clauses for ex info block %d", i);
522                         }
523                 }
524         }
525         return assembly->text_rva + idx;
526 }
527
528 static guint32
529 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 token)
530 {
531         int i;
532         MonoDynamicTable *table;
533         guint32 *values;
534         
535         table = &assembly->tables [table_idx];
536
537         g_assert (col < table->columns);
538
539         values = table->values + table->columns;
540         for (i = 1; i <= table->rows; ++i) {
541                 if (values [col] == token)
542                         return i;
543         }
544         return 0;
545 }
546
547 /*
548  * idx is the table index of the object
549  * type is one of CUSTOM_ATTR_*
550  */
551 static void
552 mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 idx, guint32 type, MonoArray *cattrs)
553 {
554         MonoDynamicTable *table;
555         MonoReflectionCustomAttr *cattr;
556         guint32 *values;
557         guint32 count, i, token;
558         char blob_size [6];
559         char *p = blob_size;
560         
561         /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
562         if (!cattrs)
563                 return;
564         count = mono_array_length (cattrs);
565         table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
566         table->rows += count;
567         alloc_table (table, table->rows);
568         values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
569         idx <<= CUSTOM_ATTR_BITS;
570         idx |= type;
571         for (i = 0; i < count; ++i) {
572                 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
573                 values [MONO_CUSTOM_ATTR_PARENT] = idx;
574                 token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor);
575                 type = mono_metadata_token_index (token);
576                 type <<= CUSTOM_ATTR_TYPE_BITS;
577                 switch (mono_metadata_token_table (token)) {
578                 case MONO_TABLE_METHOD:
579                         type |= CUSTOM_ATTR_TYPE_METHODDEF;
580                         break;
581                 case MONO_TABLE_MEMBERREF:
582                         type |= CUSTOM_ATTR_TYPE_MEMBERREF;
583                         break;
584                 default:
585                         g_error ("got wrong token in custom attr");
586                 }
587                 values [MONO_CUSTOM_ATTR_TYPE] = type;
588                 p = blob_size;
589                 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
590                 values [MONO_CUSTOM_ATTR_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, p - blob_size);
591                 mono_image_add_stream_data (&assembly->blob,
592                         mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
593                 values += MONO_CUSTOM_ATTR_SIZE;
594                 ++table->next_idx;
595         }
596 }
597
598 /*
599  * Fill in the MethodDef and ParamDef tables for a method.
600  * This is used for both normal methods and constructors.
601  */
602 static void
603 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
604 {
605         MonoDynamicTable *table;
606         guint32 *values;
607         char *name;
608         guint i, count;
609
610         /* room in this table is already allocated */
611         table = &assembly->tables [MONO_TABLE_METHOD];
612         *mb->table_idx = table->next_idx ++;
613         values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
614         if (mb->name) {
615                 name = mono_string_to_utf8 (mb->name);
616                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
617                 g_free (name);
618         } else { /* a constructor */
619                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
620         }
621         values [MONO_METHOD_FLAGS] = mb->attrs;
622         values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
623         values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
624         values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
625         
626         table = &assembly->tables [MONO_TABLE_PARAM];
627         values [MONO_METHOD_PARAMLIST] = table->next_idx;
628
629         if (mb->pinfo) {
630                 MonoDynamicTable *mtable;
631                 guint32 *mvalues;
632                 
633                 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
634                 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
635                 
636                 count = 0;
637                 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
638                         if (mono_array_get (mb->pinfo, gpointer, i))
639                                 count++;
640                 }
641                 table->rows += count;
642                 alloc_table (table, table->rows);
643                 values = table->values + table->next_idx * MONO_PARAM_SIZE;
644                 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
645                         MonoReflectionParamBuilder *pb;
646                         if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
647                                 values [MONO_PARAM_FLAGS] = pb->attrs;
648                                 values [MONO_PARAM_SEQUENCE] = i;
649                                 name = mono_string_to_utf8 (pb->name);
650                                 values [MONO_PARAM_NAME] = string_heap_insert (&assembly->sheap, name);
651                                 g_free (name);
652                                 values += MONO_PARAM_SIZE;
653                                 if (pb->marshal_info) {
654                                         mtable->rows++;
655                                         alloc_table (mtable, mtable->rows);
656                                         mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
657                                         mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << HAS_FIELD_MARSHAL_BITS) | HAS_FIELD_MARSHAL_PARAMDEF;
658                                         mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, pb->marshal_info);
659                                 }
660                                 table->next_idx++;
661                                 mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PARAMDEF, pb->cattrs);
662                         }
663                 }
664         }
665 }
666
667 static void
668 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
669 {
670         MonoDynamicTable *table;
671         guint32 *values;
672         char *name;
673         ReflectionMethodBuilder rmb;
674
675         rmb.ilgen = mb->ilgen;
676         rmb.rtype = mb->rtype;
677         rmb.parameters = mb->parameters;
678         rmb.pinfo = mb->pinfo;
679         rmb.attrs = mb->attrs;
680         rmb.iattrs = mb->iattrs;
681         rmb.call_conv = mb->call_conv;
682         rmb.code = mb->code;
683         rmb.type = mb->type;
684         rmb.name = mb->name;
685         rmb.table_idx = &mb->table_idx;
686         rmb.init_locals = mb->init_locals;
687
688         mono_image_basic_method (&rmb, assembly);
689
690         if (mb->dll) { /* It's a P/Invoke method */
691                 guint32 moduleref;
692                 table = &assembly->tables [MONO_TABLE_IMPLMAP];
693                 table->rows ++;
694                 alloc_table (table, table->rows);
695                 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
696                 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
697                 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
698                 name = mono_string_to_utf8 (mb->dllentry);
699                 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
700                 g_free (name);
701                 name = mono_string_to_utf8 (mb->dll);
702                 moduleref = string_heap_insert (&assembly->sheap, name);
703                 g_free (name);
704                 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
705                         table = &assembly->tables [MONO_TABLE_MODULEREF];
706                         table->rows ++;
707                         alloc_table (table, table->rows);
708                         table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
709                         values [MONO_IMPLMAP_SCOPE] = table->rows;
710                 }
711         }
712         if (mb->override_method) {
713                 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
714                 table = &assembly->tables [MONO_TABLE_METHODIMPL];
715                 table->rows ++;
716                 alloc_table (table, table->rows);
717                 values = table->values + table->rows * MONO_MTHODIMPL_SIZE;
718                 values [MONO_MTHODIMPL_CLASS] = tb->table_idx;
719                 values [MONO_MTHODIMPL_BODY] = METHODDEFORREF_METHODDEF | (mb->table_idx << METHODDEFORREF_BITS);
720                 if (mb->override_method->method)
721                         values [MONO_MTHODIMPL_DECLARATION] = mono_image_get_methodref_token (assembly, mb->override_method->method);
722                 else {
723                         MonoReflectionMethodBuilder *omb = (MonoReflectionMethodBuilder*)mb->override_method;
724                         values [MONO_MTHODIMPL_DECLARATION] = METHODDEFORREF_METHODDEF | (omb->table_idx << METHODDEFORREF_BITS);
725                 }
726         }
727         mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_METHODDEF, mb->cattrs);
728 }
729
730 static void
731 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
732 {
733         ReflectionMethodBuilder rmb;
734
735         rmb.ilgen = mb->ilgen;
736         rmb.rtype = mono_type_get_object (domain, &mono_defaults.void_class->byval_arg);
737         rmb.parameters = mb->parameters;
738         rmb.pinfo = mb->pinfo;
739         rmb.attrs = mb->attrs;
740         rmb.iattrs = mb->iattrs;
741         rmb.call_conv = mb->call_conv;
742         rmb.code = NULL;
743         rmb.type = mb->type;
744         rmb.name = NULL;
745         rmb.table_idx = &mb->table_idx;
746         rmb.init_locals = mb->init_locals;
747
748         mono_image_basic_method (&rmb, assembly);
749         mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_METHODDEF, mb->cattrs);
750
751 }
752
753 static guint32
754 fieldref_encode_signature (MonoDynamicAssembly *assembly, MonoClassField *field)
755 {
756         char blob_size [64];
757         char *b = blob_size;
758         char *p;
759         char* buf;
760         guint32 idx;
761         
762         p = buf = g_malloc (64);
763         
764         mono_metadata_encode_value (0x06, p, &p);
765         /* encode custom attributes before the type */
766         encode_type (assembly, field->type, p, &p);
767         g_assert (p-buf < 64);
768         mono_metadata_encode_value (p-buf, b, &b);
769         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
770         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
771         g_free (buf);
772         return idx;
773 }
774
775 static guint32
776 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
777 {
778         char blob_size [64];
779         char *b = blob_size;
780         char *p;
781         char* buf;
782         guint32 idx;
783         
784         p = buf = g_malloc (64);
785         
786         mono_metadata_encode_value (0x06, p, &p);
787         /* encode custom attributes before the type */
788         encode_reflection_type (assembly, fb->type, p, &p);
789         g_assert (p-buf < 64);
790         mono_metadata_encode_value (p-buf, b, &b);
791         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
792         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
793         g_free (buf);
794         return idx;
795 }
796
797 /*
798  * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
799  * dest may be misaligned.
800  */
801 static void
802 swap_with_size (char *dest, const char* val, int len, int nelem) {
803 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
804         int elem;
805
806         for (elem = 0; elem < nelem; ++elem) {
807                 switch (len) {
808                 case 1:
809                         *dest = *val;
810                         break;
811                 case 2:
812                         dest [0] = val [1];
813                         dest [1] = val [0];
814                         break;
815                 case 4:
816                         dest [0] = val [3];
817                         dest [1] = val [2];
818                         dest [2] = val [1];
819                         dest [3] = val [0];
820                         break;
821                 case 8:
822                         dest [0] = val [7];
823                         dest [1] = val [6];
824                         dest [2] = val [5];
825                         dest [3] = val [4];
826                         dest [4] = val [3];
827                         dest [5] = val [2];
828                         dest [6] = val [1];
829                         dest [7] = val [0];
830                         break;
831                 default:
832                         g_assert_not_reached ();
833                 }
834                 dest += len;
835                 val += len;
836         }
837 #else
838         memcpy (dest, val, len * nelem);
839 #endif
840 }
841
842 static guint32
843 encode_constant (MonoDynamicAssembly *assembly, MonoObject *val, guint32 *ret_type) {
844         char blob_size [64];
845         char *b = blob_size;
846         char *p, *box_val;
847         char* buf;
848         guint32 idx, len;
849         
850         p = buf = g_malloc (64);
851
852         box_val = ((char*)val) + sizeof (MonoObject);
853         *ret_type = val->vtable->klass->byval_arg.type;
854 handle_enum:
855         switch (*ret_type) {
856         case MONO_TYPE_BOOLEAN:
857         case MONO_TYPE_U1:
858         case MONO_TYPE_I1:
859                 len = 1;
860                 break;
861         case MONO_TYPE_CHAR:
862         case MONO_TYPE_U2:
863         case MONO_TYPE_I2:
864                 len = 2;
865                 break;
866         case MONO_TYPE_U4:
867         case MONO_TYPE_I4:
868         case MONO_TYPE_R4:
869                 len = 4;
870                 break;
871         case MONO_TYPE_U8:
872         case MONO_TYPE_I8:
873         case MONO_TYPE_R8:
874                 len = 8;
875                 break;
876         case MONO_TYPE_VALUETYPE:
877                 if (val->vtable->klass->enumtype) {
878                         *ret_type = val->vtable->klass->enum_basetype->type;
879                         goto handle_enum;
880                 } else
881                         g_error ("we can't encode valuetypes");
882         case MONO_TYPE_STRING: {
883                 MonoString *str = (MonoString*)val;
884                 /* there is no signature */
885                 len = str->length * 2;
886                 mono_metadata_encode_value (len, b, &b);
887                 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
888 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
889                 {
890                         char *swapped = g_malloc (2 * mono_string_length (str));
891                         const char *p = (const char*)mono_string_chars (str);
892
893                         swap_with_size (swapped, p, 2, mono_string_length (str));
894                         mono_image_add_stream_data (&assembly->blob, swapped, len);
895                         g_free (swapped);
896                 }
897 #else
898                 mono_image_add_stream_data (&assembly->blob, (const char*)mono_string_chars (str), len);
899 #endif
900
901                 g_free (buf);
902                 return idx;
903         }
904         default:
905                 g_error ("we don't encode constant type 0x%02x yet", *ret_type);
906         }
907
908         /* there is no signature */
909         mono_metadata_encode_value (len, b, &b);
910         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
911 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
912         swap_with_size (blob_size, val, len, 1);
913         mono_image_add_stream_data (&assembly->blob, blob_size, len);
914 #else
915         mono_image_add_stream_data (&assembly->blob, box_val, len);
916 #endif
917
918         g_free (buf);
919         return idx;
920 }
921
922 static guint32
923 encode_marshal_blob (MonoDynamicAssembly *assembly, MonoReflectionMarshal *minfo) {
924         char blob_size [64];
925         char *b = blob_size;
926         char *p, *buf;
927         guint32 idx, len;
928         
929         p = buf = g_malloc (256);
930
931         switch (minfo->type) {
932         /* FIXME: handle ARRAY and other unmanaged types that need extra info */
933         default:
934                 mono_metadata_encode_value (minfo->type, p, &p);
935                 break;
936         }
937         len = p-buf;
938         mono_metadata_encode_value (len, b, &b);
939         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
940         mono_image_add_stream_data (&assembly->blob, buf, len);
941         g_free (buf);
942         return idx;
943 }
944
945 static void
946 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
947 {
948         MonoDynamicTable *table;
949         guint32 *values;
950         char *name;
951
952         /* maybe this fixup should be done in the C# code */
953         if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
954                 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
955         table = &assembly->tables [MONO_TABLE_FIELD];
956         fb->table_idx = table->next_idx ++;
957         values = table->values + fb->table_idx * MONO_FIELD_SIZE;
958         name = mono_string_to_utf8 (fb->name);
959         values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
960         g_free (name);
961         values [MONO_FIELD_FLAGS] = fb->attrs;
962         values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
963
964         if (fb->offset != -1) {
965                 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
966                 table->rows ++;
967                 alloc_table (table, table->rows);
968                 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
969                 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
970                 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
971         }
972         if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
973                 guint32 field_type = 0;
974                 table = &assembly->tables [MONO_TABLE_CONSTANT];
975                 table->rows ++;
976                 alloc_table (table, table->rows);
977                 values = table->values + table->rows * MONO_CONSTANT_SIZE;
978                 values [MONO_CONSTANT_PARENT] = HASCONSTANT_FIEDDEF | (fb->table_idx << HASCONSTANT_BITS);
979                 values [MONO_CONSTANT_VALUE] = encode_constant (assembly, fb->def_value, &field_type);
980                 values [MONO_CONSTANT_TYPE] = field_type;
981                 values [MONO_CONSTANT_PADDING] = 0;
982         }
983         if (fb->rva_data) {
984                 guint32 rva_idx;
985                 table = &assembly->tables [MONO_TABLE_FIELDRVA];
986                 table->rows ++;
987                 alloc_table (table, table->rows);
988                 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
989                 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
990                 /*
991                  * We store it in the code section because it's simpler for now.
992                  */
993                 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
994                 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
995         }
996         if (fb->marshal_info) {
997                 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
998                 table->rows ++;
999                 alloc_table (table, table->rows);
1000                 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
1001                 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << HAS_FIELD_MARSHAL_BITS) | HAS_FIELD_MARSHAL_FIELDSREF;
1002                 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, fb->marshal_info);
1003         }
1004         mono_image_add_cattrs (assembly, fb->table_idx, CUSTOM_ATTR_FIELDDEF, fb->cattrs);
1005 }
1006
1007 static guint32
1008 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
1009 {
1010         char *buf, *p;
1011         char blob_size [6];
1012         char *b = blob_size;
1013         guint32 nparams = 0;
1014         MonoReflectionMethodBuilder *mb = fb->get_method;
1015         guint32 idx, i, size;
1016
1017         if (mb && mb->parameters)
1018                 nparams = mono_array_length (mb->parameters);
1019         size = 24 + nparams * 10;
1020         buf = p = g_malloc (size);
1021         *p = 0x08;
1022         p++;
1023         mono_metadata_encode_value (nparams, p, &p);
1024         if (mb) {
1025                 encode_reflection_type (assembly, mb->rtype, p, &p);
1026                 for (i = 0; i < nparams; ++i) {
1027                         MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
1028                         encode_reflection_type (assembly, pt, p, &p);
1029                 }
1030         } else {
1031                 *p++ = 1; /* void: a property should probably not be allowed without a getter */
1032         }
1033         /* store length */
1034         g_assert (p - buf < size);
1035         mono_metadata_encode_value (p-buf, b, &b);
1036         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1037         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
1038         g_free (buf);
1039         return idx;
1040 }
1041
1042 static void
1043 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
1044 {
1045         MonoDynamicTable *table;
1046         guint32 *values;
1047         char *name;
1048         guint num_methods = 0;
1049         guint32 semaidx;
1050
1051         /* 
1052          * we need to set things in the following tables:
1053          * PROPERTYMAP (info already filled in _get_type_info ())
1054          * PROPERTY    (rows already preallocated in _get_type_info ())
1055          * METHOD      (method info already done with the generic method code)
1056          * METHODSEMANTICS
1057          */
1058         table = &assembly->tables [MONO_TABLE_PROPERTY];
1059         pb->table_idx = table->next_idx ++;
1060         values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
1061         name = mono_string_to_utf8 (pb->name);
1062         values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
1063         g_free (name);
1064         values [MONO_PROPERTY_FLAGS] = pb->attrs;
1065         values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
1066
1067         /* FIXME: we still don't handle 'other' methods */
1068         if (pb->get_method) num_methods ++;
1069         if (pb->set_method) num_methods ++;
1070
1071         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1072         table->rows += num_methods;
1073         alloc_table (table, table->rows);
1074
1075         if (pb->get_method) {
1076                 semaidx = table->next_idx ++;
1077                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1078                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
1079                 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
1080                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
1081         }
1082         if (pb->set_method) {
1083                 semaidx = table->next_idx ++;
1084                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1085                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
1086                 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
1087                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
1088         }
1089         mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PROPERTY, pb->cattrs);
1090 }
1091
1092 static void
1093 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicAssembly *assembly)
1094 {
1095         MonoDynamicTable *table;
1096         guint32 *values;
1097         char *name;
1098         guint num_methods = 0;
1099         guint32 semaidx;
1100
1101         /* 
1102          * we need to set things in the following tables:
1103          * EVENTMAP (info already filled in _get_type_info ())
1104          * EVENT    (rows already preallocated in _get_type_info ())
1105          * METHOD      (method info already done with the generic method code)
1106          * METHODSEMANTICS
1107          */
1108         table = &assembly->tables [MONO_TABLE_EVENT];
1109         eb->table_idx = table->next_idx ++;
1110         values = table->values + eb->table_idx * MONO_EVENT_SIZE;
1111         name = mono_string_to_utf8 (eb->name);
1112         values [MONO_EVENT_NAME] = string_heap_insert (&assembly->sheap, name);
1113         g_free (name);
1114         values [MONO_EVENT_FLAGS] = eb->attrs;
1115         values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, eb->type->type);
1116
1117         /*
1118          * FIXME: we still don't handle 'other' methods 
1119          */
1120         if (eb->add_method) num_methods ++;
1121         if (eb->remove_method) num_methods ++;
1122         if (eb->raise_method) num_methods ++;
1123
1124         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1125         table->rows += num_methods;
1126         alloc_table (table, table->rows);
1127
1128         if (eb->add_method) {
1129                 semaidx = table->next_idx ++;
1130                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1131                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
1132                 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
1133                 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1134         }
1135         if (eb->remove_method) {
1136                 semaidx = table->next_idx ++;
1137                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1138                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
1139                 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
1140                 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1141         }
1142         if (eb->raise_method) {
1143                 semaidx = table->next_idx ++;
1144                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1145                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
1146                 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
1147                 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1148         }
1149         mono_image_add_cattrs (assembly, eb->table_idx, CUSTOM_ATTR_EVENT, eb->cattrs);
1150 }
1151
1152 static guint32
1153 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
1154 {
1155         MonoDynamicTable *table;
1156         guint32 token;
1157         guint32 *values;
1158         guint32 cols [MONO_ASSEMBLY_SIZE];
1159
1160         if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, image))))
1161                 return token;
1162
1163         mono_metadata_decode_row (&image->tables [MONO_TABLE_ASSEMBLY], 0, cols, MONO_ASSEMBLY_SIZE);
1164
1165         table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
1166         token = table->next_idx ++;
1167         table->rows ++;
1168         alloc_table (table, table->rows);
1169         values = table->values + token * MONO_ASSEMBLYREF_SIZE;
1170         if (strcmp ("corlib", image->assembly_name) == 0)
1171                 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "mscorlib");
1172         else
1173                 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, image->assembly_name);
1174         values [MONO_ASSEMBLYREF_MAJOR_VERSION] = cols [MONO_ASSEMBLY_MAJOR_VERSION];
1175         values [MONO_ASSEMBLYREF_MINOR_VERSION] = cols [MONO_ASSEMBLY_MINOR_VERSION];
1176         values [MONO_ASSEMBLYREF_BUILD_NUMBER] = cols [MONO_ASSEMBLY_BUILD_NUMBER];
1177         values [MONO_ASSEMBLYREF_REV_NUMBER] = cols [MONO_ASSEMBLY_REV_NUMBER];
1178         values [MONO_ASSEMBLYREF_FLAGS] = 0;
1179         values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0;
1180         values [MONO_ASSEMBLYREF_CULTURE] = 0;
1181         values [MONO_ASSEMBLYREF_HASH_VALUE] = 0;
1182
1183         token <<= RESOLTION_SCOPE_BITS;
1184         token |= RESOLTION_SCOPE_ASSEMBLYREF;
1185         g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
1186         return token;
1187 }
1188
1189 static guint32
1190 create_typespec (MonoDynamicAssembly *assembly, MonoType *type)
1191 {
1192         MonoDynamicTable *table;
1193         guint32 *values;
1194         guint32 token;
1195         char sig [128];
1196         char *p = sig;
1197         char blob_size [6];
1198         char *b = blob_size;
1199
1200         switch (type->type) {
1201         case MONO_TYPE_FNPTR:
1202         case MONO_TYPE_PTR:
1203         case MONO_TYPE_SZARRAY:
1204         case MONO_TYPE_ARRAY:
1205                 encode_type (assembly, type, p, &p);
1206                 break;
1207         default:
1208                 return 0;
1209         }
1210         
1211         g_assert (p-sig < 128);
1212         mono_metadata_encode_value (p-sig, b, &b);
1213         token = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1214         mono_image_add_stream_data (&assembly->blob, sig, p-sig);
1215
1216         table = &assembly->tables [MONO_TABLE_TYPESPEC];
1217         alloc_table (table, table->rows + 1);
1218         values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
1219         values [MONO_TYPESPEC_SIGNATURE] = token;
1220
1221         token = TYPEDEFORREF_TYPESPEC | (table->next_idx << TYPEDEFORREF_BITS);
1222         g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
1223         table->next_idx ++;
1224         return token;
1225 }
1226
1227 /*
1228  * Despite the name, we handle also TypeSpec (with the above helper).
1229  */
1230 static guint32
1231 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
1232 {
1233         MonoDynamicTable *table;
1234         guint32 *values;
1235         guint32 token, scope, enclosing;
1236         MonoClass *klass;
1237
1238         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
1239         if (token)
1240                 return token;
1241         token = create_typespec (assembly, type);
1242         if (token)
1243                 return token;
1244         klass = mono_class_from_mono_type (type);
1245         /*
1246          * If it's in the same module:
1247          */
1248         if (klass->image == assembly->assembly.image) {
1249                 MonoReflectionTypeBuilder *tb = klass->reflection_info;
1250                 return TYPEDEFORREF_TYPEDEF | (tb->table_idx << TYPEDEFORREF_BITS);
1251         }
1252
1253         if (klass->nested_in) {
1254                 enclosing = mono_image_typedef_or_ref (assembly, &klass->nested_in->byval_arg);
1255                 /* get the typeref idx of the enclosing type */
1256                 enclosing >>= TYPEDEFORREF_BITS;
1257                 scope = (enclosing << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_TYPEREF;
1258         } else {
1259                 scope = resolution_scope_from_image (assembly, klass->image);
1260         }
1261         table = &assembly->tables [MONO_TABLE_TYPEREF];
1262         alloc_table (table, table->rows + 1);
1263         values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
1264         values [MONO_TYPEREF_SCOPE] = scope;
1265         values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1266         values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1267         token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
1268         g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
1269         table->next_idx ++;
1270         return token;
1271 }
1272
1273 /*
1274  * Insert a memberef row into the metadata: the token that point to the memberref
1275  * is returned. Caching is done in the caller (mono_image_get_methodref_token() or
1276  * mono_image_get_fieldref_token()).
1277  * The sig param is an index to an already built signature.
1278  */
1279 static guint32
1280 mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoType *type, const char *name, guint32 sig)
1281 {
1282         MonoDynamicTable *table;
1283         guint32 *values;
1284         guint32 token, pclass;
1285         guint32 parent;
1286
1287         parent = mono_image_typedef_or_ref (assembly, type);
1288         switch (parent & TYPEDEFORREF_MASK) {
1289         case TYPEDEFORREF_TYPEREF:
1290                 pclass = MEMBERREF_PARENT_TYPEREF;
1291                 break;
1292         case TYPEDEFORREF_TYPESPEC:
1293                 pclass = MEMBERREF_PARENT_TYPESPEC;
1294                 break;
1295         case TYPEDEFORREF_TYPEDEF:
1296                 /* should never get here */
1297         default:
1298                 g_error ("unknow typeref or def token");
1299         }
1300         /* extract the index */
1301         parent >>= TYPEDEFORREF_BITS;
1302
1303         table = &assembly->tables [MONO_TABLE_MEMBERREF];
1304         alloc_table (table, table->rows + 1);
1305         values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
1306         values [MONO_MEMBERREF_CLASS] = pclass | (parent << MEMBERREF_PARENT_BITS);
1307         values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
1308         values [MONO_MEMBERREF_SIGNATURE] = sig;
1309         token = MONO_TOKEN_MEMBER_REF | table->next_idx;
1310         table->next_idx ++;
1311
1312         return token;
1313 }
1314
1315 static guint32
1316 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method)
1317 {
1318         guint32 token;
1319         
1320         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
1321         if (token)
1322                 return token;
1323         token = mono_image_get_memberref_token (assembly, &method->klass->byval_arg,
1324                 method->name,  method_encode_signature (assembly, method->signature));
1325         g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
1326         return token;
1327 }
1328
1329 static guint32
1330 mono_image_get_fieldref_token (MonoDynamicAssembly *assembly, MonoClassField *field, MonoClass *klass)
1331 {
1332         guint32 token;
1333         
1334         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, field));
1335         if (token)
1336                 return token;
1337         token = mono_image_get_memberref_token (assembly, &klass->byval_arg, 
1338                 field->name,  fieldref_encode_signature (assembly, field));
1339         g_hash_table_insert (assembly->handleref, field, GUINT_TO_POINTER(token));
1340         return token;
1341 }
1342
1343 static int
1344 reflection_cc_to_file (int call_conv) {
1345         switch (call_conv & 0x3) {
1346         case 0:
1347         case 1: return MONO_CALL_DEFAULT;
1348         case 2: return MONO_CALL_VARARG;
1349         default:
1350                 g_assert_not_reached ();
1351         }
1352         return 0;
1353 }
1354
1355 typedef struct {
1356         MonoType *parent;
1357         MonoMethodSignature *sig;
1358         char *name;
1359         guint32 token;
1360 } ArrayMethod;
1361
1362 static guint32
1363 mono_image_get_array_token (MonoDynamicAssembly *assembly, MonoReflectionArrayMethod *m)
1364 {
1365         guint32 nparams, i;
1366         GList *tmp;
1367         char *name;
1368         MonoMethodSignature *sig;
1369         ArrayMethod *am;
1370         
1371         name = mono_string_to_utf8 (m->name);
1372         nparams = mono_array_length (m->parameters);
1373         sig = g_malloc0 (sizeof (MonoMethodSignature) + sizeof (MonoType*) * nparams);
1374         sig->hasthis = 1;
1375         sig->call_convention = reflection_cc_to_file (m->call_conv);
1376         sig->param_count = nparams;
1377         sig->ret = m->ret? m->ret->type: &mono_defaults.void_class->byval_arg;
1378         for (i = 0; i < nparams; ++i) {
1379                 MonoReflectionType *t = mono_array_get (m->parameters, gpointer, i);
1380                 sig->params [i] = t->type;
1381         }
1382
1383         for (tmp = assembly->array_methods; tmp; tmp = tmp->next) {
1384                 am = tmp->data;
1385                 if (strcmp (name, am->name) == 0 && 
1386                                 mono_metadata_type_equal (am->parent, m->parent->type) &&
1387                                 mono_metadata_signature_equal (am->sig, sig)) {
1388                         g_free (name);
1389                         g_free (sig);
1390                         return am->token;
1391                 }
1392         }
1393         am = g_new0 (ArrayMethod, 1);
1394         am->name = name;
1395         am->sig = sig;
1396         am->parent = m->parent->type;
1397         am->token = mono_image_get_memberref_token (assembly, am->parent,
1398                 name,  method_encode_signature (assembly, sig));
1399         assembly->array_methods = g_list_prepend (assembly->array_methods, am);
1400         m->table_idx = am->token & 0xffffff;
1401         return am->token;
1402 }
1403
1404 /*
1405  * Insert into the metadata tables all the info about the TypeBuilder tb.
1406  * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
1407  */
1408 static void
1409 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
1410 {
1411         MonoDynamicTable *table;
1412         guint *values;
1413         int i;
1414         char *n;
1415
1416         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1417         values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
1418         values [MONO_TYPEDEF_FLAGS] = tb->attrs;
1419         if (tb->parent) { /* interfaces don't have a parent */
1420                 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
1421         } else
1422                 values [MONO_TYPEDEF_EXTENDS] = 0;
1423         n = mono_string_to_utf8 (tb->name);
1424         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
1425         g_free (n);
1426         n = mono_string_to_utf8 (tb->nspace);
1427         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
1428         g_free (n);
1429         values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
1430         values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
1431
1432         /*
1433          * if we have explicitlayout or sequentiallayouts, output data in the
1434          * ClassLayout table.
1435          */
1436         if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) && (tb->class_size != -1)) {
1437                 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
1438                 table->rows++;
1439                 alloc_table (table, table->rows);
1440                 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
1441                 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
1442                 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
1443                 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
1444         }
1445
1446         /* handle interfaces */
1447         if (tb->interfaces) {
1448                 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1449                 i = table->rows;
1450                 table->rows += mono_array_length (tb->interfaces);
1451                 alloc_table (table, table->rows);
1452                 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
1453                 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
1454                         MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
1455                         values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
1456                         values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface->type);
1457                         values += MONO_INTERFACEIMPL_SIZE;
1458                 }
1459         }
1460
1461         /* handle fields */
1462         if (tb->fields) {
1463                 table = &assembly->tables [MONO_TABLE_FIELD];
1464                 table->rows += mono_array_length (tb->fields);
1465                 alloc_table (table, table->rows);
1466                 for (i = 0; i < mono_array_length (tb->fields); ++i)
1467                         mono_image_get_field_info (
1468                                 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
1469         }
1470
1471         /* handle constructors */
1472         if (tb->ctors) {
1473                 table = &assembly->tables [MONO_TABLE_METHOD];
1474                 table->rows += mono_array_length (tb->ctors);
1475                 alloc_table (table, table->rows);
1476                 for (i = 0; i < mono_array_length (tb->ctors); ++i)
1477                         mono_image_get_ctor_info (domain,
1478                                 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
1479         }
1480
1481         /* handle methods */
1482         if (tb->methods) {
1483                 table = &assembly->tables [MONO_TABLE_METHOD];
1484                 table->rows += mono_array_length (tb->methods);
1485                 alloc_table (table, table->rows);
1486                 for (i = 0; i < mono_array_length (tb->methods); ++i)
1487                         mono_image_get_method_info (
1488                                 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
1489         }
1490
1491         /* Do the same with properties etc.. */
1492         if (tb->events && mono_array_length (tb->events)) {
1493                 table = &assembly->tables [MONO_TABLE_EVENT];
1494                 table->rows += mono_array_length (tb->events);
1495                 alloc_table (table, table->rows);
1496                 table = &assembly->tables [MONO_TABLE_EVENTMAP];
1497                 table->rows ++;
1498                 alloc_table (table, table->rows);
1499                 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
1500                 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
1501                 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
1502                 for (i = 0; i < mono_array_length (tb->events); ++i)
1503                         mono_image_get_event_info (
1504                                 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly);
1505         }
1506         if (tb->properties && mono_array_length (tb->properties)) {
1507                 table = &assembly->tables [MONO_TABLE_PROPERTY];
1508                 table->rows += mono_array_length (tb->properties);
1509                 alloc_table (table, table->rows);
1510                 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
1511                 table->rows ++;
1512                 alloc_table (table, table->rows);
1513                 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
1514                 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
1515                 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
1516                 for (i = 0; i < mono_array_length (tb->properties); ++i)
1517                         mono_image_get_property_info (
1518                                 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
1519         }
1520         if (tb->subtypes) {
1521                 MonoDynamicTable *ntable;
1522                 
1523                 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1524                 table->rows += mono_array_length (tb->subtypes);
1525                 alloc_table (table, table->rows);
1526
1527                 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1528                 ntable->rows += mono_array_length (tb->subtypes);
1529                 alloc_table (ntable, ntable->rows);
1530                 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
1531
1532                 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1533                         MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
1534
1535                         values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
1536                         values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
1537                         /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
1538                                 mono_string_to_utf8 (subtype->name), subtype->table_idx,
1539                                 mono_string_to_utf8 (tb->name), tb->table_idx,
1540                                 ntable->next_idx, ntable->rows);*/
1541                         values += MONO_NESTED_CLASS_SIZE;
1542                         ntable->next_idx++;
1543                 }
1544                 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1545                         MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
1546
1547                         mono_image_get_type_info (domain, subtype, assembly);
1548                 }
1549         }
1550         mono_image_add_cattrs (assembly, tb->table_idx, CUSTOM_ATTR_TYPEDEF, tb->cattrs);
1551 }
1552
1553 static void
1554 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
1555 {
1556         MonoDynamicTable *table;
1557         int i;
1558         char *name;
1559
1560         table = &assembly->tables [MONO_TABLE_MODULE];
1561         mb->table_idx = table->next_idx ++;
1562         name = mono_string_to_utf8 (mb->module.name);
1563         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
1564         g_free (name);
1565         i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1566         i /= 16;
1567         ++i;
1568         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1569         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1570         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1571
1572         mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_MODULE, mb->cattrs);
1573         /*
1574          * fill-in info in other tables as well.
1575          */
1576         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1577         table->rows += mono_array_length (mb->types);
1578         alloc_table (table, table->rows);
1579         /*
1580          * We assign here the typedef indexes to avoid mismatches if a type that
1581          * has not yet been stored in the tables is referenced by another type.
1582          */
1583         for (i = 0; i < mono_array_length (mb->types); ++i) {
1584                 int j;
1585                 MonoReflectionTypeBuilder *type = mono_array_get (mb->types, MonoReflectionTypeBuilder*, i);
1586                 type->table_idx = table->next_idx ++;
1587                 if (!type->subtypes)
1588                         continue;
1589                 for (j = 0; j < mono_array_length (type->subtypes); ++j) {
1590                         MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, j);
1591                         subtype->table_idx = table->next_idx ++;
1592                 }
1593         }
1594         for (i = 0; i < mono_array_length (mb->types); ++i)
1595                 mono_image_get_type_info (domain, mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
1596 }
1597
1598 #define align_pointer(base,p)\
1599         do {\
1600                 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1601                 if (__diff & 3)\
1602                         (p) += 4 - (__diff & 3);\
1603         } while (0)
1604
1605 static int
1606 compare_semantics (const void *a, const void *b)
1607 {
1608         const guint32 *a_values = a;
1609         const guint32 *b_values = b;
1610         int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1611         if (assoc)
1612                 return assoc;
1613         return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1614 }
1615
1616 static int
1617 compare_custom_attrs (const void *a, const void *b)
1618 {
1619         const guint32 *a_values = a;
1620         const guint32 *b_values = b;
1621
1622         return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1623 }
1624
1625 static int
1626 compare_field_marshal (const void *a, const void *b)
1627 {
1628         const guint32 *a_values = a;
1629         const guint32 *b_values = b;
1630
1631         return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1632 }
1633
1634 static int
1635 compare_nested (const void *a, const void *b)
1636 {
1637         const guint32 *a_values = a;
1638         const guint32 *b_values = b;
1639
1640         return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1641 }
1642
1643 /*
1644  * build_compressed_metadata() fills in the blob of data that represents the 
1645  * raw metadata as it will be saved in the PE file. The five streams are output 
1646  * and the metadata tables are comnpressed from the guint32 array representation, 
1647  * to the compressed on-disk format.
1648  */
1649 static void
1650 build_compressed_metadata (MonoDynamicAssembly *assembly)
1651 {
1652         MonoDynamicTable *table;
1653         int i;
1654         guint64 valid_mask = 0;
1655         guint64 sorted_mask;
1656         guint32 heapt_size = 0;
1657         guint32 meta_size = 256; /* allow for header and other stuff */
1658         guint32 table_offset;
1659         guint32 ntables = 0;
1660         guint64 *int64val;
1661         guint32 *int32val;
1662         guint16 *int16val;
1663         MonoImage *meta;
1664         unsigned char *p;
1665         /*
1666          * We need to use the current ms version or the ms runtime it won't find
1667          * the support dlls. D'oh!
1668          * const char *version = "mono-" VERSION;
1669          */
1670         const char *version = "v1.0.3705";
1671         struct StreamDesc {
1672                 const char *name;
1673                 MonoDynamicStream *stream;
1674         } stream_desc [] = {
1675                 {"#~", &assembly->tstream},
1676                 {"#Strings", &assembly->sheap},
1677                 {"#US", &assembly->us},
1678                 {"#Blob", &assembly->blob},
1679                 {"#GUID", &assembly->guid}
1680         };
1681         
1682         /* tables that are sorted */
1683         sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1684                 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1685                 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1686                 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1687                 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1688                 | ((guint64)1 << MONO_TABLE_DECLSECURITY);
1689         
1690         /* Compute table sizes */
1691         /* the MonoImage has already been created in mono_image_basic_init() */
1692         meta = assembly->assembly.image;
1693         
1694         /* Setup the info used by compute_sizes () */
1695         meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1696         meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1697         meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1698
1699         meta_size += assembly->blob.index;
1700         meta_size += assembly->guid.index;
1701         meta_size += assembly->sheap.index;
1702         meta_size += assembly->us.index;
1703
1704         for (i=0; i < 64; ++i)
1705                 meta->tables [i].rows = assembly->tables [i].rows;
1706         
1707         for (i = 0; i < 64; i++){
1708                 if (meta->tables [i].rows == 0)
1709                         continue;
1710                 valid_mask |= (guint64)1 << i;
1711                 ntables ++;
1712                 meta->tables [i].row_size = mono_metadata_compute_size (
1713                         meta, i, &meta->tables [i].size_bitfield);
1714                 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1715         }
1716         heapt_size += 24; /* #~ header size */
1717         heapt_size += ntables * 4;
1718         meta_size += heapt_size;
1719         meta->raw_metadata = g_malloc0 (meta_size);
1720         p = meta->raw_metadata;
1721         /* the metadata signature */
1722         *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1723         /* version numbers and 4 bytes reserved */
1724         int16val = (guint16*)p;
1725         *int16val++ = GUINT16_TO_LE (1);
1726         *int16val = GUINT16_TO_LE (1);
1727         p += 8;
1728         /* version string */
1729         int32val = (guint32*)p;
1730         *int32val = GUINT32_TO_LE ((strlen (version) + 3) & (~3)); /* needs to be multiple of 4 */
1731         p += 4;
1732         memcpy (p, version, GUINT32_FROM_LE (*int32val));
1733         p += GUINT32_FROM_LE (*int32val);
1734         align_pointer (meta->raw_metadata, p);
1735         int16val = (guint16*)p;
1736         *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
1737         *int16val = GUINT16_TO_LE (5); /* number of streams */
1738         p += 4;
1739
1740         /*
1741          * write the stream info.
1742          */
1743         table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1744         table_offset += 3; table_offset &= ~3;
1745
1746         assembly->tstream.index = heapt_size;
1747         for (i = 0; i < 5; ++i) {
1748                 int32val = (guint32*)p;
1749                 stream_desc [i].stream->offset = table_offset;
1750                 *int32val++ = GUINT32_TO_LE (table_offset);
1751                 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
1752                 table_offset += GUINT32_FROM_LE (*int32val);
1753                 table_offset += 3; table_offset &= ~3;
1754                 p += 8;
1755                 strcpy (p, stream_desc [i].name);
1756                 p += strlen (stream_desc [i].name) + 1;
1757                 align_pointer (meta->raw_metadata, p);
1758         }
1759         /* 
1760          * now copy the data, the table stream header and contents goes first.
1761          */
1762         g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1763         p = meta->raw_metadata + assembly->tstream.offset;
1764         int32val = (guint32*)p;
1765         *int32val = GUINT32_TO_LE (0); /* reserved */
1766         p += 4;
1767         *p++ = 1; /* version */
1768         *p++ = 0;
1769         if (meta->idx_string_wide)
1770                 *p |= 0x01;
1771         if (meta->idx_guid_wide)
1772                 *p |= 0x02;
1773         if (meta->idx_blob_wide)
1774                 *p |= 0x04;
1775         ++p;
1776         *p++ = 0; /* reserved */
1777         int64val = (guint64*)p;
1778         *int64val++ = GUINT64_TO_LE (valid_mask);
1779         *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables  */
1780         p += 16;
1781         int32val = (guint32*)p;
1782         for (i = 0; i < 64; i++){
1783                 if (meta->tables [i].rows == 0)
1784                         continue;
1785                 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
1786         }
1787         p = (unsigned char*)int32val;
1788
1789         /* sort the tables that still need sorting */
1790         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1791         if (table->rows)
1792                 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
1793         table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1794         if (table->rows)
1795                 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
1796         table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1797         if (table->rows)
1798                 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
1799         table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1800         if (table->rows)
1801                 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
1802
1803         /* compress the tables */
1804         for (i = 0; i < 64; i++){
1805                 int row, col;
1806                 guint32 *values;
1807                 guint32 bitfield = meta->tables [i].size_bitfield;
1808                 if (!meta->tables [i].rows)
1809                         continue;
1810                 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1811                         g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1812                 meta->tables [i].base = p;
1813                 for (row = 1; row <= meta->tables [i].rows; ++row) {
1814                         values = assembly->tables [i].values + row * assembly->tables [i].columns;
1815                         for (col = 0; col < assembly->tables [i].columns; ++col) {
1816                                 switch (mono_metadata_table_size (bitfield, col)) {
1817                                 case 1:
1818                                         *p++ = values [col];
1819                                         break;
1820                                 case 2:
1821                                         int16val = (guint16*)p;
1822                                         *int16val = GUINT16_TO_LE (values [col]);
1823                                         p += 2;
1824                                         break;
1825                                 case 4:
1826                                         int32val = (guint32*)p;
1827                                         *int32val = GUINT32_TO_LE (values [col]);
1828                                         p += 4;
1829                                         break;
1830                                 default:
1831                                         g_assert_not_reached ();
1832                                 }
1833                         }
1834                 }
1835                 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1836         }
1837         
1838         g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1839         memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1840         memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1841         memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1842         memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1843
1844         assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1845 }
1846
1847 /*
1848  * Some tables in metadata need to be sorted according to some criteria, but
1849  * when methods and fields are first created with reflection, they may be assigned a token
1850  * that doesn't correspond to the final token they will get assigned after the sorting.
1851  * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
1852  * with the reflection objects that represent them. Once all the tables are set up, the 
1853  * reflection objects will contains the correct table index. fixup_method() will fixup the
1854  * tokens for the method with ILGenerator @ilgen.
1855  */
1856 static void
1857 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *assembly) {
1858         guint32 code_idx = GPOINTER_TO_UINT (value);
1859         MonoReflectionILTokenInfo *iltoken;
1860         MonoReflectionFieldBuilder *field;
1861         MonoReflectionCtorBuilder *ctor;
1862         MonoReflectionMethodBuilder *method;
1863         guint32 i, idx;
1864         unsigned char *target;
1865
1866         for (i = 0; i < ilgen->num_token_fixups; ++i) {
1867                 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
1868                 target = assembly->code.data + code_idx + iltoken->code_pos;
1869                 switch (target [3]) {
1870                 case MONO_TABLE_FIELD:
1871                         if (strcmp (iltoken->member->vtable->klass->name, "FieldBuilder"))
1872                                 g_assert_not_reached ();
1873                         field = (MonoReflectionFieldBuilder *)iltoken->member;
1874                         idx = field->table_idx;
1875                         break;
1876                 case MONO_TABLE_METHOD:
1877                         if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
1878                                 method = (MonoReflectionMethodBuilder *)iltoken->member;
1879                                 idx = method->table_idx;
1880                         } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
1881                                 ctor = (MonoReflectionCtorBuilder *)iltoken->member;
1882                                 idx = ctor->table_idx;
1883                         } else {
1884                                 g_assert_not_reached ();
1885                         }
1886                         break;
1887                 default:
1888                         g_error ("got unexpected table 0x%02x in fixup", target [3]);
1889                 }
1890                 target [0] = idx & 0xff;
1891                 target [1] = (idx >> 8) & 0xff;
1892                 target [2] = (idx >> 16) & 0xff;
1893         }
1894 }
1895
1896 /*
1897  * mono_image_build_metadata() will fill the info in all the needed metadata tables
1898  * for the AssemblyBuilder @assemblyb: it iterates over the assembly modules
1899  * and recursively outputs the info for a module. Each module will output all the info
1900  * about it's types etc.
1901  * At the end of the process, method and field tokens are fixed up and the on-disk
1902  * compressed metadata representation is created.
1903  */
1904 static void
1905 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
1906 {
1907         MonoDynamicTable *table;
1908         MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
1909         MonoDomain *domain = ((MonoObject *)assemblyb)->vtable->domain;
1910         guint32 len;
1911         guint32 *values;
1912         char *name;
1913         int i;
1914         
1915         assembly->text_rva = START_TEXT_RVA;
1916
1917         table = &assembly->tables [MONO_TABLE_ASSEMBLY];
1918         alloc_table (table, 1);
1919         values = table->values + MONO_ASSEMBLY_SIZE;
1920         values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
1921         name = mono_string_to_utf8 (assemblyb->name);
1922         values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
1923         g_free (name);
1924         values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
1925         values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
1926         values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1927         values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1928         values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1929         values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1930         values [MONO_ASSEMBLY_FLAGS] = 0;
1931
1932         mono_image_add_cattrs (assembly, 1, CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs);
1933
1934         assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
1935         assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
1936
1937         if (assemblyb->modules) {
1938                 len = mono_array_length (assemblyb->modules);
1939                 table = &assembly->tables [MONO_TABLE_MODULE];
1940                 alloc_table (table, len);
1941                 for (i = 0; i < len; ++i)
1942                         mono_image_fill_module_table (domain, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
1943         } else {
1944                 table = &assembly->tables [MONO_TABLE_MODULE];
1945                 table->rows++;
1946                 alloc_table (table, table->rows);
1947                 table->values [table->next_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, "RefEmit_YouForgotToDefineAModule");
1948                 table->next_idx ++;
1949         }
1950
1951         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1952         /* 
1953          * table->rows is already set above and in mono_image_fill_module_table.
1954          */
1955         alloc_table (table, table->rows);
1956         /*
1957          * Set the first entry.
1958          */
1959         values = table->values + table->columns;
1960         values [MONO_TYPEDEF_FLAGS] = 0;
1961         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
1962         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
1963         values [MONO_TYPEDEF_EXTENDS] = 0;
1964         values [MONO_TYPEDEF_FIELD_LIST] = 1;
1965         values [MONO_TYPEDEF_METHOD_LIST] = 1;
1966
1967         /* fixup tokens */
1968         mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
1969         
1970         build_compressed_metadata (assembly);
1971 }
1972
1973 /*
1974  * mono_image_insert_string:
1975  * @assembly: assembly builder object
1976  * @str: a string
1977  *
1978  * Insert @str into the user string stream of @assembly.
1979  */
1980 guint32
1981 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
1982 {
1983         guint32 idx;
1984         char buf [16];
1985         char *b = buf;
1986         
1987         if (!assembly->dynamic_assembly)
1988                 mono_image_basic_init (assembly);
1989         mono_metadata_encode_value (1 | (str->length * 2), b, &b);
1990         idx = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
1991 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1992         {
1993                 char *swapped = g_malloc (2 * mono_string_length (str));
1994                 const char *p = (const char*)mono_string_chars (str);
1995
1996                 swap_with_size (swapped, p, 2, mono_string_length (str));
1997                 mono_image_add_stream_data (&assembly->dynamic_assembly->us, swapped, str->length * 2);
1998                 g_free (swapped);
1999         }
2000 #else
2001         mono_image_add_stream_data (&assembly->dynamic_assembly->us, (const char*)mono_string_chars (str), str->length * 2);
2002 #endif
2003         mono_image_add_stream_data (&assembly->dynamic_assembly->us, "", 1);
2004         return MONO_TOKEN_STRING | idx;
2005 }
2006
2007 /*
2008  * mono_image_create_token:
2009  * @assembly: a dynamic assembly
2010  * @obj:
2011  *
2012  * Get a token to insert in the IL code stream for the given MemberInfo.
2013  * @obj can be one of:
2014  *      ConstructorBuilder
2015  *      MethodBuilder
2016  *      FieldBuilder
2017  *      MonoCMethod
2018  *      MonoMethod
2019  *      MonoField
2020  *      MonoType
2021  *      TypeBuilder
2022  */
2023 guint32
2024 mono_image_create_token (MonoDynamicAssembly *assembly, MonoObject *obj)
2025 {
2026         MonoClass *klass;
2027         guint32 token;
2028
2029         if (!obj)
2030                 g_error ("System.Array methods not yet supported");
2031         
2032         klass = obj->vtable->klass;
2033         if (strcmp (klass->name, "MethodBuilder") == 0) {
2034                 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
2035                 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
2036                 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
2037                 return token;
2038         }
2039         if (strcmp (klass->name, "ConstructorBuilder") == 0) {
2040                 MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
2041                 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
2042                 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
2043                 return token;
2044         }
2045         if (strcmp (klass->name, "FieldBuilder") == 0) {
2046                 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
2047                 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
2048         }
2049         if (strcmp (klass->name, "TypeBuilder") == 0) {
2050                 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
2051                 return tb->table_idx | MONO_TOKEN_TYPE_DEF;
2052         }
2053         if (strcmp (klass->name, "MonoType") == 0) {
2054                 MonoReflectionType *tb = (MonoReflectionType *)obj;
2055                 return mono_metadata_token_from_dor (
2056                         mono_image_typedef_or_ref (assembly, tb->type));
2057         }
2058         if (strcmp (klass->name, "MonoCMethod") == 0 ||
2059                         strcmp (klass->name, "MonoMethod") == 0) {
2060                 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
2061                 token = mono_image_get_methodref_token (assembly, m->method);
2062                 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
2063                 return token;
2064         }
2065         if (strcmp (klass->name, "MonoField") == 0) {
2066                 MonoReflectionField *f = (MonoReflectionField *)obj;
2067                 token = mono_image_get_fieldref_token (assembly, f->field, f->klass);
2068                 /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/
2069                 return token;
2070         }
2071         if (strcmp (klass->name, "MonoArrayMethod") == 0) {
2072                 MonoReflectionArrayMethod *m = (MonoReflectionArrayMethod *)obj;
2073                 token = mono_image_get_array_token (assembly, m);
2074                 return token;
2075         }
2076         g_print ("requested token for %s\n", klass->name);
2077         return 0;
2078 }
2079
2080 typedef struct {
2081         guint32 import_lookup_table;
2082         guint32 timestamp;
2083         guint32 forwarder;
2084         guint32 name_rva;
2085         guint32 import_address_table_rva;
2086 } MonoIDT;
2087
2088 typedef struct {
2089         guint32 name_rva;
2090         guint32 flags;
2091 } MonoILT;
2092
2093 /*
2094  * mono_image_basic_ini:
2095  * @assembly: an assembly builder object
2096  *
2097  * Create the MonoImage that represents the assembly builder and setup some
2098  * of the helper hash table and the basic metadata streams.
2099  */
2100 void
2101 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
2102 {
2103         static const guchar entrycode [16] = {0xff, 0x25, 0};
2104         MonoDynamicAssembly *assembly;
2105         MonoImage *image;
2106         int i;
2107         
2108         if (assemblyb->dynamic_assembly)
2109                 return;
2110
2111 #if HAVE_BOEHM_GC
2112         assembly = assemblyb->dynamic_assembly = GC_malloc (sizeof (MonoDynamicAssembly));
2113 #else
2114         assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
2115 #endif
2116
2117         assembly->token_fixups = mono_g_hash_table_new (g_direct_hash, g_direct_equal);
2118         assembly->handleref = g_hash_table_new (g_direct_hash, g_direct_equal);
2119         assembly->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
2120
2121         string_heap_init (&assembly->sheap);
2122         mono_image_add_stream_data (&assembly->us, "", 1);
2123         mono_image_add_stream_data (&assembly->blob, "", 1);
2124         /* import tables... */
2125         mono_image_add_stream_data (&assembly->code, entrycode, sizeof (entrycode));
2126         assembly->iat_offset = mono_image_add_stream_zero (&assembly->code, 8); /* two IAT entries */
2127         assembly->idt_offset = mono_image_add_stream_zero (&assembly->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
2128         mono_image_add_stream_zero (&assembly->code, 2); /* flags for name entry */
2129         assembly->imp_names_offset = mono_image_add_stream_data (&assembly->code, "_CorExeMain", 12);
2130         mono_image_add_stream_data (&assembly->code, "mscoree.dll", 12);
2131         assembly->ilt_offset = mono_image_add_stream_zero (&assembly->code, 8); /* two ILT entries */
2132         stream_data_align (&assembly->code);
2133
2134         assembly->cli_header_offset = mono_image_add_stream_zero (&assembly->code, sizeof (MonoCLIHeader));
2135
2136         for (i=0; i < 64; ++i) {
2137                 assembly->tables [i].next_idx = 1;
2138                 assembly->tables [i].columns = table_sizes [i];
2139         }
2140
2141         image = g_new0 (MonoImage, 1);
2142         
2143         /* keep in sync with image.c */
2144         image->name = mono_string_to_utf8 (assemblyb->name);
2145         image->assembly_name = image->name; /* they may be different */
2146
2147         image->method_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2148         image->class_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2149         image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2150         image->array_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2151
2152         assembly->assembly.image = image;
2153         
2154 }
2155
2156 static int
2157 calc_section_size (MonoDynamicAssembly *assembly)
2158 {
2159         int nsections = 0;
2160
2161         /* alignment constraints */
2162         assembly->code.index += 3;
2163         assembly->code.index &= ~3;
2164         assembly->meta_size += 3;
2165         assembly->meta_size &= ~3;
2166
2167         assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index;
2168         assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2169         nsections++;
2170
2171         assembly->sections [MONO_SECTION_RELOC].size = 12;
2172         assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2173         nsections++;
2174
2175         return nsections;
2176 }
2177
2178 /*
2179  * mono_image_create_pefile:
2180  * @assemblyb: an assembly builder object
2181  * 
2182  * When we need to save an assembly, we first call this function that ensures the metadata 
2183  * tables are built for all the modules in the assembly. This function creates the PE-COFF
2184  * header, the image sections, the CLI header etc. all the data is written in
2185  * assembly->pefile where it can be easily retrieved later in chunks.
2186  */
2187 void
2188 mono_image_create_pefile (MonoReflectionAssemblyBuilder *assemblyb) {
2189         MonoMSDOSHeader *msdos;
2190         MonoDotNetHeader *header;
2191         MonoSectionTable *section;
2192         MonoCLIHeader *cli_header;
2193         guint32 size, image_size, virtual_base;
2194         guint32 header_start, section_start, file_offset, virtual_offset;
2195         MonoDynamicAssembly *assembly;
2196         MonoDynamicStream *pefile;
2197         int i, nsections;
2198         guint32 *rva;
2199         guint16 *data16;
2200         static const unsigned char msheader[] = {
2201                 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,  0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2202                 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2203                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2204                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2205                 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,  0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2206                 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,  0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2207                 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,  0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2208                 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2209         };
2210
2211         mono_image_basic_init (assemblyb);
2212         assembly = assemblyb->dynamic_assembly;
2213
2214         /* already created */
2215         if (assembly->pefile.index)
2216                 return;
2217         
2218         mono_image_build_metadata (assemblyb);
2219         nsections = calc_section_size (assembly);
2220
2221         pefile = &assembly->pefile;
2222
2223         /* The DOS header and stub */
2224         g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2225         mono_image_add_stream_data (pefile, msheader, sizeof (msheader));
2226
2227         /* the dotnet header */
2228         header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2229
2230         /* the section tables */
2231         section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2232
2233         file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2234         virtual_offset = VIRT_ALIGN;
2235         image_size = 0;
2236
2237         for (i = 0; i < MONO_SECTION_MAX; ++i) {
2238                 if (!assembly->sections [i].size)
2239                         continue;
2240                 /* align offsets */
2241                 file_offset += FILE_ALIGN - 1;
2242                 file_offset &= ~(FILE_ALIGN - 1);
2243                 virtual_offset += VIRT_ALIGN - 1;
2244                 virtual_offset &= ~(VIRT_ALIGN - 1);
2245
2246                 assembly->sections [i].offset = file_offset;
2247                 assembly->sections [i].rva = virtual_offset;
2248
2249                 file_offset += assembly->sections [i].size;
2250                 virtual_offset += assembly->sections [i].size;
2251                 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2252         }
2253
2254         file_offset += FILE_ALIGN - 1;
2255         file_offset &= ~(FILE_ALIGN - 1);
2256         mono_image_add_stream_zero (pefile, file_offset - pefile->index);
2257
2258         image_size += section_start + sizeof (MonoSectionTable) * nsections;
2259
2260         /* back-patch info */
2261         msdos = (MonoMSDOSHeader*)pefile->data;
2262         msdos->nlast_page = GUINT16_FROM_LE (file_offset & (512 - 1));
2263         msdos->npages = GUINT16_FROM_LE ((file_offset + (512 - 1)) / 512);
2264         msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2265
2266         header = (MonoDotNetHeader*)(pefile->data + header_start);
2267         header->pesig [0] = 'P';
2268         header->pesig [1] = 'E';
2269         
2270         header->coff.coff_machine = GUINT16_FROM_LE (0x14c);
2271         header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2272         header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2273         header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2274         /* it's an exe */
2275         header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2276         /* FIXME: it's a dll */
2277         /*header->coff.coff_attributes = GUINT16_FROM_LE (0x210e); */
2278
2279         virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2280
2281         header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2282         header->pe.pe_major = 6;
2283         header->pe.pe_minor = 0;
2284         size = assembly->sections [MONO_SECTION_TEXT].size;
2285         size += FILE_ALIGN - 1;
2286         size &= ~(FILE_ALIGN - 1);
2287         header->pe.pe_code_size = size;
2288         size = assembly->sections [MONO_SECTION_RSRC].size;
2289         size += FILE_ALIGN - 1;
2290         size &= ~(FILE_ALIGN - 1);
2291         header->pe.pe_data_size = size;
2292         g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2293         header->pe.pe_rva_code_base = assembly->sections [MONO_SECTION_TEXT].rva;
2294         header->pe.pe_rva_data_base = assembly->sections [MONO_SECTION_RSRC].rva;
2295         /* pe_rva_entry_point always at the beginning of the text section */
2296         header->pe.pe_rva_entry_point = assembly->sections [MONO_SECTION_TEXT].rva;
2297
2298         header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2299         header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2300         header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2301         header->nt.pe_os_major = GUINT16_FROM_LE (4);
2302         header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2303         header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2304         size = section_start;
2305         size += FILE_ALIGN - 1;
2306         size &= ~(FILE_ALIGN - 1);
2307         header->nt.pe_header_size = GUINT32_FROM_LE (size);
2308         size = image_size;
2309         size += VIRT_ALIGN - 1;
2310         size &= ~(VIRT_ALIGN - 1);
2311         header->nt.pe_image_size = GUINT32_FROM_LE (size);
2312         header->nt.pe_subsys_required = GUINT16_FROM_LE (3); /* 3 -> cmdline app, 2 -> GUI app */
2313         header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2314         header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2315         header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2316         header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2317         header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2318         header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2319
2320         /* fill data directory entries */
2321
2322         header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2323         header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2324
2325         header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2326         header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2327
2328         header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2329         header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2330         header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2331         header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2332         /* patch imported function RVA name */
2333         rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2334         *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2335
2336         /* the import table */
2337         header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2338         header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2339         /* patch imported dll RVA name and other entries in the dir */
2340         rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2341         *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 12); /* 12 is strlen+1 of func name */
2342         rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2343         *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2344         rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2345         *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2346
2347         rva = (guint32*)(assembly->code.data + assembly->ilt_offset);
2348         *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset - 2);
2349
2350         /* the CLI header info */
2351         cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2352         cli_header->ch_size = GUINT32_FROM_LE (72);
2353         cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2354         cli_header->ch_flags = GUINT32_FROM_LE (CLI_FLAGS_ILONLY);
2355         if (assemblyb->entry_point) 
2356                 cli_header->ch_entry_point = GUINT32_FROM_LE (assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF);
2357         else
2358                 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2359         cli_header->ch_metadata.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->code.index);
2360         cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
2361
2362         /* write the section tables and section content */
2363         section = (MonoSectionTable*)(pefile->data + section_start);
2364         for (i = 0; i < MONO_SECTION_MAX; ++i) {
2365                 static const char *section_names [] = {
2366                         ".text", ".rsrc", ".reloc"
2367                 };
2368                 if (!assembly->sections [i].size)
2369                         continue;
2370                 strcpy (section->st_name, section_names [i]);
2371                 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
2372                 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
2373                 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
2374                 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
2375                 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
2376                 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
2377                 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
2378                 switch (i) {
2379                 case MONO_SECTION_TEXT:
2380                         /* patch entry point */
2381                         rva = (guint32*)(assembly->code.data + 2);
2382                         *rva = GUINT32_FROM_LE (virtual_base + assembly->text_rva + assembly->iat_offset);
2383                         memcpy (pefile->data + assembly->sections [i].offset, assembly->code.data, assembly->code.index);
2384                         memcpy (pefile->data + assembly->sections [i].offset + assembly->code.index, assembly->assembly.image->raw_metadata, assembly->meta_size);
2385                         break;
2386                 case MONO_SECTION_RELOC:
2387                         rva = (guint32*)(pefile->data + assembly->sections [i].offset);
2388                         *rva = GUINT32_FROM_LE (assembly->text_rva);
2389                         ++rva;
2390                         *rva = GUINT32_FROM_LE (12);
2391                         ++rva;
2392                         data16 = (guint16*)rva;
2393                         /* 
2394                          * the entrypoint is always at the start of the text section 
2395                          * 3 is IMAGE_REL_BASED_HIGHLOW
2396                          * 2 is patch_size_rva - text_rva
2397                          */
2398                         *data16 = GUINT16_FROM_LE ((3 << 12) + (2));
2399                         data16++;
2400                         *data16 = 0; /* terminate */
2401                         break;
2402                 case MONO_SECTION_RSRC:
2403                 default:
2404                         g_assert_not_reached ();
2405                 }
2406                 section++;
2407         }
2408         
2409         /* check that the file is properly padded */
2410 #if 0
2411         {
2412                 FILE *f = fopen ("mypetest.exe", "w");
2413                 fwrite (pefile->data, pefile->index, 1, f);
2414                 fclose (f);
2415         }
2416 #endif
2417 }
2418
2419 /*
2420  * We need to return always the same object for MethodInfo, FieldInfo etc..
2421  * type uses a different hash, since it uses custom hash/equal functions.
2422  */
2423 static MonoGHashTable *object_cache = NULL;
2424 static MonoGHashTable *type_cache = NULL;
2425
2426 #define CHECK_OBJECT(t,p)       \
2427         do {    \
2428                 t _obj; \
2429                 if (!object_cache)      \
2430                         object_cache = mono_g_hash_table_new (g_direct_hash, g_direct_equal);   \
2431                 if ((_obj = mono_g_hash_table_lookup (object_cache, (p))))      \
2432                         return _obj;    \
2433         } while (0)
2434
2435 #define CACHE_OBJECT(p,o)       \
2436         do {    \
2437                 mono_g_hash_table_insert (object_cache, p,o);   \
2438         } while (0)
2439
2440 /*
2441  * mono_assembly_get_object:
2442  * @domain: an app domain
2443  * @assembly: an assembly
2444  *
2445  * Return an System.Reflection.Assembly object representing the MonoAssembly @assembly.
2446  */
2447 MonoReflectionAssembly*
2448 mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly)
2449 {
2450         static MonoClass *System_Reflection_Assembly;
2451         MonoReflectionAssembly *res;
2452         
2453         CHECK_OBJECT (MonoReflectionAssembly *, assembly);
2454         if (!System_Reflection_Assembly)
2455                 System_Reflection_Assembly = mono_class_from_name (
2456                         mono_defaults.corlib, "System.Reflection", "Assembly");
2457         res = (MonoReflectionAssembly *)mono_object_new (domain, System_Reflection_Assembly);
2458         res->assembly = assembly;
2459         CACHE_OBJECT (assembly, res);
2460         return res;
2461 }
2462
2463 static gboolean
2464 mymono_metadata_type_equal (MonoType *t1, MonoType *t2)
2465 {
2466         if ((t1->type != t2->type) ||
2467             (t1->byref != t2->byref))
2468                 return FALSE;
2469
2470         switch (t1->type) {
2471         case MONO_TYPE_VOID:
2472         case MONO_TYPE_BOOLEAN:
2473         case MONO_TYPE_CHAR:
2474         case MONO_TYPE_I1:
2475         case MONO_TYPE_U1:
2476         case MONO_TYPE_I2:
2477         case MONO_TYPE_U2:
2478         case MONO_TYPE_I4:
2479         case MONO_TYPE_U4:
2480         case MONO_TYPE_I8:
2481         case MONO_TYPE_U8:
2482         case MONO_TYPE_R4:
2483         case MONO_TYPE_R8:
2484         case MONO_TYPE_STRING:
2485         case MONO_TYPE_I:
2486         case MONO_TYPE_U:
2487         case MONO_TYPE_OBJECT:
2488                 return TRUE;
2489         case MONO_TYPE_VALUETYPE:
2490         case MONO_TYPE_CLASS:
2491                 return t1->data.klass == t2->data.klass;
2492         case MONO_TYPE_PTR:
2493         case MONO_TYPE_SZARRAY:
2494                 return mymono_metadata_type_equal (t1->data.type, t2->data.type);
2495         case MONO_TYPE_ARRAY:
2496                 if (t1->data.array->rank != t2->data.array->rank)
2497                         return FALSE;
2498                 return mymono_metadata_type_equal (t1->data.array->type, t2->data.array->type);
2499         default:
2500                 g_error ("implement type compare for %0x!", t1->type);
2501                 return FALSE;
2502         }
2503
2504         return FALSE;
2505 }
2506
2507 static guint
2508 mymono_metadata_type_hash (MonoType *t1)
2509 {
2510         guint hash;
2511
2512         hash = t1->type;
2513
2514         hash |= t1->byref << 6; /* do not collide with t1->type values */
2515         switch (t1->type) {
2516         case MONO_TYPE_VALUETYPE:
2517         case MONO_TYPE_CLASS:
2518                 /* check if the distribution is good enough */
2519                 return hash << 7 | g_str_hash (t1->data.klass->name);
2520         case MONO_TYPE_PTR:
2521         case MONO_TYPE_SZARRAY:
2522                 return hash << 7 | mymono_metadata_type_hash (t1->data.type);
2523         }
2524         return hash;
2525 }
2526
2527 /*
2528  * mono_type_get_object:
2529  * @domain: an app domain
2530  * @type: a type
2531  *
2532  * Return an System.MonoType object representing the type @type.
2533  */
2534 MonoReflectionType*
2535 mono_type_get_object (MonoDomain *domain, MonoType *type)
2536 {
2537         MonoReflectionType *res;
2538         MonoClass *klass = mono_class_from_mono_type (type);
2539
2540         if (!type_cache)
2541                 type_cache = mono_g_hash_table_new ((GHashFunc)mymono_metadata_type_hash, 
2542                                 (GCompareFunc)mymono_metadata_type_equal);
2543         if ((res = mono_g_hash_table_lookup (type_cache, type)))
2544                 return res;
2545         if (klass->reflection_info) {
2546                 /* should this be considered an error condition? */
2547                 if (!type->byref)
2548                         return klass->reflection_info;
2549         }
2550         mono_class_init (klass);
2551         res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class);
2552         res->type = type;
2553         mono_g_hash_table_insert (type_cache, type, res);
2554         return res;
2555 }
2556
2557 /*
2558  * mono_method_get_object:
2559  * @domain: an app domain
2560  * @method: a method
2561  *
2562  * Return an System.Reflection.MonoMethod object representing the method @method.
2563  */
2564 MonoReflectionMethod*
2565 mono_method_get_object (MonoDomain *domain, MonoMethod *method)
2566 {
2567         /*
2568          * We use the same C representation for methods and constructors, but the type 
2569          * name in C# is different.
2570          */
2571         const char *cname;
2572         MonoClass *klass;
2573         MonoReflectionMethod *ret;
2574
2575         CHECK_OBJECT (MonoReflectionMethod *, method);
2576         if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
2577                 cname = "MonoCMethod";
2578         else
2579                 cname = "MonoMethod";
2580         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
2581
2582         ret = (MonoReflectionMethod*)mono_object_new (domain, klass);
2583         ret->method = method;
2584         ret->name = mono_string_new (domain, method->name);
2585         CACHE_OBJECT (method, ret);
2586         return ret;
2587 }
2588
2589 /*
2590  * mono_field_get_object:
2591  * @domain: an app domain
2592  * @klass: a type
2593  * @field: a field
2594  *
2595  * Return an System.Reflection.MonoField object representing the field @field
2596  * in class @klass.
2597  */
2598 MonoReflectionField*
2599 mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *field)
2600 {
2601         MonoReflectionField *res;
2602         MonoClass *oklass;
2603
2604         CHECK_OBJECT (MonoReflectionField *, field);
2605         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
2606         res = (MonoReflectionField *)mono_object_new (domain, oklass);
2607         res->klass = klass;
2608         res->field = field;
2609         CACHE_OBJECT (field, res);
2610         return res;
2611 }
2612
2613 /*
2614  * mono_property_get_object:
2615  * @domain: an app domain
2616  * @klass: a type
2617  * @property: a property
2618  *
2619  * Return an System.Reflection.MonoProperty object representing the property @property
2620  * in class @klass.
2621  */
2622 MonoReflectionProperty*
2623 mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *property)
2624 {
2625         MonoReflectionProperty *res;
2626         MonoClass *oklass;
2627
2628         CHECK_OBJECT (MonoReflectionProperty *, property);
2629         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
2630         res = (MonoReflectionProperty *)mono_object_new (domain, oklass);
2631         res->klass = klass;
2632         res->property = property;
2633         CACHE_OBJECT (property, res);
2634         return res;
2635 }
2636
2637 /*
2638  * mono_event_get_object:
2639  * @domain: an app domain
2640  * @klass: a type
2641  * @event: a event
2642  *
2643  * Return an System.Reflection.MonoEvent object representing the event @event
2644  * in class @klass.
2645  */
2646 MonoReflectionEvent*
2647 mono_event_get_object (MonoDomain *domain, MonoClass *klass, MonoEvent *event)
2648 {
2649         MonoReflectionEvent *res;
2650         MonoClass *oklass;
2651
2652         CHECK_OBJECT (MonoReflectionEvent *, event);
2653         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoEvent");
2654         res = (MonoReflectionEvent *)mono_object_new (domain, oklass);
2655         res->klass = klass;
2656         res->event = event;
2657         CACHE_OBJECT (event, res);
2658         return res;
2659 }
2660
2661 /*
2662  * mono_param_get_objects:
2663  * @domain: an app domain
2664  * @method: a method
2665  *
2666  * Return an System.Reflection.ParameterInfo array object representing the parameters
2667  * in the method @method.
2668  */
2669 MonoReflectionParameter**
2670 mono_param_get_objects (MonoDomain *domain, MonoMethod *method)
2671 {
2672         MonoReflectionParameter **res;
2673         MonoReflectionMethod *member;
2674         MonoClass *oklass;
2675         char **names;
2676         int i;
2677
2678         if (!method->signature->param_count)
2679                 return NULL;
2680
2681         member = mono_method_get_object (domain, method);
2682         names = g_new (char *, method->signature->param_count);
2683         mono_method_get_param_names (method, (const char **) names);
2684         
2685         /* Note: the cache is based on the address of the signature into the method
2686          * since we already cache MethodInfos with the method as keys.
2687          */
2688         CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
2689         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
2690 #if HAVE_BOEHM_GC
2691         res = GC_malloc (sizeof (MonoReflectionParameter*) * method->signature->param_count);
2692 #else
2693         res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
2694 #endif
2695         for (i = 0; i < method->signature->param_count; ++i) {
2696                 res [i] = (MonoReflectionParameter *)mono_object_new (domain, oklass);
2697                 res [i]->ClassImpl = mono_type_get_object (domain, method->signature->params [i]);
2698                 res [i]->DefaultValueImpl = NULL; /* FIXME */
2699                 res [i]->MemberImpl = (MonoObject*)member;
2700                 res [i]->NameImpl = mono_string_new (domain, names [i]);
2701                 res [i]->PositionImpl = i + 1;
2702                 res [i]->AttrsImpl = method->signature->params [i]->attrs;
2703         }
2704         g_free (names);
2705         CACHE_OBJECT (&(method->signature), res);
2706         return res;
2707 }
2708
2709 /*
2710  * mono_reflection_parse_type:
2711  * @name: type name
2712  *
2713  * Parse a type name as accepted by the GetType () method and output the info
2714  * extracted in the info structure.
2715  * the name param will be mangled, so, make a copy before passing it to this function.
2716  * The fields in info will be valid until the memory pointed to by name is valid.
2717  * Returns 0 on parse error.
2718  * See also mono_type_get_name () below.
2719  */
2720 int
2721 mono_reflection_parse_type (char *name, MonoTypeNameParse *info) {
2722
2723         char *start, *p, *w, *last_point;
2724         int in_modifiers = 0;
2725         int isbyref = 0, rank;
2726
2727         start = p = w = name;
2728
2729         info->name = info->name_space = info->assembly = NULL;
2730         info->nested = NULL;
2731         info->modifiers = NULL;
2732
2733         /* last_point separates the namespace from the name */
2734         last_point = NULL;
2735
2736         while (*p) {
2737                 switch (*p) {
2738                 case '+':
2739                         *p = 0; /* NULL terminate the name */
2740                         start = p + 1;
2741                         /* we have parsed the nesting namespace + name */
2742                         if (info->name) {
2743                                 info->nested = g_list_append (info->nested, start);
2744                                 break;
2745                         }
2746                         if (last_point) {
2747                                 info->name_space = start;
2748                                 *last_point = 0;
2749                                 info->name = last_point + 1;
2750                         } else {
2751                                 info->name_space = (char *)"";
2752                                 info->name = start;
2753                         }
2754                         break;
2755                 case '.':
2756                         last_point = w;
2757                         break;
2758                 case '\\':
2759                         ++p;
2760                         break;
2761                 case '&':
2762                 case '*':
2763                 case '[':
2764                 case ',':
2765                         in_modifiers = 1;
2766                         break;
2767                 default:
2768                         break;
2769                 }
2770                 if (in_modifiers)
2771                         break;
2772                 *w++ = *p++;
2773         }
2774         
2775         if (info->name) {
2776                 info->nested = g_list_append (info->nested, start);
2777         } else {
2778                 if (last_point) {
2779                         info->name_space = start;
2780                         *last_point = 0;
2781                         info->name = last_point + 1;
2782                 } else {
2783                         info->name_space = (char *)"";
2784                         info->name = start;
2785                 }
2786         }
2787         while (*p) {
2788                 switch (*p) {
2789                 case '&':
2790                         if (isbyref) /* only one level allowed by the spec */
2791                                 return 0;
2792                         isbyref = 1;
2793                         info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (0));
2794                         *p++ = 0;
2795                         break;
2796                 case '*':
2797                         info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-1));
2798                         *p++ = 0;
2799                         break;
2800                 case '[':
2801                         rank = 1;
2802                         *p++ = 0;
2803                         while (*p) {
2804                                 if (*p == ']')
2805                                         break;
2806                                 if (*p == ',')
2807                                         rank++;
2808                                 else if (*p != '*') /* '*' means unknown lower bound */
2809                                         return 0;
2810                                 ++p;
2811                         }
2812                         if (*p++ != ']')
2813                                 return 0;
2814                         info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank));
2815                         break;
2816                 case ',':
2817                         *p++ = 0;
2818                         while (*p) {
2819                                 if (*p == ' ') {
2820                                         ++p;
2821                                         continue;
2822                                 }
2823                                 break;
2824                         }
2825                         if (!*p)
2826                                 return 0; /* missing assembly name */
2827                         info->assembly = p;
2828                         break;
2829                 default:
2830                         break;
2831                 }
2832         }
2833         *w = 0; /* terminate class name */
2834         if (!info->name || !*info->name)
2835                 return 0;
2836         /* add other consistency checks */
2837         return 1;
2838 }
2839
2840 static void
2841 mono_type_get_name_recurse (MonoType *type, GString *str)
2842 {
2843         MonoClass *klass;
2844         
2845         switch (type->type) {
2846         case MONO_TYPE_ARRAY: {
2847                 int i, rank = type->data.array->rank;
2848
2849                 mono_type_get_name_recurse (type->data.array->type, str);
2850                 g_string_append_c (str, '[');
2851                 for (i = 1; i < rank; i++)
2852                         g_string_append_c (str, ',');
2853                 g_string_append_c (str, ']');
2854                 break;
2855         }
2856         case MONO_TYPE_SZARRAY:
2857                 mono_type_get_name_recurse (type->data.type, str);
2858                 g_string_append (str, "[]");
2859                 break;
2860         case MONO_TYPE_PTR:
2861                 mono_type_get_name_recurse (type->data.type, str);
2862                 g_string_append_c (str, '*');
2863                 break;
2864         default:
2865                 klass = mono_class_from_mono_type (type);
2866                 if (klass->nested_in) {
2867                         mono_type_get_name_recurse (&klass->nested_in->byval_arg, str);
2868                         g_string_append_c (str, '+');
2869                 }
2870                 if (*klass->name_space) {
2871                         g_string_append (str, klass->name_space);
2872                         g_string_append_c (str, '.');
2873                 }
2874                 g_string_append (str, klass->name);
2875                 break;
2876         }
2877 }
2878
2879 /*
2880  * mono_type_get_name:
2881  * @type: a type
2882  *
2883  * Returns the string representation for type as required by System.Reflection.
2884  * The inverse of mono_reflection_parse_type ().
2885  */
2886 char*
2887 mono_type_get_name (MonoType *type)
2888 {
2889         GString* result = g_string_new ("");
2890         mono_type_get_name_recurse (type, result);
2891
2892         if (type->byref)
2893                 g_string_append_c (result, '&');
2894
2895         return g_string_free (result, FALSE);
2896 }
2897
2898 /*
2899  * mono_reflection_get_type:
2900  * @image: a metadata context
2901  * @info: type description structure
2902  * @ignorecase: flag for case-insensitive string compares
2903  *
2904  * Build a MonoType from the type description in @info.
2905  * 
2906  */
2907 MonoType*
2908 mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase)
2909 {
2910         MonoClass *klass;
2911         GList *mod;
2912         int modval;
2913         
2914         if (!image)
2915                 image = mono_defaults.corlib;
2916
2917         if (ignorecase)
2918                 klass = mono_class_from_name_case (image, info->name_space, info->name);
2919         else
2920                 klass = mono_class_from_name (image, info->name_space, info->name);
2921         if (!klass)
2922                 return NULL;
2923         for (mod = info->nested; mod; mod = mod->next) {
2924                 GList *nested;
2925
2926                 mono_class_init (klass);
2927                 nested = klass->nested_classes;
2928                 klass = NULL;
2929                 while (nested) {
2930                         klass = nested->data;
2931                         if (ignorecase) {
2932                                 if (g_strcasecmp (klass->name, mod->data) == 0)
2933                                         break;
2934                         } else {
2935                                 if (strcmp (klass->name, mod->data) == 0)
2936                                         break;
2937                         }
2938                         klass = NULL;
2939                         nested = nested->next;
2940                 }
2941                 if (!klass)
2942                         break;
2943         }
2944         if (!klass)
2945                 return NULL;
2946         mono_class_init (klass);
2947         for (mod = info->modifiers; mod; mod = mod->next) {
2948                 modval = GPOINTER_TO_UINT (mod->data);
2949                 if (!modval) { /* byref: must be last modifier */
2950                         return &klass->this_arg;
2951                 } else if (modval == -1) {
2952                         klass = mono_ptr_class_get (&klass->byval_arg);
2953                 } else { /* array rank */
2954                         klass = mono_array_class_get (&klass->byval_arg, modval);
2955                 }
2956                 mono_class_init (klass);
2957         }
2958         return &klass->byval_arg;
2959 }
2960
2961 /*
2962  * Optimization we could avoid mallocing() an little-endian archs that
2963  * don't crash with unaligned accesses.
2964  */
2965 static void
2966 fill_param_data (MonoImage *image, MonoMethodSignature *sig, guint32 blobidx, void **params) {
2967         int len, i, slen, type;
2968         const char *p = mono_metadata_blob_heap (image, blobidx);
2969
2970         len = mono_metadata_decode_value (p, &p);
2971         if (len < 2 || read16 (p) != 0x0001) /* Prolog */
2972                 return;
2973
2974         /* skip prolog */
2975         p += 2;
2976         for (i = 0; i < sig->param_count; ++i) {
2977                 type = sig->params [i]->type;
2978 handle_enum:
2979                 switch (type) {
2980                 case MONO_TYPE_U1:
2981                 case MONO_TYPE_I1:
2982                 case MONO_TYPE_BOOLEAN: {
2983                         MonoBoolean *bval = params [i] = g_malloc (sizeof (MonoBoolean));
2984                         *bval = *p;
2985                         ++p;
2986                         break;
2987                 }
2988                 case MONO_TYPE_CHAR:
2989                 case MONO_TYPE_U2:
2990                 case MONO_TYPE_I2: {
2991                         guint16 *val = params [i] = g_malloc (sizeof (guint16));
2992                         *val = read16 (p);
2993                         p += 2;
2994                         break;
2995                 }
2996 #if SIZEOF_VOID_P == 4
2997                 case MONO_TYPE_U:
2998                 case MONO_TYPE_I:
2999 #endif
3000                 case MONO_TYPE_R4:
3001                 case MONO_TYPE_U4:
3002                 case MONO_TYPE_I4: {
3003                         guint32 *val = params [i] = g_malloc (sizeof (guint32));
3004                         *val = read32 (p);
3005                         p += 4;
3006                         break;
3007                 }
3008 #if SIZEOF_VOID_P == 8
3009                 case MONO_TYPE_U: /* error out instead? this should probably not happen */
3010                 case MONO_TYPE_I:
3011 #endif
3012                 case MONO_TYPE_R8:
3013                 case MONO_TYPE_U8:
3014                 case MONO_TYPE_I8: {
3015                         guint64 *val = params [i] = g_malloc (sizeof (guint64));
3016                         *val = read64 (p);
3017                         p += 8;
3018                         break;
3019                 }
3020                 case MONO_TYPE_VALUETYPE:
3021                         if (sig->params [i]->data.klass->enumtype) {
3022                                 type = sig->params [i]->data.klass->enum_basetype->type;
3023                                 goto handle_enum;
3024                         } else {
3025                                 g_warning ("generic valutype %s not handled in custom attr value decoding", sig->params [i]->data.klass->name);
3026                         }
3027                         break;
3028                 case MONO_TYPE_STRING: {
3029                         slen = mono_metadata_decode_value (p, &p);
3030                         params [i] = mono_string_new_len (mono_domain_get (), p, slen);
3031                         p += slen;
3032                         break;
3033                 }
3034                 default:
3035                         g_warning ("Type %02x not handled in custom attr value decoding", sig->params [i]->type);
3036                         break;
3037                 }
3038         }
3039 }
3040
3041 static void
3042 free_param_data (MonoMethodSignature *sig, void **params) {
3043         int i;
3044         for (i = 0; i < sig->param_count; ++i) {
3045                 switch (sig->params [i]->type) {
3046                 case MONO_TYPE_BOOLEAN:
3047                 case MONO_TYPE_CHAR:
3048                 case MONO_TYPE_U:
3049                 case MONO_TYPE_I:
3050                 case MONO_TYPE_U1:
3051                 case MONO_TYPE_I1:
3052                 case MONO_TYPE_U2:
3053                 case MONO_TYPE_I2:
3054                 case MONO_TYPE_U4:
3055                 case MONO_TYPE_I4:
3056                 case MONO_TYPE_U8:
3057                 case MONO_TYPE_I8:
3058                 case MONO_TYPE_R8:
3059                 case MONO_TYPE_R4:
3060                 case MONO_TYPE_VALUETYPE:
3061                         g_free (params [i]);
3062                         break;
3063                 default:
3064                         break;
3065                 }
3066         }
3067 }
3068
3069 /*
3070  * Find the method index in the metadata methodDef table.
3071  * Later put these three helper methods in metadata and export them.
3072  */
3073 static guint32
3074 find_method_index (MonoMethod *method) {
3075         MonoClass *klass = method->klass;
3076         int i;
3077
3078         for (i = 0; i < klass->method.count; ++i) {
3079                 if (method == klass->methods [i])
3080                         return klass->method.first + 1 + i;
3081         }
3082         return 0;
3083 }
3084
3085 /*
3086  * Find the field index in the metadata FieldDef table.
3087  */
3088 static guint32
3089 find_field_index (MonoClass *klass, MonoClassField *field) {
3090         int i;
3091
3092         for (i = 0; i < klass->field.count; ++i) {
3093                 if (field == &klass->fields [i])
3094                         return klass->field.first + 1 + i;
3095         }
3096         return 0;
3097 }
3098
3099 /*
3100  * Find the property index in the metadata Property table.
3101  */
3102 static guint32
3103 find_property_index (MonoClass *klass, MonoProperty *property) {
3104         int i;
3105
3106         for (i = 0; i < klass->property.count; ++i) {
3107                 if (property == &klass->properties [i])
3108                         return klass->property.first + 1 + i;
3109         }
3110         return 0;
3111 }
3112
3113 /*
3114  * Find the event index in the metadata Event table.
3115  */
3116 static guint32
3117 find_event_index (MonoClass *klass, MonoEvent *event) {
3118         int i;
3119
3120         for (i = 0; i < klass->event.count; ++i) {
3121                 if (event == &klass->events [i])
3122                         return klass->event.first + 1 + i;
3123         }
3124         return 0;
3125 }
3126
3127 /*
3128  * mono_reflection_get_custom_attrs:
3129  * @obj: a reflection object handle
3130  *
3131  * Return an array with all the custom attributes defined of the
3132  * reflection handle @obj. The objects are fully build.
3133  */
3134 MonoArray*
3135 mono_reflection_get_custom_attrs (MonoObject *obj)
3136 {
3137         guint32 idx, mtoken, i, len;
3138         guint32 cols [MONO_CUSTOM_ATTR_SIZE];
3139         MonoClass *klass;
3140         MonoImage *image;
3141         MonoTableInfo *ca;
3142         MonoMethod *method;
3143         MonoObject *attr;
3144         MonoArray *result;
3145         GList *list = NULL;
3146         void **params;
3147         
3148         klass = obj->vtable->klass;
3149         /* FIXME: need to handle: Module */
3150         if (klass == mono_defaults.monotype_class) {
3151                 MonoReflectionType *rtype = (MonoReflectionType*)obj;
3152                 klass = mono_class_from_mono_type (rtype->type);
3153                 idx = mono_metadata_token_index (klass->type_token);
3154                 idx <<= CUSTOM_ATTR_BITS;
3155                 idx |= CUSTOM_ATTR_TYPEDEF;
3156                 image = klass->image;
3157         } else if (strcmp ("Assembly", klass->name) == 0) {
3158                 MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
3159                 idx = 1; /* there is only one assembly */
3160                 idx <<= CUSTOM_ATTR_BITS;
3161                 idx |= CUSTOM_ATTR_ASSEMBLY;
3162                 image = rassembly->assembly->image;
3163         } else if (strcmp ("MonoProperty", klass->name) == 0) {
3164                 MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj;
3165                 idx = find_property_index (rprop->klass, rprop->property);
3166                 idx <<= CUSTOM_ATTR_BITS;
3167                 idx |= CUSTOM_ATTR_PROPERTY;
3168                 image = rprop->klass->image;
3169         } else if (strcmp ("MonoEvent", klass->name) == 0) {
3170                 MonoReflectionEvent *revent = (MonoReflectionEvent*)obj;
3171                 idx = find_event_index (revent->klass, revent->event);
3172                 idx <<= CUSTOM_ATTR_BITS;
3173                 idx |= CUSTOM_ATTR_EVENT;
3174                 image = revent->klass->image;
3175         } else if (strcmp ("MonoField", klass->name) == 0) {
3176                 MonoReflectionField *rfield = (MonoReflectionField*)obj;
3177                 idx = find_field_index (rfield->klass, rfield->field);
3178                 idx <<= CUSTOM_ATTR_BITS;
3179                 idx |= CUSTOM_ATTR_FIELDDEF;
3180                 image = rfield->klass->image;
3181         } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
3182                 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
3183                 idx = find_method_index (rmethod->method);
3184                 idx <<= CUSTOM_ATTR_BITS;
3185                 idx |= CUSTOM_ATTR_METHODDEF;
3186                 image = rmethod->method->klass->image;
3187         } else if (strcmp ("ParameterInfo", klass->name) == 0) {
3188                 MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
3189                 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl;
3190                 guint32 method_index = find_method_index (rmethod->method);
3191                 guint32 param_list, param_last, param_pos, found;
3192
3193                 image = rmethod->method->klass->image;
3194                 ca = &image->tables [MONO_TABLE_METHOD];
3195
3196                 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
3197                 if (method_index == ca->rows) {
3198                         ca = &image->tables [MONO_TABLE_PARAM];
3199                         param_last = ca->rows + 1;
3200                 } else {
3201                         param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
3202                         ca = &image->tables [MONO_TABLE_PARAM];
3203                 }
3204                 found = 0;
3205                 for (i = param_list; i < param_last; ++i) {
3206                         param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
3207                         if (param_pos == param->PositionImpl) {
3208                                 found = 1;
3209                                 break;
3210                         }
3211                 }
3212                 if (!found)
3213                         return mono_array_new (mono_domain_get (), mono_defaults.object_class, 0);
3214                 idx = i;
3215                 idx <<= CUSTOM_ATTR_BITS;
3216                 idx |= CUSTOM_ATTR_PARAMDEF;
3217         } else { /* handle other types here... */
3218                 g_error ("get custom attrs not yet supported for %s", klass->name);
3219         }
3220
3221         /* at this point image and index are set correctly for searching the custom attr */
3222         ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
3223         /* the table is not sorted */
3224         for (i = 0; i < ca->rows; ++i) {
3225                 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
3226                 if (cols [MONO_CUSTOM_ATTR_PARENT] != idx)
3227                         continue;
3228                 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> CUSTOM_ATTR_TYPE_BITS;
3229                 switch (cols [MONO_CUSTOM_ATTR_TYPE] & CUSTOM_ATTR_TYPE_MASK) {
3230                 case CUSTOM_ATTR_TYPE_METHODDEF:
3231                         mtoken |= MONO_TOKEN_METHOD_DEF;
3232                         break;
3233                 case CUSTOM_ATTR_TYPE_MEMBERREF:
3234                         mtoken |= MONO_TOKEN_MEMBER_REF;
3235                         break;
3236                 default:
3237                         g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
3238                         break;
3239                 }
3240                 method = mono_get_method (image, mtoken, NULL);
3241                 if (!method)
3242                         g_error ("Can't find custom attr constructor");
3243                 mono_class_init (method->klass);
3244                 /*g_print ("got attr %s\n", method->klass->name);*/
3245                 params = g_new (void*, method->signature->param_count);
3246                 fill_param_data (image, method->signature, cols [MONO_CUSTOM_ATTR_VALUE], params);
3247                 attr = mono_object_new (mono_domain_get (), method->klass);
3248                 mono_runtime_invoke (method, attr, params, NULL);
3249                 list = g_list_prepend (list, attr);
3250                 free_param_data (method->signature, params);
3251                 g_free (params);
3252         }
3253
3254         len = g_list_length (list);
3255         /*
3256          * The return type is really object[], but System/Attribute.cs does a cast
3257          * to (Attribute []) and that is not allowed: I'm lazy for now, but we should
3258          * probably fix that.
3259          */
3260         klass = mono_class_from_name (mono_defaults.corlib, "System", "Attribute");
3261         result = mono_array_new (mono_domain_get (), klass, len);
3262         for (i = 0; i < len; ++i) {
3263                 mono_array_set (result, gpointer, i, list->data);
3264                 list = list->next;
3265         }
3266         g_list_free (g_list_first (list));
3267
3268         return result;
3269 }
3270
3271 static MonoMethodSignature*
3272 ctor_builder_to_signature (MonoReflectionCtorBuilder *ctor) {
3273         MonoMethodSignature *sig;
3274         int count, i;
3275
3276         count = ctor->parameters? mono_array_length (ctor->parameters): 0;
3277
3278         sig = g_malloc0 (sizeof (MonoMethodSignature) + sizeof (MonoType*) * count);
3279         sig->hasthis = 1;
3280         sig->param_count = count;
3281         sig->sentinelpos = -1; /* FIXME */
3282         for (i = 0; i < count; ++i) {
3283                 MonoReflectionType *pt = mono_array_get (ctor->parameters, MonoReflectionType*, i);
3284                 sig->params [i] = pt->type;
3285         }
3286         return sig;
3287 }
3288
3289 static void
3290 get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type)
3291 {
3292         MonoClass *klass = mono_object_class (prop);
3293         if (strcmp (klass->name, "PropertyBuilder") == 0) {
3294                 MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *)prop;
3295                 *name = mono_string_to_utf8 (pb->name);
3296                 *type = pb->type->type;
3297         } else {
3298                 MonoReflectionProperty *p = (MonoReflectionProperty *)prop;
3299                 *name = g_strdup (p->property->name);
3300                 if (p->property->get)
3301                         *type = p->property->get->signature->ret;
3302                 else
3303                         *type = p->property->set->signature->params [p->property->set->signature->param_count - 1];
3304         }
3305 }
3306
3307 static void
3308 get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
3309 {
3310         MonoClass *klass = mono_object_class (field);
3311         if (strcmp (klass->name, "FieldBuilder") == 0) {
3312                 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)field;
3313                 *name = mono_string_to_utf8 (fb->name);
3314                 *type = fb->type->type;
3315         } else {
3316                 MonoReflectionField *f = (MonoReflectionField *)field;
3317                 *name = g_strdup (f->field->name);
3318                 *type = f->field->type;
3319         }
3320 }
3321
3322 static char*
3323 type_get_qualified_name (MonoType *type, MonoAssembly *ass) {
3324         char *name, *result;
3325         MonoClass *klass;
3326         MonoAssembly *ta;
3327
3328         name = mono_type_get_name (type);
3329         klass = mono_class_from_mono_type (type);
3330         ta = klass->image->assembly;
3331         if (ta == ass || klass->image == mono_defaults.corlib)
3332                 return name;
3333
3334         /* missing public key */
3335         result = g_strdup_printf ("%s, %s, Version=%d.%d.%d.%d, Culture=%s", 
3336                 name, ta->aname.name,
3337                 ta->aname.major, ta->aname.minor, ta->aname.build, ta->aname.revision,
3338                 ta->aname.culture && *ta->aname.culture? ta->aname.culture: "neutral");
3339         g_free (name);
3340         return result;
3341 }
3342
3343 static void
3344 encode_cattr_value (char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg)
3345 {
3346         char *argval;
3347         MonoTypeEnum simple_type;
3348         
3349         if ((p-buffer) + 10 >= *buflen) {
3350                 char *newbuf;
3351                 *buflen *= 2;
3352                 newbuf = g_realloc (buffer, *buflen);
3353                 p = newbuf + (p-buffer);
3354                 buffer = newbuf;
3355         }
3356         argval = ((char*)arg + sizeof (MonoObject));
3357         simple_type = type->type;
3358 handle_enum:
3359         switch (simple_type) {
3360         case MONO_TYPE_BOOLEAN:
3361         case MONO_TYPE_U1:
3362         case MONO_TYPE_I1:
3363                 *p++ = *argval;
3364                 break;
3365         case MONO_TYPE_CHAR:
3366         case MONO_TYPE_U2:
3367         case MONO_TYPE_I2:
3368                 swap_with_size (p, argval, 2, 1);
3369                 p += 2;
3370                 break;
3371         case MONO_TYPE_U4:
3372         case MONO_TYPE_I4:
3373         case MONO_TYPE_R4:
3374                 swap_with_size (p, argval, 4, 1);
3375                 p += 4;
3376                 break;
3377         case MONO_TYPE_U8:
3378         case MONO_TYPE_I8:
3379         case MONO_TYPE_R8:
3380                 swap_with_size (p, argval, 8, 1);
3381                 p += 8;
3382                 break;
3383         case MONO_TYPE_VALUETYPE:
3384                 if (type->data.klass->enumtype) {
3385                         simple_type = type->data.klass->enum_basetype->type;
3386                         goto handle_enum;
3387                 } else {
3388                         g_warning ("generic valutype %s not handled in custom attr value decoding", type->data.klass->name);
3389                 }
3390                 break;
3391         case MONO_TYPE_STRING: {
3392                 char *str = mono_string_to_utf8 ((MonoString*)arg);
3393                 guint32 slen = strlen (str);
3394                 if ((p-buffer) + 10 + slen >= *buflen) {
3395                         char *newbuf;
3396                         *buflen *= 2;
3397                         *buflen += slen;
3398                         newbuf = g_realloc (buffer, *buflen);
3399                         p = newbuf + (p-buffer);
3400                         buffer = newbuf;
3401                 }
3402                 mono_metadata_encode_value (slen, p, &p);
3403                 memcpy (p, str, slen);
3404                 p += slen;
3405                 g_free (str);
3406                 break;
3407         }
3408         case MONO_TYPE_CLASS: {
3409                 char *str;
3410                 guint32 slen;
3411                 if (!mono_object_isinst (arg, mono_defaults.monotype_class))
3412                         g_error ("only types allowed");
3413 handle_type:
3414                 str = type_get_qualified_name (((MonoReflectionType*)arg)->type, NULL);
3415                 slen = strlen (str);
3416                 if ((p-buffer) + 10 + slen >= *buflen) {
3417                         char *newbuf;
3418                         *buflen *= 2;
3419                         *buflen += slen;
3420                         newbuf = g_realloc (buffer, *buflen);
3421                         p = newbuf + (p-buffer);
3422                         buffer = newbuf;
3423                 }
3424                 mono_metadata_encode_value (slen, p, &p);
3425                 memcpy (p, str, slen);
3426                 p += slen;
3427                 g_free (str);
3428                 break;
3429         }
3430         /* it may be a boxed value or a Type */
3431         case MONO_TYPE_OBJECT: {
3432                 MonoClass *klass = mono_object_class (arg);
3433                 char *str;
3434                 guint32 slen;
3435                 
3436                 if (mono_object_isinst (arg, mono_defaults.monotype_class)) {
3437                         *p++ = 0x50;
3438                         goto handle_type;
3439                 } else if (klass->enumtype) {
3440                         *p++ = 0x55;
3441                 } else if (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8) {
3442                         *p++ = simple_type = klass->byval_arg.type;
3443                         goto handle_enum;
3444                 } else {
3445                         g_error ("unhandled type in custom attr");
3446                 }
3447                 str = type_get_qualified_name (klass->enum_basetype, NULL);
3448                 slen = strlen (str);
3449                 if ((p-buffer) + 10 + slen >= *buflen) {
3450                         char *newbuf;
3451                         *buflen *= 2;
3452                         *buflen += slen;
3453                         newbuf = g_realloc (buffer, *buflen);
3454                         p = newbuf + (p-buffer);
3455                         buffer = newbuf;
3456                 }
3457                 mono_metadata_encode_value (slen, p, &p);
3458                 memcpy (p, str, slen);
3459                 p += slen;
3460                 g_free (str);
3461                 simple_type = klass->enum_basetype->type;
3462                 goto handle_enum;
3463         }
3464         default:
3465                 g_error ("type 0x%02x not yet supported in custom attr encoder", simple_type);
3466         }
3467         *retp = p;
3468         *retbuffer = buffer;
3469 }
3470
3471 /*
3472  * mono_reflection_get_custom_attrs_blob:
3473  * @ctor: custom attribute constructor
3474  * @ctorArgs: arguments o the constructor
3475  * @properties:
3476  * @propValues:
3477  * @fields:
3478  * @fieldValues:
3479  * 
3480  * Creates the blob of data that needs to be saved in the metadata and that represents
3481  * the custom attributed described by @ctor, @ctorArgs etc.
3482  * Returns: a Byte array representing the blob of data.
3483  */
3484 MonoArray*
3485 mono_reflection_get_custom_attrs_blob (MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues) {
3486         MonoArray *result;
3487         MonoMethodSignature *sig;
3488         MonoObject *arg;
3489         char *buffer, *p;
3490         guint32 buflen, i;
3491
3492         if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
3493                 sig = ctor_builder_to_signature ((MonoReflectionCtorBuilder*)ctor);
3494         } else {
3495                 sig = ((MonoReflectionMethod*)ctor)->method->signature;
3496         }
3497         buflen = 256;
3498         p = buffer = g_malloc (buflen);
3499         /* write the prolog */
3500         *p++ = 1;
3501         *p++ = 0;
3502         for (i = 0; i < sig->param_count; ++i) {
3503                 arg = (MonoObject*)mono_array_get (ctorArgs, gpointer, i);
3504                 encode_cattr_value (buffer, p, &buffer, &p, &buflen, sig->params [i], arg);
3505         }
3506         i = 0;
3507         if (properties)
3508                 i += mono_array_length (properties);
3509         if (fields)
3510                 i += mono_array_length (fields);
3511         *p++ = i & 0xff;
3512         *p++ = (i >> 8) & 0xff;
3513         if (properties) {
3514                 MonoObject *prop;
3515                 for (i = 0; i < mono_array_length (properties); ++i) {
3516                         MonoType *ptype;
3517                         char *pname;
3518                         int len;
3519                         
3520                         prop = mono_array_get (properties, gpointer, i);
3521                         get_prop_name_and_type (prop, &pname, &ptype);
3522                         *p++ = 0x54; /* PROPERTY signature */
3523                         len = strlen (pname);
3524                         mono_metadata_encode_value (len, p, &p);
3525                         memcpy (p, pname, len);
3526                         p += len;
3527                         encode_cattr_value (buffer, p, &buffer, &p, &buflen, ptype, (MonoObject*)mono_array_get (propValues, gpointer, i));
3528                         g_free (pname);
3529                 }
3530         }
3531
3532         if (fields) {
3533                 MonoObject *field;
3534                 for (i = 0; i < mono_array_length (fields); ++i) {
3535                         MonoType *ftype;
3536                         char *fname;
3537                         int len;
3538                         
3539                         field = mono_array_get (fields, gpointer, i);
3540                         get_field_name_and_type (field, &fname, &ftype);
3541                         *p++ = 0x53; /* FIELD signature */
3542                         len = strlen (fname);
3543                         mono_metadata_encode_value (len, p, &p);
3544                         memcpy (p, fname, len);
3545                         p += len;
3546                         encode_cattr_value (buffer, p, &buffer, &p, &buflen, ftype, (MonoObject*)mono_array_get (fieldValues, gpointer, i));
3547                         g_free (fname);
3548                 }
3549         }
3550
3551         g_assert (p - buffer <= buflen);
3552         buflen = p - buffer;
3553         result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
3554         p = mono_array_addr (result, char, 0);
3555         memcpy (p, buffer, buflen);
3556         g_free (buffer);
3557         if (strcmp (ctor->vtable->klass->name, "MonoCMethod"))
3558                 g_free (sig);
3559         return result;
3560 }
3561
3562 /*
3563  * mono_reflection_setup_internal_class:
3564  * @tb: a TypeBuilder object
3565  *
3566  * Creates a MonoClass that represents the TypeBuilder.
3567  * This is a trick that lets us simplify a lot of reflection code
3568  * (and will allow us to support Build and Run assemblies easier).
3569  */
3570 void
3571 mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
3572 {
3573         MonoClass *klass, *parent;
3574
3575         klass = g_new0 (MonoClass, 1);
3576
3577         klass->image = tb->module->assemblyb->dynamic_assembly->assembly.image;
3578
3579         if (tb->parent)
3580                 parent = mono_class_from_mono_type (tb->parent->type);
3581         else
3582                 parent = NULL;
3583         
3584         klass->inited = 1; /* we lie to the runtime */
3585         klass->name = mono_string_to_utf8 (tb->name);
3586         klass->name_space = mono_string_to_utf8 (tb->nspace);
3587         klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx;
3588         klass->flags = tb->attrs;
3589
3590         klass->element_class = klass;
3591         klass->reflection_info = tb; /* need to pin. */
3592
3593         if (parent != NULL)
3594                 mono_class_setup_parent (klass, parent);
3595         mono_class_setup_mono_type (klass);
3596
3597         /*
3598          * FIXME: handle interfaces.
3599          */
3600
3601         tb->type.type = &klass->byval_arg;
3602
3603         /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/
3604 }
3605
3606 /*
3607  * mono_reflection_create_internal_class:
3608  * @tb: a TypeBuilder object
3609  *
3610  * Actually create the MonoClass that is associated with the TypeBuilder.
3611  */
3612 void
3613 mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
3614 {
3615         MonoClass *klass;
3616
3617         klass = mono_class_from_mono_type (tb->type.type);
3618
3619         if (klass->enumtype && klass->enum_basetype == NULL) {
3620                 MonoReflectionFieldBuilder *fb;
3621
3622                 g_assert (tb->fields != NULL);
3623                 g_assert (mono_array_length (tb->fields) >= 1);
3624
3625                 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, 0);
3626
3627                 klass->enum_basetype = fb->type->type;
3628                 klass->element_class = mono_class_from_mono_type (klass->enum_basetype);
3629         }
3630 }
3631
3632 MonoArray *
3633 mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
3634 {
3635         MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly;
3636         guint32 na = mono_array_length (sig->arguments);
3637         guint32 buflen, i;
3638         MonoArray *result;
3639         char *buf, *p;
3640
3641         p = buf = g_malloc (10 + na * 10);
3642
3643         mono_metadata_encode_value (0x07, p, &p);
3644         mono_metadata_encode_value (na, p, &p);
3645         for (i = 0; i < na; ++i) {
3646                 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i);
3647                 encode_reflection_type (assembly, type, p, &p);
3648         }
3649
3650         buflen = p - buf;
3651         result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
3652         p = mono_array_addr (result, char, 0);
3653         memcpy (p, buf, buflen);
3654         g_free (buf);
3655
3656         return result;
3657 }
3658
3659 MonoArray *
3660 mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig)
3661 {
3662         MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly;
3663         guint32 na = mono_array_length (sig->arguments);
3664         guint32 buflen, i;
3665         MonoArray *result;
3666         char *buf, *p;
3667
3668         p = buf = g_malloc (10 + na * 10);
3669
3670         mono_metadata_encode_value (0x06, p, &p);
3671         for (i = 0; i < na; ++i) {
3672                 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i);
3673                 encode_reflection_type (assembly, type, p, &p);
3674         }
3675
3676         buflen = p - buf;
3677         result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
3678         p = mono_array_addr (result, char, 0);
3679         memcpy (p, buf, buflen);
3680         g_free (buf);
3681
3682         return result;
3683 }
3684