Wed Feb 13 18:25:55 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / reflection.c
1
2 /*
3  * reflection.c: Routines for creating an image at runtime.
4  * 
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001, 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 <stdio.h>
16 #include <glib.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <string.h>
20 #include "image.h"
21 #include "cil-coff.h"
22 #include "rawbuffer.h"
23 #include "mono-endian.h"
24 #include "private.h"
25
26 #define TEXT_OFFSET 512
27 #define CLI_H_SIZE 136
28 #define FILE_ALIGN 512
29
30 typedef struct {
31         MonoReflectionILGen *ilgen;
32         MonoReflectionType *rtype;
33         MonoArray *parameters;
34         MonoArray *pinfo;
35         guint32 attrs;
36         guint32 iattrs;
37         guint32 call_conv;
38         guint32 *table_idx; /* note: it's a pointer */
39         MonoArray *code;
40         MonoObject *type;
41         MonoString *name;
42 } ReflectionMethodBuilder;
43
44 const unsigned char table_sizes [64] = {
45         MONO_MODULE_SIZE,
46         MONO_TYPEREF_SIZE,
47         MONO_TYPEDEF_SIZE,
48         0,
49         MONO_FIELD_SIZE,
50         0,
51         MONO_METHOD_SIZE,
52         0,
53         MONO_PARAM_SIZE,
54         MONO_INTERFACEIMPL_SIZE,
55         MONO_MEMBERREF_SIZE,    /* 0x0A */
56         MONO_CONSTANT_SIZE,
57         MONO_CUSTOM_ATTR_SIZE,
58         MONO_FIELD_MARSHAL_SIZE,
59         MONO_DECL_SECURITY_SIZE,
60         MONO_CLASS_LAYOUT_SIZE,
61         MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
62         MONO_STAND_ALONE_SIGNATURE_SIZE,
63         MONO_EVENT_MAP_SIZE,
64         0,
65         MONO_EVENT_SIZE,
66         MONO_PROPERTY_MAP_SIZE,
67         0,
68         MONO_PROPERTY_SIZE,
69         MONO_METHOD_SEMA_SIZE,
70         MONO_MTHODIMPL_SIZE,
71         MONO_MODULEREF_SIZE,    /* 0x1A */
72         MONO_TYPESPEC_SIZE,
73         MONO_IMPLMAP_SIZE,      
74         MONO_FIELD_RVA_SIZE,
75         0,
76         0,
77         MONO_ASSEMBLY_SIZE,     /* 0x20 */
78         MONO_ASSEMBLY_PROCESSOR_SIZE,
79         MONO_ASSEMBLYOS_SIZE,
80         MONO_ASSEMBLYREF_SIZE,
81         MONO_ASSEMBLYREFPROC_SIZE,
82         MONO_ASSEMBLYREFOS_SIZE,
83         MONO_FILE_SIZE,
84         MONO_EXP_TYPE_SIZE,
85         MONO_MANIFEST_SIZE,
86         MONO_NESTED_CLASS_SIZE,
87         0       /* 0x2A */
88 };
89
90 static guint32 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type);
91 static guint32 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method);
92
93 static void
94 alloc_table (MonoDynamicTable *table, guint nrows)
95 {
96         table->rows = nrows;
97         g_assert (table->columns);
98         table->values = g_realloc (table->values, (1 + table->rows) * table->columns * sizeof (guint32));
99 }
100
101 static guint32
102 string_heap_insert (MonoStringHeap *sh, const char *str)
103 {
104         guint32 idx;
105         guint32 len;
106         gpointer oldkey, oldval;
107
108         if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
109                 return GPOINTER_TO_UINT (oldval);
110
111         len = strlen (str) + 1;
112         idx = sh->index;
113         if (idx + len > sh->alloc_size) {
114                 sh->alloc_size += len + 4096;
115                 sh->data = g_realloc (sh->data, sh->alloc_size);
116         }
117         /*
118          * We strdup the string even if we already copy them in sh->data
119          * so that the string pointers in the hash remain valid even if
120          * we need to realloc sh->data. We may want to avoid that later.
121          */
122         g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
123         memcpy (sh->data + idx, str, len);
124         sh->index += len;
125         return idx;
126 }
127
128 static void
129 string_heap_init (MonoStringHeap *sh)
130 {
131         sh->index = 0;
132         sh->alloc_size = 4096;
133         sh->data = g_malloc (4096);
134         sh->hash = g_hash_table_new (g_str_hash, g_str_equal);
135         string_heap_insert (sh, "");
136 }
137
138 static void
139 string_heap_free (MonoStringHeap *sh)
140 {
141         g_free (sh->data);
142         g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL);
143         g_hash_table_destroy (sh->hash);
144 }
145
146 static guint32
147 mono_image_add_stream_data (MonoDynamicStream *stream, char *data, guint32 len)
148 {
149         guint32 idx;
150         if (stream->alloc_size < stream->index + len) {
151                 stream->alloc_size += len + 4096;
152                 stream->data = g_realloc (stream->data, stream->alloc_size);
153         }
154         memcpy (stream->data + stream->index, data, len);
155         idx = stream->index;
156         stream->index += len;
157         /* 
158          * align index? Not without adding an additional param that controls it since
159          * we may store a blob value in pieces.
160          */
161         return idx;
162 }
163
164 static void
165 stream_data_align (MonoDynamicStream *stream)
166 {
167         char buf [4] = {0};
168         guint32 count = stream->index % 4;
169
170         /* we assume the stream data will be aligned */
171         if (count)
172                 mono_image_add_stream_data (stream, buf, 4 - count);
173 }
174
175 static void
176 encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endbuf)
177 {
178         if (!type) {
179                 g_assert_not_reached ();
180                 return;
181         }
182                 
183         if (type->byref)
184                 mono_metadata_encode_value (MONO_TYPE_BYREF, p, &p);
185
186         switch (type->type){
187         case MONO_TYPE_VOID:
188         case MONO_TYPE_BOOLEAN:
189         case MONO_TYPE_CHAR:
190         case MONO_TYPE_I1:
191         case MONO_TYPE_U1:
192         case MONO_TYPE_I2:
193         case MONO_TYPE_U2:
194         case MONO_TYPE_I4:
195         case MONO_TYPE_U4:
196         case MONO_TYPE_I8:
197         case MONO_TYPE_U8:
198         case MONO_TYPE_R4:
199         case MONO_TYPE_R8:
200         case MONO_TYPE_I:
201         case MONO_TYPE_U:
202         case MONO_TYPE_STRING:
203         case MONO_TYPE_OBJECT:
204         case MONO_TYPE_TYPEDBYREF:
205                 mono_metadata_encode_value (type->type, p, &p);
206                 break;
207         case MONO_TYPE_SZARRAY:
208                 mono_metadata_encode_value (type->type, p, &p);
209                 encode_type (assembly, type->data.type, p, &p);
210                 break;
211         case MONO_TYPE_VALUETYPE:
212         case MONO_TYPE_CLASS:
213                 mono_metadata_encode_value (type->type, p, &p);
214                 mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, type), p, &p);
215                 break;
216         default:
217                 g_error ("need to encode type %x", type->type);
218         }
219         *endbuf = p;
220 }
221
222 static void
223 encode_reflection_type (MonoDynamicAssembly *assembly, MonoReflectionType *type, char *p, char **endbuf)
224 {
225         MonoReflectionTypeBuilder *tb;
226         guint32 token;
227
228         if (!type) {
229                 mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf);
230                 return;
231         }
232         if (type->type) {
233                 encode_type (assembly, type->type, p, endbuf);
234                 return;
235         }
236
237         tb = (MonoReflectionTypeBuilder*) type;
238         token = TYPEDEFORREF_TYPEDEF | (tb->table_idx << TYPEDEFORREF_BITS); /* typedef */
239
240         /* FIXME: handle other base types (need to have also some hacks to compile corlib) ... */
241         /* FIXME: handle byref ... */
242         mono_metadata_encode_value (MONO_TYPE_CLASS, p, &p);
243         mono_metadata_encode_value (token, p, endbuf);
244         /*g_print ("encoding type %s to 0x%08x\n", mono_string_to_utf8 (tb->name), token);*/
245 }
246
247 static guint32
248 method_encode_signature (MonoDynamicAssembly *assembly, MonoMethodSignature *sig)
249 {
250         char *buf;
251         char *p;
252         int i;
253         guint32 nparams =  sig->param_count;
254         guint32 size = 10 + nparams * 10;
255         guint32 idx;
256         char blob_size [6];
257         char *b = blob_size;
258         
259         p = buf = g_malloc (size);
260         /*
261          * FIXME: vararg, explicit_this, differenc call_conv values...
262          */
263         *p = sig->call_convention;
264         if (sig->hasthis)
265                 *p |= 0x20; /* hasthis */
266         p++;
267         mono_metadata_encode_value (nparams, p, &p);
268         encode_type (assembly, sig->ret, p, &p);
269         for (i = 0; i < nparams; ++i)
270                 encode_type (assembly, sig->params [i], p, &p);
271         /* store length */
272         mono_metadata_encode_value (p-buf, b, &b);
273         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
274         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
275         g_free (buf);
276         return idx;
277 }
278
279 static guint32
280 method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
281 {
282         /*
283          * FIXME: reuse code from method_encode_signature().
284          */
285         char *buf;
286         char *p;
287         int i;
288         guint32 nparams =  mb->parameters ? mono_array_length (mb->parameters): 0;
289         guint32 size = 10 + nparams * 10;
290         guint32 idx;
291         char blob_size [6];
292         char *b = blob_size;
293         
294         p = buf = g_malloc (size);
295         /* LAMESPEC: all the call conv spec is foobared */
296         *p = mb->call_conv & 0x60; /* has-this, explicit-this */
297         if (mb->call_conv & 2)
298                 *p |= 0x5; /* vararg */
299         if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
300                 *p |= 0x20; /* hasthis */
301         p++;
302         mono_metadata_encode_value (nparams, p, &p);
303         encode_reflection_type (assembly, mb->rtype, p, &p);
304         for (i = 0; i < nparams; ++i) {
305                 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
306                 encode_reflection_type (assembly, pt, p, &p);
307         }
308         /* store length */
309         mono_metadata_encode_value (p-buf, b, &b);
310         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
311         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
312         g_free (buf);
313         return idx;
314 }
315
316 static guint32
317 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
318 {
319         MonoDynamicTable *table;
320         guint32 *values;
321         char *p;
322         guint32 idx, sig_idx;
323         guint nl = mono_array_length (ilgen->locals);
324         char *buf;
325         char blob_size [6];
326         char *b = blob_size;
327         int i;
328
329         p = buf = g_malloc (10 + nl * 10);
330         table = &assembly->tables [MONO_TABLE_STANDALONESIG];
331         idx = table->next_idx ++;
332         table->rows ++;
333         alloc_table (table, table->rows);
334         values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
335
336         mono_metadata_encode_value (0x07, p, &p);
337         mono_metadata_encode_value (nl, p, &p);
338         for (i = 0; i < nl; ++i) {
339                 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
340                 encode_reflection_type (assembly, lb->type, p, &p);
341         }
342         mono_metadata_encode_value (p-buf, b, &b);
343         sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
344         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
345         g_free (buf);
346
347         values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
348
349         return idx;
350 }
351
352 static guint32
353 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
354 {
355         /* we use only tiny formats now: need  to implement ILGenerator */
356         char flags = 0;
357         guint32 idx;
358         guint32 code_size;
359         gint32 max_stack, i;
360         gint32 num_locals = 0;
361         gint32 num_exception = 0;
362         gint maybe_small;
363         guint32 fat_flags;
364         char fat_header [12];
365         guint32 *intp;
366         guint16 *shortp;
367         guint32 local_sig = 0;
368         guint32 header_size = 12;
369         MonoArray *code;
370
371         if ((mb->attrs & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
372                         (mb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
373                         (mb->iattrs & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
374                         (mb->attrs & METHOD_ATTRIBUTE_ABSTRACT))
375                 return 0;
376
377         /*if (mb->name)
378                 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
379         if (mb->ilgen) {
380                 code = mb->ilgen->code;
381                 code_size = mb->ilgen->code_len;
382                 max_stack = mb->ilgen->max_stack;
383                 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
384                 if (mb->ilgen->ex_handlers) {
385                         MonoILExceptionInfo *ex_info;
386                         for (i = 0; i < mono_array_length (mb->ilgen->ex_handlers); ++i) {
387                                 ex_info = (MonoILExceptionInfo*)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
388                                 if (ex_info->handlers)
389                                         num_exception += mono_array_length (ex_info->handlers);
390                                 else
391                                         num_exception++;
392                         }
393                 }
394         } else {
395                 code = mb->code;
396                 code_size = mono_array_length (code);
397                 max_stack = 8; /* we probably need to run a verifier on the code... */
398         }
399
400         /* check for exceptions, maxstack, locals */
401         maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
402         if (maybe_small) {
403                 if (code_size < 64 && !(code_size & 1)) {
404                         flags = (code_size << 2) | 0x2;
405                 } else if (code_size < 32 && (code_size & 1)) {
406                         flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
407                 } else {
408                         goto fat_header;
409                 }
410                 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
411                 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
412                 return assembly->text_rva + idx + CLI_H_SIZE;
413         } 
414 fat_header:
415         if (num_locals)
416                 local_sig = MONO_TOKEN_SIGNATURE | encode_locals (assembly, mb->ilgen);
417         /* 
418          * FIXME: need to set also the header size in fat_flags.
419          * (and more sects and init locals flags)
420          */
421         fat_flags =  0x03;
422         if (num_exception)
423                 fat_flags |= METHOD_HEADER_MORE_SECTS;
424         fat_header [0] = fat_flags;
425         fat_header [1] = (header_size / 4 ) << 4;
426         shortp = (guint16*)(fat_header + 2);
427         *shortp = max_stack;
428         intp = (guint32*)(fat_header + 4);
429         *intp = code_size;
430         intp = (guint32*)(fat_header + 8);
431         *intp = local_sig;
432         idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
433         mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
434         if (num_exception) {
435                 unsigned char sheader [4];
436                 MonoExceptionClause clause;
437                 MonoILExceptionInfo * ex_info;
438                 MonoILExceptionBlock * ex_block;
439                 int j;
440
441                 stream_data_align (&assembly->code);
442                 /* always use fat format for now */
443                 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
444                 num_exception *= sizeof (MonoExceptionClause);
445                 sheader [1] = num_exception & 0xff;
446                 sheader [2] = (num_exception >> 8) & 0xff;
447                 sheader [3] = (num_exception >> 16) & 0xff;
448                 mono_image_add_stream_data (&assembly->code, sheader, 4);
449                 /* fat header, so we are already aligned */
450                 /* reverse order */
451                 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
452                         ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
453                         if (ex_info->handlers) {
454                                 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
455                                         ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
456                                         clause.flags = ex_block->type;
457                                         clause.try_offset = ex_info->start;
458                                         clause.try_len = ex_info->len;
459                                         clause.handler_offset = ex_block->start;
460                                         clause.handler_len = ex_block->len;
461                                         clause.token_or_filter = ex_block->extype ? mono_metadata_token_from_dor (
462                                                         mono_image_typedef_or_ref (assembly, ex_block->extype->type)): 0;
463                                         /* FIXME: ENOENDIAN */
464                                         mono_image_add_stream_data (&assembly->code, (char*)&clause, sizeof (clause));
465                                 }
466                         } else {
467                                 g_error ("No clauses");
468                         }
469                 }
470         }
471         return assembly->text_rva + idx + CLI_H_SIZE;
472 }
473
474 static guint32
475 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index)
476 {
477         int i;
478         MonoDynamicTable *table;
479         guint32 *values;
480         
481         table = &assembly->tables [table_idx];
482
483         g_assert (col < table->columns);
484
485         values = table->values + table->columns;
486         for (i = 1; i <= table->rows; ++i) {
487                 if (values [col] == index)
488                         return i;
489         }
490         return 0;
491 }
492
493 static void
494 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
495 {
496         MonoDynamicTable *table;
497         guint32 *values;
498         char *name;
499         guint i, count;
500
501         /* room in this table is already allocated */
502         table = &assembly->tables [MONO_TABLE_METHOD];
503         *mb->table_idx = table->next_idx ++;
504         values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
505         if (mb->name) {
506                 name = mono_string_to_utf8 (mb->name);
507                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
508                 g_free (name);
509         } else { /* a constructor */
510                 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
511         }
512         values [MONO_METHOD_FLAGS] = mb->attrs;
513         values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
514         values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
515         values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
516         
517         table = &assembly->tables [MONO_TABLE_PARAM];
518         values [MONO_METHOD_PARAMLIST] = table->next_idx;
519
520         if (mb->pinfo) {
521                 count = 0;
522                 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
523                         if (mono_array_get (mb->pinfo, gpointer, i))
524                                 count++;
525                 }
526                 table->rows += count;
527                 alloc_table (table, table->rows);
528                 values = table->values + table->next_idx * MONO_PARAM_SIZE;
529                 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
530                         MonoReflectionParamBuilder *pb;
531                         if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
532                                 values [MONO_PARAM_FLAGS] = pb->attrs;
533                                 values [MONO_PARAM_SEQUENCE] = i;
534                                 name = mono_string_to_utf8 (pb->name);
535                                 values [MONO_PARAM_NAME] = string_heap_insert (&assembly->sheap, name);
536                                 g_free (name);
537                                 values += MONO_PARAM_SIZE;
538                                 table->next_idx++;
539                         }
540                 }
541         }
542 }
543
544 static void
545 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
546 {
547         MonoDynamicTable *table;
548         guint32 *values;
549         char *name;
550         ReflectionMethodBuilder rmb;
551
552         rmb.ilgen = mb->ilgen;
553         rmb.rtype = mb->rtype;
554         rmb.parameters = mb->parameters;
555         rmb.pinfo = mb->pinfo;
556         rmb.attrs = mb->attrs;
557         rmb.iattrs = mb->iattrs;
558         rmb.call_conv = mb->call_conv;
559         rmb.code = mb->code;
560         rmb.type = mb->type;
561         rmb.name = mb->name;
562         rmb.table_idx = &mb->table_idx;
563
564         mono_image_basic_method (&rmb, assembly);
565
566         if (mb->dll) { /* It's a P/Invoke method */
567                 guint32 moduleref;
568                 table = &assembly->tables [MONO_TABLE_IMPLMAP];
569                 table->rows ++;
570                 alloc_table (table, table->rows);
571                 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
572                 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
573                 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
574                 name = mono_string_to_utf8 (mb->dllentry);
575                 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
576                 g_free (name);
577                 name = mono_string_to_utf8 (mb->dll);
578                 moduleref = string_heap_insert (&assembly->sheap, name);
579                 g_free (name);
580                 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
581                         table = &assembly->tables [MONO_TABLE_MODULEREF];
582                         table->rows ++;
583                         alloc_table (table, table->rows);
584                         table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
585                         values [MONO_IMPLMAP_SCOPE] = table->rows;
586                 }
587         }
588         if (mb->override_method) {
589                 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
590                 table = &assembly->tables [MONO_TABLE_METHODIMPL];
591                 table->rows ++;
592                 alloc_table (table, table->rows);
593                 values = table->values + table->rows * MONO_MTHODIMPL_SIZE;
594                 values [MONO_MTHODIMPL_CLASS] = tb->table_idx;
595                 values [MONO_MTHODIMPL_BODY] = METHODDEFORREF_METHODDEF | (mb->table_idx << METHODDEFORREF_BITS);
596                 if (mb->override_method->method)
597                         values [MONO_MTHODIMPL_DECLARATION] = mono_image_get_methodref_token (assembly, mb->override_method->method);
598                 else {
599                         MonoReflectionMethodBuilder *omb = (MonoReflectionMethodBuilder*)mb->override_method;
600                         values [MONO_MTHODIMPL_DECLARATION] = METHODDEFORREF_METHODDEF | (omb->table_idx << METHODDEFORREF_BITS);
601                 }
602         }
603 }
604
605 static void
606 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
607 {
608         ReflectionMethodBuilder rmb;
609
610         rmb.ilgen = mb->ilgen;
611         rmb.rtype = mono_type_get_object (domain, &mono_defaults.void_class->byval_arg);
612         rmb.parameters = mb->parameters;
613         rmb.pinfo = mb->pinfo;
614         rmb.attrs = mb->attrs;
615         rmb.iattrs = mb->iattrs;
616         rmb.call_conv = mb->call_conv;
617         rmb.code = NULL;
618         rmb.type = mb->type;
619         rmb.name = NULL;
620         rmb.table_idx = &mb->table_idx;
621
622         mono_image_basic_method (&rmb, assembly);
623
624 }
625
626 static guint32
627 fieldref_encode_signature (MonoDynamicAssembly *assembly, MonoClassField *field)
628 {
629         char blob_size [64];
630         char *b = blob_size;
631         char *p;
632         char* buf;
633         guint32 idx;
634         
635         p = buf = g_malloc (64);
636         
637         /* No start code with field refs...
638          * mono_metadata_encode_value (0x06, p, &p);
639          */
640         /* encode custom attributes before the type */
641         encode_type (assembly, field->type, p, &p);
642         g_assert (p-buf < 64);
643         mono_metadata_encode_value (p-buf, b, &b);
644         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
645         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
646         g_free (buf);
647         return idx;
648 }
649
650 static guint32
651 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
652 {
653         char blob_size [64];
654         char *b = blob_size;
655         char *p;
656         char* buf;
657         guint32 idx;
658         
659         p = buf = g_malloc (64);
660         
661         mono_metadata_encode_value (0x06, p, &p);
662         /* encode custom attributes before the type */
663         encode_reflection_type (assembly, fb->type, p, &p);
664         g_assert (p-buf < 64);
665         mono_metadata_encode_value (p-buf, b, &b);
666         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
667         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
668         g_free (buf);
669         return idx;
670 }
671
672 static guint32
673 encode_constant (MonoDynamicAssembly *assembly, MonoObject *val, guint32 *ret_type) {
674         char blob_size [64];
675         char *b = blob_size;
676         char *p, *box_val;
677         char* buf;
678         guint32 idx, len;
679         
680         p = buf = g_malloc (64);
681
682         box_val = ((char*)val) + sizeof (MonoObject);
683         *ret_type = val->vtable->klass->byval_arg.type;
684         switch (*ret_type) {
685         case MONO_TYPE_BOOLEAN:
686         case MONO_TYPE_U1:
687         case MONO_TYPE_I1:
688                 len = 1;
689                 break;
690         case MONO_TYPE_CHAR:
691         case MONO_TYPE_U2:
692         case MONO_TYPE_I2:
693                 len = 2;
694                 break;
695         case MONO_TYPE_U4:
696         case MONO_TYPE_I4:
697         case MONO_TYPE_R4:
698                 len = 4;
699                 break;
700         case MONO_TYPE_U8:
701         case MONO_TYPE_I8:
702         case MONO_TYPE_R8:
703                 len = 8;
704                 break;
705         case MONO_TYPE_STRING:
706         default:
707                 g_error ("we don't encode constant type 0x%02x yet", *ret_type);
708         }
709
710         /* there is no signature */
711         mono_metadata_encode_value (len, b, &b);
712         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
713         /* FIXME: ENOENDIAN */
714         mono_image_add_stream_data (&assembly->blob, box_val, len);
715
716         g_free (buf);
717         return idx;
718 }
719
720 static void
721 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
722 {
723         MonoDynamicTable *table;
724         guint32 *values;
725         char *name;
726
727         table = &assembly->tables [MONO_TABLE_FIELD];
728         fb->table_idx = table->next_idx ++;
729         values = table->values + fb->table_idx * MONO_FIELD_SIZE;
730         name = mono_string_to_utf8 (fb->name);
731         values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
732         g_free (name);
733         values [MONO_FIELD_FLAGS] = fb->attrs;
734         values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
735
736         if (fb->offset != -1) {
737                 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
738                 table->rows ++;
739                 alloc_table (table, table->rows);
740                 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
741                 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
742                 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
743         }
744         if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
745                 guint32 field_type = 0;
746                 table = &assembly->tables [MONO_TABLE_CONSTANT];
747                 table->rows ++;
748                 alloc_table (table, table->rows);
749                 values = table->values + table->rows * MONO_CONSTANT_SIZE;
750                 values [MONO_CONSTANT_PARENT] = HASCONSTANT_FIEDDEF | (fb->table_idx << HASCONSTANT_BITS);
751                 values [MONO_CONSTANT_VALUE] = encode_constant (assembly, fb->def_value, &field_type);
752                 values [MONO_CONSTANT_TYPE] = field_type;
753                 values [MONO_CONSTANT_PADDING] = 0;
754         }
755 }
756
757 static guint32
758 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
759 {
760         char *buf, *p;
761         char blob_size [6];
762         char *b = blob_size;
763         guint32 nparams = 0;
764         MonoReflectionMethodBuilder *mb = fb->get_method;
765         guint32 idx, i;
766
767         if (mb && mb->parameters)
768                 nparams = mono_array_length (mb->parameters);
769         buf = p = g_malloc (24 + nparams * 10);
770         *p = 0x08;
771         p++;
772         mono_metadata_encode_value (nparams, p, &p);
773         if (mb) {
774                 encode_reflection_type (assembly, mb->rtype, p, &p);
775                 for (i = 0; i < nparams; ++i) {
776                         MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
777                         encode_reflection_type (assembly, pt, p, &p);
778                 }
779         } else {
780                 *p++ = 1; /* void: a property should probably not be allowed without a getter */
781         }
782         /* store length */
783         mono_metadata_encode_value (p-buf, b, &b);
784         idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
785         mono_image_add_stream_data (&assembly->blob, buf, p-buf);
786         g_free (buf);
787         return idx;
788 }
789
790 static void
791 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
792 {
793         MonoDynamicTable *table;
794         guint32 *values;
795         char *name;
796         guint num_methods = 0;
797         guint32 semaidx;
798
799         /* 
800          * we need to set things in the following tables:
801          * PROPERTYMAP (info already filled in _get_type_info ())
802          * PROPERTY    (rows already preallocated in _get_type_info ())
803          * METHOD      (method info already done with the generic method code)
804          * METHODSEMANTICS
805          */
806         table = &assembly->tables [MONO_TABLE_PROPERTY];
807         pb->table_idx = table->next_idx ++;
808         values = table->values + pb->table_idx * MONO_FIELD_SIZE;
809         name = mono_string_to_utf8 (pb->name);
810         values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
811         g_free (name);
812         values [MONO_PROPERTY_FLAGS] = pb->attrs;
813         values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
814
815         /* FIXME: we still don't handle 'other' methods */
816         if (pb->get_method) num_methods ++;
817         if (pb->set_method) num_methods ++;
818
819         table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
820         table->rows += num_methods;
821         alloc_table (table, table->rows);
822
823         if (pb->get_method) {
824                 semaidx = table->next_idx ++;
825                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
826                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
827                 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
828                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
829         }
830         if (pb->set_method) {
831                 semaidx = table->next_idx ++;
832                 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
833                 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
834                 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
835                 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
836         }
837 }
838
839 static guint32
840 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
841 {
842         if (image != mono_defaults.corlib)
843                 g_error ("multiple assemblyref not yet supported");
844         /* first row in assemblyref */
845         return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF;
846 }
847
848 static guint32
849 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
850 {
851         MonoDynamicTable *table;
852         guint32 *values;
853         guint32 token;
854         MonoClass *klass;
855
856         if (!assembly->typeref)
857                 assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal);
858         
859         token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
860         if (token)
861                 return token;
862         klass = type->data.klass;
863         /*
864          * If it's in the same module:
865          * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS)
866          */
867
868         table = &assembly->tables [MONO_TABLE_TYPEREF];
869         alloc_table (table, table->rows + 1);
870         values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
871         values [MONO_TYPEREF_SCOPE] = resolution_scope_from_image (assembly, klass->image);
872         values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
873         values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
874         token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
875         g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
876         table->next_idx ++;
877         return token;
878 }
879
880 static guint32
881 mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoClass *klass, const char *name, guint32 sig)
882 {
883         MonoDynamicTable *table;
884         guint32 *values;
885         guint32 token, pclass;
886         guint32 parent;
887
888         /*
889          * FIXME: we need to cache the token.
890          */
891         parent = mono_image_typedef_or_ref (assembly, &klass->byval_arg);
892         switch (parent & TYPEDEFORREF_MASK) {
893         case TYPEDEFORREF_TYPEREF:
894                 pclass = MEMBERREF_PARENT_TYPEREF;
895                 break;
896         case TYPEDEFORREF_TYPESPEC:
897                 pclass = MEMBERREF_PARENT_TYPESPEC;
898                 break;
899         case TYPEDEFORREF_TYPEDEF:
900                 /* should never get here */
901         default:
902                 g_error ("unknow typeref or def token");
903         }
904         /* extract the index */
905         parent >>= TYPEDEFORREF_BITS;
906
907         table = &assembly->tables [MONO_TABLE_MEMBERREF];
908         alloc_table (table, table->rows + 1);
909         values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
910         values [MONO_MEMBERREF_CLASS] = pclass | (parent << MEMBERREF_PARENT_BITS);
911         values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
912         values [MONO_MEMBERREF_SIGNATURE] = sig;
913         token = MONO_TOKEN_MEMBER_REF | table->next_idx;
914         table->next_idx ++;
915
916         return token;
917 }
918
919 static guint32
920 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method)
921 {
922         return mono_image_get_memberref_token (assembly, method->klass, 
923                 method->name,  method_encode_signature (assembly, method->signature));
924 }
925
926 static guint32
927 mono_image_get_fieldref_token (MonoDynamicAssembly *assembly, MonoClassField *field, MonoClass *klass)
928 {
929         return mono_image_get_memberref_token (assembly, klass, 
930                 field->name,  fieldref_encode_signature (assembly, field));
931 }
932
933 static void
934 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
935 {
936         MonoDynamicTable *table;
937         guint *values;
938         int i;
939         char *n;
940
941         table = &assembly->tables [MONO_TABLE_TYPEDEF];
942         tb->table_idx = table->next_idx ++;
943         values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
944         values [MONO_TYPEDEF_FLAGS] = tb->attrs;
945         if (tb->parent) { /* interfaces don't have a parent */
946                 if (tb->parent->type)
947                         values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
948                 else {
949                         MonoReflectionTypeBuilder *ptb = (MonoReflectionTypeBuilder *)tb->parent;
950                         values [MONO_TYPEDEF_EXTENDS] = TYPEDEFORREF_TYPEDEF | (ptb->table_idx << TYPEDEFORREF_BITS);
951                 }
952         } else
953                 values [MONO_TYPEDEF_EXTENDS] = 0;
954         n = mono_string_to_utf8 (tb->name);
955         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
956         g_free (n);
957         n = mono_string_to_utf8 (tb->nspace);
958         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
959         g_free (n);
960         values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
961         values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
962
963         /*
964          * FIXME: constructors and methods need to be output in the same order
965          * as they are defined (according to table_idx).
966          */
967
968         /* handle constructors */
969         if (tb->ctors) {
970                 table = &assembly->tables [MONO_TABLE_METHOD];
971                 table->rows += mono_array_length (tb->ctors);
972                 alloc_table (table, table->rows);
973                 for (i = 0; i < mono_array_length (tb->ctors); ++i)
974                         mono_image_get_ctor_info (domain,
975                                 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
976         }
977
978         /* handle methods */
979         if (tb->methods) {
980                 table = &assembly->tables [MONO_TABLE_METHOD];
981                 table->rows += mono_array_length (tb->methods);
982                 alloc_table (table, table->rows);
983                 for (i = 0; i < mono_array_length (tb->methods); ++i)
984                         mono_image_get_method_info (
985                                 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
986         }
987
988         /* handle fields */
989         if (tb->fields) {
990                 table = &assembly->tables [MONO_TABLE_FIELD];
991                 table->rows += mono_array_length (tb->fields);
992                 alloc_table (table, table->rows);
993                 for (i = 0; i < mono_array_length (tb->fields); ++i)
994                         mono_image_get_field_info (
995                                 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
996         }
997
998         /* Do the same with properties etc.. */
999         if (tb->properties && mono_array_length (tb->properties)) {
1000                 table = &assembly->tables [MONO_TABLE_PROPERTY];
1001                 table->rows += mono_array_length (tb->properties);
1002                 alloc_table (table, table->rows);
1003                 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
1004                 table->rows ++;
1005                 alloc_table (table, table->rows);
1006                 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
1007                 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
1008                 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
1009                 for (i = 0; i < mono_array_length (tb->properties); ++i)
1010                         mono_image_get_property_info (
1011                                 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
1012         }
1013         if (tb->subtypes) {
1014                 MonoDynamicTable *ntable;
1015                 
1016                 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1017                 table->rows += mono_array_length (tb->subtypes);
1018                 alloc_table (table, table->rows);
1019
1020                 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1021                 ntable->rows += mono_array_length (tb->subtypes);
1022                 alloc_table (ntable, ntable->rows);
1023                 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
1024
1025                 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1026                         MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
1027
1028                         mono_image_get_type_info (domain, subtype, assembly);
1029                         values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
1030                         values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
1031                         /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
1032                                 mono_string_to_utf8 (subtype->name), subtype->table_idx,
1033                                 mono_string_to_utf8 (tb->name), tb->table_idx,
1034                                 ntable->next_idx, ntable->rows);*/
1035                         values += MONO_NESTED_CLASS_SIZE;
1036                         ntable->next_idx++;
1037                 }
1038         }
1039 }
1040
1041 static void
1042 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
1043 {
1044         MonoDynamicTable *table;
1045         int i;
1046         char *name;
1047
1048         table = &assembly->tables [MONO_TABLE_MODULE];
1049         mb->table_idx = table->next_idx ++;
1050         name = mono_string_to_utf8 (mb->module.name);
1051         table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
1052         g_free (name);
1053         /* need to set mvid? */
1054
1055         /*
1056          * fill-in info in other tables as well.
1057          */
1058         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1059         table->rows += mono_array_length (mb->types);
1060         alloc_table (table, table->rows);
1061         for (i = 0; i < mono_array_length (mb->types); ++i)
1062                 mono_image_get_type_info (domain, mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
1063 }
1064
1065 #define align_pointer(base,p)\
1066         do {\
1067                 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1068                 if (__diff & 3)\
1069                         (p) += 4 - (__diff & 3);\
1070         } while (0)
1071
1072 static void
1073 build_compressed_metadata (MonoDynamicAssembly *assembly)
1074 {
1075         int i;
1076         guint64 valid_mask = 0;
1077         guint32 heapt_size = 0;
1078         guint32 meta_size = 256; /* allow for header and other stuff */
1079         guint32 table_offset;
1080         guint32 ntables = 0;
1081         guint64 *int64val;
1082         guint32 *int32val;
1083         guint16 *int16val;
1084         MonoImage *meta;
1085         unsigned char *p;
1086         char *version = "mono" VERSION;
1087         
1088         /* Compute table sizes */
1089         meta = assembly->assembly.image = g_new0 (MonoImage, 1);
1090         
1091         /* Setup the info used by compute_sizes () */
1092         meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1093         meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1094         meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1095
1096         meta_size += assembly->blob.index;
1097         meta_size += assembly->guid.index;
1098         meta_size += assembly->sheap.index;
1099         meta_size += assembly->us.index;
1100
1101         for (i=0; i < 64; ++i)
1102                 meta->tables [i].rows = assembly->tables [i].rows;
1103         
1104         for (i = 0; i < 64; i++){
1105                 if (meta->tables [i].rows == 0)
1106                         continue;
1107                 valid_mask |= (guint64)1 << i;
1108                 ntables ++;
1109                 meta->tables [i].row_size = mono_metadata_compute_size (
1110                         meta, i, &meta->tables [i].size_bitfield);
1111                 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1112         }
1113         heapt_size += 24; /* #~ header size */
1114         heapt_size += ntables * 4;
1115         meta_size += heapt_size;
1116         meta->raw_metadata = g_malloc0 (meta_size);
1117         p = meta->raw_metadata;
1118         /* the metadata signature */
1119         *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1120         /* version numbers and 4 bytes reserved */
1121         int16val = (guint16*)p;
1122         *int16val++ = 1;
1123         *int16val = 1;
1124         p += 8;
1125         /* version string */
1126         int32val = (guint32*)p;
1127         *int32val = strlen (version);
1128         p += 4;
1129         memcpy (p, version, *int32val);
1130         p += *int32val;
1131         align_pointer (meta->raw_metadata, p);
1132         int16val = (guint16*)p;
1133         *int16val++ = 0; /* flags must be 0 */
1134         *int16val = 5; /* number of streams */
1135         p += 4;
1136
1137         /*
1138          * write the stream info.
1139          */
1140         table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
1141         table_offset += 3; table_offset &= ~3;
1142         
1143         int32val = (guint32*)p;
1144         *int32val++ = assembly->tstream.offset = table_offset;
1145         *int32val = heapt_size;
1146         table_offset += *int32val;
1147         table_offset += 3; table_offset &= ~3;
1148         p += 8;
1149         strcpy (p, "#~");
1150         p += 3;
1151         align_pointer (meta->raw_metadata, p);
1152
1153         int32val = (guint32*)p;
1154         *int32val++ = assembly->sheap.offset = table_offset;
1155         *int32val = assembly->sheap.index;
1156         table_offset += *int32val;
1157         table_offset += 3; table_offset &= ~3;
1158         p += 8;
1159         strcpy (p, "#Strings");
1160         p += 9;
1161         align_pointer (meta->raw_metadata, p);
1162
1163         int32val = (guint32*)p;
1164         *int32val++ = assembly->us.offset = table_offset;
1165         *int32val = assembly->us.index;
1166         table_offset += *int32val;
1167         table_offset += 3; table_offset &= ~3;
1168         p += 8;
1169         strcpy (p, "#US");
1170         p += 4;
1171         align_pointer (meta->raw_metadata, p);
1172
1173         int32val = (guint32*)p;
1174         *int32val++ = assembly->blob.offset = table_offset;
1175         *int32val = assembly->blob.index;
1176         table_offset += *int32val;
1177         table_offset += 3; table_offset &= ~3;
1178         p += 8;
1179         strcpy (p, "#Blob");
1180         p += 6;
1181         align_pointer (meta->raw_metadata, p);
1182
1183         int32val = (guint32*)p;
1184         *int32val++ = assembly->guid.offset = table_offset;
1185         *int32val = assembly->guid.index;
1186         table_offset += *int32val;
1187         table_offset += 3; table_offset &= ~3;
1188         p += 8;
1189         strcpy (p, "#GUID");
1190         p += 6;
1191         align_pointer (meta->raw_metadata, p);
1192
1193         /* 
1194          * now copy the data, the table stream header and contents goes first.
1195          */
1196         g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
1197         p = meta->raw_metadata + assembly->tstream.offset;
1198         int32val = (guint32*)p;
1199         *int32val = 0; /* reserved */
1200         p += 4;
1201         *p++ = 1; /* version */
1202         *p++ = 0;
1203         if (meta->idx_string_wide)
1204                 *p |= 0x01;
1205         if (meta->idx_guid_wide)
1206                 *p |= 0x02;
1207         if (meta->idx_blob_wide)
1208                 *p |= 0x04;
1209         ++p;
1210         *p++ = 0; /* reserved */
1211         int64val = (guint64*)p;
1212         *int64val++ = valid_mask;
1213         *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now  */
1214         p += 16;
1215         int32val = (guint32*)p;
1216         for (i = 0; i < 64; i++){
1217                 if (meta->tables [i].rows == 0)
1218                         continue;
1219                 *int32val++ = meta->tables [i].rows;
1220         }
1221         p = (unsigned char*)int32val;
1222         /* compress the tables */
1223         for (i = 0; i < 64; i++){
1224                 int row, col;
1225                 guint32 *values;
1226                 guint32 bitfield = meta->tables [i].size_bitfield;
1227                 if (!meta->tables [i].rows)
1228                         continue;
1229                 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
1230                         g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
1231                 meta->tables [i].base = p;
1232                 for (row = 1; row <= meta->tables [i].rows; ++row) {
1233                         values = assembly->tables [i].values + row * assembly->tables [i].columns;
1234                         for (col = 0; col < assembly->tables [i].columns; ++col) {
1235                                 switch (mono_metadata_table_size (bitfield, col)) {
1236                                 case 1:
1237                                         *p++ = values [col];
1238                                         break;
1239                                 case 2:
1240                                         int16val = (guint16*)p;
1241                                         *int16val = values [col];
1242                                         p += 2;
1243                                         break;
1244                                 case 4:
1245                                         int32val = (guint32*)p;
1246                                         *int32val = values [col];
1247                                         p += 4;
1248                                         break;
1249                                 default:
1250                                         g_assert_not_reached ();
1251                                 }
1252                         }
1253                 }
1254                 g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
1255         }
1256         
1257         g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
1258         memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
1259         memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
1260         memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
1261         memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
1262
1263         assembly->meta_size = assembly->guid.offset + assembly->guid.index;
1264 }
1265
1266 static void
1267 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
1268 {
1269         MonoDynamicTable *table;
1270         MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
1271         MonoDomain *domain = ((MonoObject *)assemblyb)->vtable->domain;
1272         guint32 len;
1273         guint32 *values;
1274         char *name;
1275         int i;
1276         
1277         assembly->text_rva =  0x00002000;
1278
1279         table = &assembly->tables [MONO_TABLE_ASSEMBLY];
1280         alloc_table (table, 1);
1281         values = table->values + MONO_ASSEMBLY_SIZE;
1282         values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
1283         name = mono_string_to_utf8 (assemblyb->name);
1284         values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
1285         g_free (name);
1286         values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
1287         values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
1288         values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1289         values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1290         values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1291         values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1292
1293         assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
1294         assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
1295
1296         len = mono_array_length (assemblyb->modules);
1297         table = &assembly->tables [MONO_TABLE_MODULE];
1298         alloc_table (table, len);
1299         for (i = 0; i < len; ++i)
1300                 mono_image_fill_module_table (domain, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
1301
1302         table = &assembly->tables [MONO_TABLE_TYPEDEF];
1303         /* 
1304          * table->rows is already set above and in mono_image_fill_module_table.
1305          */
1306         alloc_table (table, table->rows);
1307         /*
1308          * Set the first entry.
1309          */
1310         values = table->values + table->columns;
1311         values [MONO_TYPEDEF_FLAGS] = 0;
1312         values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
1313         values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
1314         values [MONO_TYPEDEF_EXTENDS] = 0;
1315         values [MONO_TYPEDEF_FIELD_LIST] = 1;
1316         values [MONO_TYPEDEF_METHOD_LIST] = 1;
1317
1318         /* later include all the assemblies referenced */
1319         table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
1320         alloc_table (table, 1);
1321         values = table->values + table->columns;
1322         values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib");
1323         values [MONO_ASSEMBLYREF_MAJOR_VERSION] = 0;
1324         values [MONO_ASSEMBLYREF_MINOR_VERSION] = 0;
1325         values [MONO_ASSEMBLYREF_BUILD_NUMBER] = 0;
1326         values [MONO_ASSEMBLYREF_REV_NUMBER] = 0;
1327         values [MONO_ASSEMBLYREF_FLAGS] = 0;
1328         values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0;
1329         values [MONO_ASSEMBLYREF_CULTURE] = 0;
1330         values [MONO_ASSEMBLYREF_HASH_VALUE] = 0;
1331
1332         build_compressed_metadata (assembly);
1333 }
1334
1335 guint32
1336 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
1337 {
1338         guint32 index;
1339         char buf [16];
1340         char *b = buf;
1341         
1342         if (!assembly->dynamic_assembly)
1343                 mono_image_basic_init (assembly);
1344         mono_metadata_encode_value (1 | (str->length * 2), b, &b);
1345         index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
1346         /* FIXME: ENOENDIAN */
1347         mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2);
1348         mono_image_add_stream_data (&assembly->dynamic_assembly->us, "", 1);
1349         return MONO_TOKEN_STRING | index;
1350 }
1351
1352 /*
1353  * Get a token to insert in the IL code stream for the given MemberInfo.
1354  * obj can be:
1355  *      ConstructorBuilder
1356  *      MethodBuilder
1357  *      FieldBuilder
1358  *      MonoCMethod
1359  *      MonoMethod
1360  *      MonoField
1361  *      MonoType
1362  *      TypeBuilder
1363  */
1364 guint32
1365 mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj)
1366 {
1367         MonoClass *klass = obj->vtable->klass;
1368         guint32 token;
1369
1370         mono_image_basic_init (assembly);
1371
1372         if (strcmp (klass->name, "MethodBuilder") == 0) {
1373                 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
1374                 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
1375                 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
1376                 return token;
1377         }
1378         if (strcmp (klass->name, "ConstructorBuilder") == 0) {
1379                 MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
1380                 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
1381                 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
1382                 return token;
1383         }
1384         if (strcmp (klass->name, "FieldBuilder") == 0) {
1385                 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
1386                 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
1387         }
1388         if (strcmp (klass->name, "TypeBuilder") == 0) {
1389                 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
1390                 return tb->table_idx | MONO_TOKEN_TYPE_DEF;
1391         }
1392         if (strcmp (klass->name, "MonoType") == 0) {
1393                 MonoReflectionType *tb = (MonoReflectionType *)obj;
1394                 return mono_metadata_token_from_dor (
1395                         mono_image_typedef_or_ref (assembly->dynamic_assembly, tb->type));
1396         }
1397         if (strcmp (klass->name, "MonoCMethod") == 0 ||
1398                         strcmp (klass->name, "MonoMethod") == 0) {
1399                 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
1400                 token = mono_image_get_methodref_token (assembly->dynamic_assembly, m->method);
1401                 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
1402                 return token;
1403         }
1404         if (strcmp (klass->name, "MonoField") == 0) {
1405                 MonoReflectionField *f = (MonoReflectionField *)obj;
1406                 token = mono_image_get_fieldref_token (assembly->dynamic_assembly, f->field, f->klass);
1407                 /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/
1408                 return token;
1409         }
1410         g_print ("requested token for %s\n", klass->name);
1411         return 0;
1412 }
1413
1414 void
1415 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
1416 {
1417         MonoDynamicAssembly *assembly;
1418         int i;
1419         
1420         if (assemblyb->dynamic_assembly)
1421                 return;
1422
1423         assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
1424
1425         string_heap_init (&assembly->sheap);
1426         mono_image_add_stream_data (&assembly->us, "", 1);
1427         mono_image_add_stream_data (&assembly->blob, "", 1);
1428
1429         for (i=0; i < 64; ++i) {
1430                 assembly->tables [i].next_idx = 1;
1431                 assembly->tables [i].columns = table_sizes [i];
1432         }
1433         
1434 }
1435
1436 int
1437 mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize)
1438 {
1439         MonoMSDOSHeader *msdos;
1440         MonoDotNetHeader *header;
1441         MonoSectionTable *section;
1442         MonoCLIHeader *cli_header;
1443         guint32 header_size =  TEXT_OFFSET + CLI_H_SIZE;
1444         MonoDynamicAssembly *assembly;
1445
1446         static const unsigned char msheader[] = {
1447                 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,  0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1448                 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1449                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1450                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
1451                 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,  0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
1452                 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,  0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
1453                 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,  0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
1454                 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1455         };
1456
1457         if (maxsize < header_size)
1458                 return -1;
1459
1460         mono_image_basic_init (assemblyb);
1461         assembly = assemblyb->dynamic_assembly;
1462
1463         mono_image_build_metadata (assemblyb);
1464
1465         memset (buffer, 0, header_size);
1466         memcpy (buffer, msheader, sizeof (MonoMSDOSHeader));
1467
1468         msdos = (MonoMSDOSHeader *)buffer;
1469         header = (MonoDotNetHeader *)(buffer + sizeof (MonoMSDOSHeader));
1470         section = (MonoSectionTable*) (buffer + sizeof (MonoMSDOSHeader) + sizeof (MonoDotNetHeader));
1471
1472         /* FIXME: ENDIAN problem: byteswap as needed */
1473         msdos->pe_offset = sizeof (MonoMSDOSHeader);
1474
1475         header->pesig [0] = 'P';
1476         header->pesig [1] = 'E';
1477         header->pesig [2] = header->pesig [3] = 0;
1478
1479         header->coff.coff_machine = 0x14c;
1480         header->coff.coff_sections = 1; /* only .text supported now */
1481         header->coff.coff_time = time (NULL);
1482         header->coff.coff_opt_header_size = sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4;
1483         /* it's an exe */
1484         header->coff.coff_attributes = 0x010e;
1485         /* it's a dll */
1486         //header->coff.coff_attributes = 0x210e;
1487         header->pe.pe_magic = 0x10B;
1488         header->pe.pe_major = 6;
1489         header->pe.pe_minor = 0;
1490         /* need to set: pe_code_size pe_data_size pe_rva_entry_point pe_rva_code_base pe_rva_data_base */
1491
1492         header->nt.pe_image_base = 0x400000;
1493         header->nt.pe_section_align = 8192;
1494         header->nt.pe_file_alignment = FILE_ALIGN;
1495         header->nt.pe_os_major = 4;
1496         header->nt.pe_os_minor = 0;
1497         header->nt.pe_subsys_major = 4;
1498         /* need to set pe_image_size, pe_header_size */
1499         header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */
1500         header->nt.pe_stack_reserve = 0x00100000;
1501         header->nt.pe_stack_commit = 0x00001000;
1502         header->nt.pe_heap_reserve = 0x00100000;
1503         header->nt.pe_heap_commit = 0x00001000;
1504         header->nt.pe_loader_flags = 1;
1505         header->nt.pe_data_dir_count = 16;
1506
1507 #if 0
1508         /* set: */
1509         header->datadir.pe_import_table
1510         pe_resource_table
1511         pe_reloc_table
1512         pe_iat  
1513 #endif
1514         header->datadir.pe_cli_header.size = CLI_H_SIZE;
1515         header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */
1516
1517         /* Write section tables */
1518         strcpy (section->st_name, ".text");
1519         section->st_virtual_size = 1024; /* FIXME */
1520         section->st_virtual_address = assembly->text_rva;
1521         section->st_raw_data_size = 1024; /* FIXME */
1522         section->st_raw_data_ptr = TEXT_OFFSET;
1523         section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
1524
1525         /* 
1526          * align: build_compressed_metadata () assumes metadata is aligned 
1527          * see below:
1528          * cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1529          */
1530         assembly->code.index += 3;
1531         assembly->code.index &= ~3;
1532
1533         /*
1534          * Write the MonoCLIHeader header 
1535          */
1536         cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET);
1537         cli_header->ch_size = CLI_H_SIZE;
1538         cli_header->ch_runtime_major = 2;
1539         cli_header->ch_flags = CLI_FLAGS_ILONLY;
1540         if (assemblyb->entry_point) 
1541                 cli_header->ch_entry_point = assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF;
1542         else
1543                 cli_header->ch_entry_point = 0;
1544         cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1545         cli_header->ch_metadata.size = assembly->meta_size;
1546         
1547         return header_size;
1548 }
1549
1550 /*
1551  * We need to return always the same object for Type, MethodInfo, FieldInfo etc..
1552  */
1553 static GHashTable *object_cache = NULL;
1554
1555 #define CHECK_OBJECT(t,p)       \
1556         do {    \
1557                 t _obj; \
1558                 if (!object_cache)      \
1559                         object_cache = g_hash_table_new (g_direct_hash, g_direct_equal);        \
1560                 if ((_obj = g_hash_table_lookup (object_cache, (p))))   \
1561                         return _obj;    \
1562         } while (0)
1563
1564 #define CACHE_OBJECT(p,o)       \
1565         do {    \
1566                 g_hash_table_insert (object_cache, p,o);        \
1567         } while (0)
1568         
1569 MonoReflectionAssembly*
1570 mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly)
1571 {
1572         static MonoClass *System_Reflection_Assembly;
1573         MonoReflectionAssembly *res;
1574         
1575         CHECK_OBJECT (MonoReflectionAssembly *, assembly);
1576         if (!System_Reflection_Assembly)
1577                 System_Reflection_Assembly = mono_class_from_name (
1578                         mono_defaults.corlib, "System.Reflection", "Assembly");
1579         res = (MonoReflectionAssembly *)mono_object_new (domain, System_Reflection_Assembly);
1580         res->assembly = assembly;
1581         CACHE_OBJECT (assembly, res);
1582         return res;
1583 }
1584
1585 MonoReflectionType*
1586 mono_type_get_object (MonoDomain *domain, MonoType *type)
1587 {
1588         MonoReflectionType *res;
1589         MonoClass *klass;
1590
1591         /* 
1592          * FIXME: type may come from the cache in metadata.c, we hand out only
1593          * the types from a MonoClass structure: the long term fix is to just
1594          * load corlib always and remove the cache in metadata.c altogether.
1595          * Or we may still handle it this way so we can store in MonoType additional info
1596          * as we do now.
1597          */
1598         klass = mono_class_from_mono_type (type);
1599         if ((type != &klass->byval_arg) && (type != &klass->this_arg)) {
1600                 if (type->byref)
1601                         type = &klass->this_arg;
1602                 else
1603                         type = &klass->byval_arg;
1604         }
1605         CHECK_OBJECT (MonoReflectionType *, type);
1606         res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class);
1607         res->type = type;
1608         CACHE_OBJECT (type, res);
1609         return res;
1610 }
1611
1612 MonoReflectionMethod*
1613 mono_method_get_object (MonoDomain *domain, MonoMethod *method)
1614 {
1615         /*
1616          * We use the same C representation for methods and constructors, but the type 
1617          * name in C# is different.
1618          */
1619         char *cname;
1620         MonoClass *klass;
1621         MonoReflectionMethod *ret;
1622
1623         CHECK_OBJECT (MonoReflectionMethod *, method);
1624         if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
1625                 cname = "MonoCMethod";
1626         else
1627                 cname = "MonoMethod";
1628         klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
1629
1630         ret = (MonoReflectionMethod*)mono_object_new (domain, klass);
1631         ret->method = method;
1632         CACHE_OBJECT (method, ret);
1633         return ret;
1634 }
1635
1636 MonoReflectionField*
1637 mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *field)
1638 {
1639         MonoReflectionField *res;
1640         MonoClass *oklass;
1641
1642         CHECK_OBJECT (MonoReflectionField *, field);
1643         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
1644         res = (MonoReflectionField *)mono_object_new (domain, oklass);
1645         res->klass = klass;
1646         res->field = field;
1647         CACHE_OBJECT (field, res);
1648         return res;
1649 }
1650
1651 MonoReflectionProperty*
1652 mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *property)
1653 {
1654         MonoReflectionProperty *res;
1655         MonoClass *oklass;
1656
1657         CHECK_OBJECT (MonoReflectionProperty *, property);
1658         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
1659         res = (MonoReflectionProperty *)mono_object_new (domain, oklass);
1660         res->klass = klass;
1661         res->property = property;
1662         CACHE_OBJECT (property, res);
1663         return res;
1664 }
1665
1666 MonoReflectionParameter**
1667 mono_param_get_objects (MonoDomain *domain, MonoMethod *method)
1668 {
1669         MonoReflectionParameter **res;
1670         MonoReflectionMethod *member;
1671         MonoClass *oklass;
1672         char **names;
1673         int i;
1674
1675         if (!method->signature->param_count)
1676                 return NULL;
1677
1678         member = mono_method_get_object (domain, method);
1679         names = g_new (char*, method->signature->param_count);
1680         mono_method_get_param_names (method, names);
1681         
1682         /* Note: the cache is based on the address of the signature into the method
1683          * since we already cache MethodInfos with the method as keys.
1684          */
1685         CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
1686         oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
1687         res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
1688         for (i = 0; i < method->signature->param_count; ++i) {
1689                 res [i] = (MonoReflectionParameter *)mono_object_new (domain, oklass);
1690                 res [i]->ClassImpl = mono_type_get_object (domain, method->signature->params [i]);
1691                 res [i]->DefaultValueImpl = NULL; /* FIXME */
1692                 res [i]->MemberImpl = (MonoObject*)member;
1693                 res [i]->NameImpl = mono_string_new (domain, names [i]);
1694                 res [i]->PositionImpl = i + 1;
1695                 res [i]->AttrsImpl = method->signature->params [i]->attrs;
1696         }
1697         g_free (names);
1698         CACHE_OBJECT (&(method->signature), res);
1699         return res;
1700 }
1701
1702 /*
1703  * Parse a type name as accepted by the GetType () method and output the info
1704  * extracted in the info structure.
1705  * the name param will be mangled, so, make a copy before passing it to this function.
1706  * The fields in info will be valid until the memory pointed to by name is valid.
1707  * Returns 0 on parse error.
1708  */
1709 int
1710 mono_reflection_parse_type (char *name, MonoTypeNameParse *info) {
1711
1712         char *start, *p, *w, *last_point;
1713         int in_modifiers = 0;
1714
1715         start = p = w = name;
1716
1717         info->name = info->name_space = info->assembly = NULL;
1718         info->nest_name = info->nest_name_space = NULL;
1719         info->rank = info->isbyref = info->ispointer = 0;
1720
1721         last_point = NULL;
1722
1723         while (*p) {
1724                 switch (*p) {
1725                 case '+':
1726                         /* we have parsed the nesting namespace + name */
1727                         if (last_point) {
1728                                 info->nest_name_space = start;
1729                                 *last_point = 0;
1730                                 info->nest_name = last_point + 1;
1731                         } else {
1732                                 info->nest_name_space = "";
1733                                 info->nest_name = start;
1734                         }
1735                         *p = 0; /* NULL terminate */
1736                         last_point = NULL;
1737                         start = p + 1;
1738                         break;
1739                 case '.':
1740                         last_point = w;
1741                         break;
1742                 case '\\':
1743                         ++p;
1744                         break;
1745                 case '&':
1746                 case '*':
1747                 case '[':
1748                 case ',':
1749                         in_modifiers = 1;
1750                         break;
1751                 default:
1752                         break;
1753                 }
1754                 if (in_modifiers)
1755                         break;
1756                 *w++ = *p++;
1757         }
1758         
1759         if (last_point) {
1760                 info->name_space = start;
1761                 *last_point = 0;
1762                 info->name = last_point + 1;
1763         } else {
1764                 info->name_space = "";
1765                 info->name = start;
1766         }
1767         /* FIXME: we don't mainatin an order for byref, pointer and array... */
1768         while (*p) {
1769                 switch (*p) {
1770                 case '&':
1771                         info->isbyref = 1;
1772                         *p++ = 0;
1773                         break;
1774                 case '*':
1775                         info->ispointer = 1;
1776                         *p++ = 0;
1777                         break;
1778                 case '[':
1779                         info->rank = 1;
1780                         *p++ = 0;
1781                         while (*p) {
1782                                 if (*p == ',')
1783                                         info->rank++;
1784                                 if (*p == ']')
1785                                         break;
1786                                 ++p;
1787                         }
1788                         if (*p++ != ']')
1789                                 return 0;
1790                         break;
1791                 case ',':
1792                         *p++ = 0;
1793                         while (*p) {
1794                                 if (*p == ' ') {
1795                                         ++p;
1796                                         continue;
1797                                 }
1798                                 break;
1799                         }
1800                         if (!*p)
1801                                 return 0; /* missing assembly name */
1802                         info->assembly = p;
1803                         break;
1804                 default:
1805                         break;
1806                 }
1807         }
1808         *w = 0; /* terminate class name */
1809         if (!info->name || !*info->name)
1810                 return 0;
1811         if (info->nest_name && !*info->nest_name)
1812                 return 0;
1813         /* add other consistency checks */
1814         return 1;
1815 }
1816