3 * reflection.c: Routines for creating an image at runtime.
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001, 2002 Ximian, Inc. http://www.ximian.com
12 #include "mono/utils/mono-digest.h"
13 #include "mono/metadata/reflection.h"
14 #include "mono/metadata/tabledefs.h"
15 #include "mono/metadata/tokentype.h"
16 #include "mono/metadata/appdomain.h"
17 #include "mono/metadata/opcodes.h"
18 #include <mono/metadata/exception.h>
27 #include "rawbuffer.h"
28 #include "mono-endian.h"
30 #include <mono/os/gc_wrapper.h>
32 #define TEXT_OFFSET 512
33 #define CLI_H_SIZE 136
34 #define FILE_ALIGN 512
35 #define VIRT_ALIGN 8192
36 #define START_TEXT_RVA 0x00002000
39 MonoReflectionILGen *ilgen;
40 MonoReflectionType *rtype;
41 MonoArray *parameters;
46 guint32 *table_idx; /* note: it's a pointer */
50 MonoBoolean init_locals;
51 } ReflectionMethodBuilder;
53 const unsigned char table_sizes [64] = {
63 MONO_INTERFACEIMPL_SIZE,
64 MONO_MEMBERREF_SIZE, /* 0x0A */
66 MONO_CUSTOM_ATTR_SIZE,
67 MONO_FIELD_MARSHAL_SIZE,
68 MONO_DECL_SECURITY_SIZE,
69 MONO_CLASS_LAYOUT_SIZE,
70 MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
71 MONO_STAND_ALONE_SIGNATURE_SIZE,
75 MONO_PROPERTY_MAP_SIZE,
78 MONO_METHOD_SEMA_SIZE,
80 MONO_MODULEREF_SIZE, /* 0x1A */
86 MONO_ASSEMBLY_SIZE, /* 0x20 */
87 MONO_ASSEMBLY_PROCESSOR_SIZE,
89 MONO_ASSEMBLYREF_SIZE,
90 MONO_ASSEMBLYREFPROC_SIZE,
91 MONO_ASSEMBLYREFOS_SIZE,
95 MONO_NESTED_CLASS_SIZE,
99 static guint32 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type);
100 static guint32 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method);
101 static guint32 encode_marshal_blob (MonoDynamicAssembly *assembly, MonoReflectionMarshal *minfo);
104 alloc_table (MonoDynamicTable *table, guint nrows)
107 g_assert (table->columns);
108 table->values = g_realloc (table->values, (1 + table->rows) * table->columns * sizeof (guint32));
112 string_heap_insert (MonoDynamicStream *sh, const char *str)
116 gpointer oldkey, oldval;
118 if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
119 return GPOINTER_TO_UINT (oldval);
121 len = strlen (str) + 1;
123 if (idx + len > sh->alloc_size) {
124 sh->alloc_size += len + 4096;
125 sh->data = g_realloc (sh->data, sh->alloc_size);
128 * We strdup the string even if we already copy them in sh->data
129 * so that the string pointers in the hash remain valid even if
130 * we need to realloc sh->data. We may want to avoid that later.
132 g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
133 memcpy (sh->data + idx, str, len);
139 string_heap_init (MonoDynamicStream *sh)
142 sh->alloc_size = 4096;
143 sh->data = g_malloc (4096);
144 sh->hash = g_hash_table_new (g_str_hash, g_str_equal);
145 string_heap_insert (sh, "");
148 #if 0 /* never used */
150 string_heap_free (MonoDynamicStream *sh)
153 g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL);
154 g_hash_table_destroy (sh->hash);
159 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
162 if (stream->alloc_size < stream->index + len) {
163 stream->alloc_size += len + 4096;
164 stream->data = g_realloc (stream->data, stream->alloc_size);
166 memcpy (stream->data + stream->index, data, len);
168 stream->index += len;
170 * align index? Not without adding an additional param that controls it since
171 * we may store a blob value in pieces.
177 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
180 if (stream->alloc_size < stream->index + len) {
181 stream->alloc_size += len + 4096;
182 stream->data = g_realloc (stream->data, stream->alloc_size);
184 memset (stream->data + stream->index, 0, len);
186 stream->index += len;
191 stream_data_align (MonoDynamicStream *stream)
194 guint32 count = stream->index % 4;
196 /* we assume the stream data will be aligned */
198 mono_image_add_stream_data (stream, buf, 4 - count);
202 mono_blob_entry_hash (const char* str)
206 len = mono_metadata_decode_blob_size (str, &str);
209 for (str += 1; str < end; str++)
210 h = (h << 5) - h + *str;
215 mono_blob_entry_equal (const char *str1, const char *str2) {
219 len = mono_metadata_decode_blob_size (str1, &end1);
220 len2 = mono_metadata_decode_blob_size (str2, &end2);
223 return memcmp (end1, end2, len) == 0;
227 add_to_blob_cached (MonoDynamicAssembly *assembly, char *b1, int s1, char *b2, int s2)
231 gpointer oldkey, oldval;
233 copy = g_malloc (s1+s2);
234 memcpy (copy, b1, s1);
235 memcpy (copy + s1, b2, s2);
236 if (g_hash_table_lookup_extended (assembly->blob_cache, copy, &oldkey, &oldval)) {
238 idx = GPOINTER_TO_UINT (oldval);
240 idx = mono_image_add_stream_data (&assembly->blob, b1, s1);
241 mono_image_add_stream_data (&assembly->blob, b2, s2);
242 g_hash_table_insert (assembly->blob_cache, copy, GUINT_TO_POINTER (idx));
247 /* modified version needed to handle building corlib */
249 my_mono_class_from_mono_type (MonoType *type) {
250 switch (type->type) {
251 case MONO_TYPE_ARRAY:
253 case MONO_TYPE_SZARRAY:
254 return mono_class_from_mono_type (type);
256 /* should be always valid when we reach this case... */
257 return type->data.klass;
262 encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endbuf)
265 g_assert_not_reached ();
270 mono_metadata_encode_value (MONO_TYPE_BYREF, p, &p);
274 case MONO_TYPE_BOOLEAN:
288 case MONO_TYPE_STRING:
289 case MONO_TYPE_OBJECT:
290 case MONO_TYPE_TYPEDBYREF:
291 mono_metadata_encode_value (type->type, p, &p);
294 case MONO_TYPE_SZARRAY:
295 mono_metadata_encode_value (type->type, p, &p);
296 encode_type (assembly, type->data.type, p, &p);
298 case MONO_TYPE_VALUETYPE:
299 case MONO_TYPE_CLASS:
300 mono_metadata_encode_value (type->type, p, &p);
301 mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, type), p, &p);
304 case MONO_TYPE_VALUETYPE:
305 case MONO_TYPE_CLASS: {
306 MonoClass *k = mono_class_from_mono_type (type);
307 mono_metadata_encode_value (type->type, p, &p);
308 /* ensure only non-byref gets passed to mono_image_typedef_or_ref() */
309 mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, &k->byval_arg), p, &p);
313 case MONO_TYPE_ARRAY:
314 mono_metadata_encode_value (type->type, p, &p);
315 encode_type (assembly, type->data.array->type, p, &p);
316 mono_metadata_encode_value (type->data.array->rank, p, &p);
317 mono_metadata_encode_value (0, p, &p); /* FIXME: set to 0 for now */
318 mono_metadata_encode_value (0, p, &p);
321 g_error ("need to encode type %x", type->type);
327 encode_reflection_type (MonoDynamicAssembly *assembly, MonoReflectionType *type, char *p, char **endbuf)
330 mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf);
334 encode_type (assembly, type->type, p, endbuf);
338 g_assert_not_reached ();
343 method_encode_signature (MonoDynamicAssembly *assembly, MonoMethodSignature *sig)
348 guint32 nparams = sig->param_count;
349 guint32 size = 10 + nparams * 10;
354 p = buf = g_malloc (size);
356 * FIXME: vararg, explicit_this, differenc call_conv values...
358 *p = sig->call_convention;
360 *p |= 0x20; /* hasthis */
362 mono_metadata_encode_value (nparams, p, &p);
363 encode_type (assembly, sig->ret, p, &p);
364 for (i = 0; i < nparams; ++i)
365 encode_type (assembly, sig->params [i], p, &p);
367 g_assert (p - buf < size);
368 mono_metadata_encode_value (p-buf, b, &b);
369 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
375 method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
378 * FIXME: reuse code from method_encode_signature().
383 guint32 nparams = mb->parameters ? mono_array_length (mb->parameters): 0;
384 guint32 size = 10 + nparams * 10;
389 p = buf = g_malloc (size);
390 /* LAMESPEC: all the call conv spec is foobared */
391 *p = mb->call_conv & 0x60; /* has-this, explicit-this */
392 if (mb->call_conv & 2)
393 *p |= 0x5; /* vararg */
394 if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
395 *p |= 0x20; /* hasthis */
397 mono_metadata_encode_value (nparams, p, &p);
398 encode_reflection_type (assembly, mb->rtype, p, &p);
399 for (i = 0; i < nparams; ++i) {
400 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
401 encode_reflection_type (assembly, pt, p, &p);
404 g_assert (p - buf < size);
405 mono_metadata_encode_value (p-buf, b, &b);
406 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
412 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
414 MonoDynamicTable *table;
417 guint32 idx, sig_idx, size;
418 guint nl = mono_array_length (ilgen->locals);
425 p = buf = g_malloc (size);
426 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
427 idx = table->next_idx ++;
429 alloc_table (table, table->rows);
430 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
432 mono_metadata_encode_value (0x07, p, &p);
433 mono_metadata_encode_value (nl, p, &p);
434 for (i = 0; i < nl; ++i) {
435 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
436 encode_reflection_type (assembly, lb->type, p, &p);
438 g_assert (p - buf < size);
439 mono_metadata_encode_value (p-buf, b, &b);
440 sig_idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
443 values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
449 method_count_clauses (MonoReflectionILGen *ilgen)
451 guint32 num_clauses = 0;
454 MonoILExceptionInfo *ex_info;
455 for (i = 0; i < mono_array_length (ilgen->ex_handlers); ++i) {
456 ex_info = (MonoILExceptionInfo*)mono_array_addr (ilgen->ex_handlers, MonoILExceptionInfo, i);
457 if (ex_info->handlers)
458 num_clauses += mono_array_length (ex_info->handlers);
466 static MonoExceptionClause*
467 method_encode_clauses (MonoDynamicAssembly *assembly,
468 MonoReflectionILGen *ilgen, guint32 num_clauses)
470 MonoExceptionClause *clauses;
471 MonoExceptionClause *clause;
472 MonoILExceptionInfo *ex_info;
473 MonoILExceptionBlock *ex_block;
474 guint32 finally_start;
475 int i, j, clause_index;;
477 clauses = g_new0 (MonoExceptionClause, num_clauses);
480 for (i = 0; i < mono_array_length (ilgen->ex_handlers); ++i) {
481 ex_info = (MonoILExceptionInfo*)mono_array_addr (ilgen->ex_handlers, MonoILExceptionInfo, i);
482 finally_start = ex_info->start + ex_info->len;
483 g_assert (ex_info->handlers);
484 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
485 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
486 clause = &(clauses [clause_index]);
488 clause->flags = ex_block->type;
489 clause->try_offset = ex_info->start;
491 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
492 clause->try_len = finally_start - ex_info->start;
494 clause->try_len = ex_info->len;
495 clause->handler_offset = ex_block->start;
496 clause->handler_len = ex_block->len;
497 clause->token_or_filter = ex_block->extype ? mono_metadata_token_from_dor (
498 mono_image_typedef_or_ref (assembly, ex_block->extype->type)): 0;
499 if (ex_block->extype) {
500 g_hash_table_insert (assembly->tokens,
501 GUINT_TO_POINTER (clause->token_or_filter),
504 finally_start = ex_block->start + ex_block->len;
514 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
520 gint32 num_locals = 0;
521 gint32 num_exception = 0;
524 char fat_header [12];
527 guint32 local_sig = 0;
528 guint32 header_size = 12;
531 if ((mb->attrs & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
532 (mb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
533 (mb->iattrs & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
534 (mb->attrs & METHOD_ATTRIBUTE_ABSTRACT))
538 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
540 code = mb->ilgen->code;
541 code_size = mb->ilgen->code_len;
542 max_stack = mb->ilgen->max_stack;
543 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
544 if (mb->ilgen->ex_handlers)
545 num_exception = method_count_clauses (mb->ilgen);
548 code_size = mono_array_length (code);
549 max_stack = 8; /* we probably need to run a verifier on the code... */
552 /* check for exceptions, maxstack, locals */
553 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
555 if (code_size < 64 && !(code_size & 1)) {
556 flags = (code_size << 2) | 0x2;
557 } else if (code_size < 32 && (code_size & 1)) {
558 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
562 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
563 /* add to the fixup todo list */
564 if (mb->ilgen && mb->ilgen->num_token_fixups)
565 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
566 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
567 return assembly->text_rva + idx;
571 local_sig = MONO_TOKEN_SIGNATURE | encode_locals (assembly, mb->ilgen);
573 * FIXME: need to set also the header size in fat_flags.
574 * (and more sects and init locals flags)
578 fat_flags |= METHOD_HEADER_MORE_SECTS;
580 fat_flags |= METHOD_HEADER_INIT_LOCALS;
581 fat_header [0] = fat_flags;
582 fat_header [1] = (header_size / 4 ) << 4;
583 shortp = (guint16*)(fat_header + 2);
584 *shortp = GUINT16_TO_LE (max_stack);
585 intp = (guint32*)(fat_header + 4);
586 *intp = GUINT32_TO_LE (code_size);
587 intp = (guint32*)(fat_header + 8);
588 *intp = GUINT32_TO_LE (local_sig);
589 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
590 /* add to the fixup todo list */
591 if (mb->ilgen && mb->ilgen->num_token_fixups)
592 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
594 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
596 unsigned char sheader [4];
597 MonoExceptionClause clause;
598 MonoILExceptionInfo * ex_info;
599 MonoILExceptionBlock * ex_block;
602 stream_data_align (&assembly->code);
603 /* always use fat format for now */
604 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
605 num_exception *= sizeof (MonoExceptionClause);
606 num_exception += 4; /* include the size of the header */
607 sheader [1] = num_exception & 0xff;
608 sheader [2] = (num_exception >> 8) & 0xff;
609 sheader [3] = (num_exception >> 16) & 0xff;
610 mono_image_add_stream_data (&assembly->code, sheader, 4);
611 /* fat header, so we are already aligned */
613 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
614 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
615 if (ex_info->handlers) {
616 int finally_start = ex_info->start + ex_info->len;
617 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
618 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
619 clause.flags = GUINT32_TO_LE (ex_block->type);
620 clause.try_offset = GUINT32_TO_LE (ex_info->start);
621 /* need fault, too, probably */
622 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
623 clause.try_len = GUINT32_TO_LE (finally_start - ex_info->start);
625 clause.try_len = GUINT32_TO_LE (ex_info->len);
626 clause.handler_offset = GUINT32_TO_LE (ex_block->start);
627 clause.handler_len = GUINT32_TO_LE (ex_block->len);
628 finally_start = ex_block->start + ex_block->len;
629 clause.token_or_filter = ex_block->extype ? mono_metadata_token_from_dor (
630 mono_image_typedef_or_ref (assembly, ex_block->extype->type)): 0;
631 clause.token_or_filter = GUINT32_TO_LE (clause.token_or_filter);
632 /*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",
633 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);*/
634 mono_image_add_stream_data (&assembly->code, (char*)&clause, sizeof (clause));
637 g_error ("No clauses for ex info block %d", i);
641 return assembly->text_rva + idx;
645 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 token)
648 MonoDynamicTable *table;
651 table = &assembly->tables [table_idx];
653 g_assert (col < table->columns);
655 values = table->values + table->columns;
656 for (i = 1; i <= table->rows; ++i) {
657 if (values [col] == token)
659 values += table->columns;
665 * idx is the table index of the object
666 * type is one of CUSTOM_ATTR_*
669 mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 idx, guint32 type, MonoArray *cattrs)
671 MonoDynamicTable *table;
672 MonoReflectionCustomAttr *cattr;
674 guint32 count, i, token;
678 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
681 count = mono_array_length (cattrs);
682 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
683 table->rows += count;
684 alloc_table (table, table->rows);
685 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
686 idx <<= CUSTOM_ATTR_BITS;
688 for (i = 0; i < count; ++i) {
689 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
690 values [MONO_CUSTOM_ATTR_PARENT] = idx;
691 token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor);
692 type = mono_metadata_token_index (token);
693 type <<= CUSTOM_ATTR_TYPE_BITS;
694 switch (mono_metadata_token_table (token)) {
695 case MONO_TABLE_METHOD:
696 type |= CUSTOM_ATTR_TYPE_METHODDEF;
698 case MONO_TABLE_MEMBERREF:
699 type |= CUSTOM_ATTR_TYPE_MEMBERREF;
702 g_warning ("got wrong token in custom attr");
705 values [MONO_CUSTOM_ATTR_TYPE] = type;
707 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
708 values [MONO_CUSTOM_ATTR_VALUE] = add_to_blob_cached (assembly, blob_size, p - blob_size,
709 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
710 values += MONO_CUSTOM_ATTR_SIZE;
716 * Fill in the MethodDef and ParamDef tables for a method.
717 * This is used for both normal methods and constructors.
720 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
722 MonoDynamicTable *table;
727 /* room in this table is already allocated */
728 table = &assembly->tables [MONO_TABLE_METHOD];
729 *mb->table_idx = table->next_idx ++;
730 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
732 name = mono_string_to_utf8 (mb->name);
733 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
735 } else { /* a constructor */
736 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
738 values [MONO_METHOD_FLAGS] = mb->attrs;
739 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
740 values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
741 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
743 table = &assembly->tables [MONO_TABLE_PARAM];
744 values [MONO_METHOD_PARAMLIST] = table->next_idx;
747 MonoDynamicTable *mtable;
750 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
751 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
754 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
755 if (mono_array_get (mb->pinfo, gpointer, i))
758 table->rows += count;
759 alloc_table (table, table->rows);
760 values = table->values + table->next_idx * MONO_PARAM_SIZE;
761 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
762 MonoReflectionParamBuilder *pb;
763 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
764 values [MONO_PARAM_FLAGS] = pb->attrs;
765 values [MONO_PARAM_SEQUENCE] = i;
766 name = mono_string_to_utf8 (pb->name);
767 values [MONO_PARAM_NAME] = string_heap_insert (&assembly->sheap, name);
769 values += MONO_PARAM_SIZE;
770 if (pb->marshal_info) {
772 alloc_table (mtable, mtable->rows);
773 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
774 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << HAS_FIELD_MARSHAL_BITS) | HAS_FIELD_MARSHAL_PARAMDEF;
775 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, pb->marshal_info);
777 pb->table_idx = table->next_idx++;
784 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
786 MonoDynamicTable *table;
789 ReflectionMethodBuilder rmb;
791 rmb.ilgen = mb->ilgen;
792 rmb.rtype = mb->rtype;
793 rmb.parameters = mb->parameters;
794 rmb.pinfo = mb->pinfo;
795 rmb.attrs = mb->attrs;
796 rmb.iattrs = mb->iattrs;
797 rmb.call_conv = mb->call_conv;
801 rmb.table_idx = &mb->table_idx;
802 rmb.init_locals = mb->init_locals;
804 mono_image_basic_method (&rmb, assembly);
806 if (mb->dll) { /* It's a P/Invoke method */
808 table = &assembly->tables [MONO_TABLE_IMPLMAP];
810 alloc_table (table, table->rows);
811 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
812 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
813 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
814 name = mono_string_to_utf8 (mb->dllentry);
815 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
817 name = mono_string_to_utf8 (mb->dll);
818 moduleref = string_heap_insert (&assembly->sheap, name);
820 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
821 table = &assembly->tables [MONO_TABLE_MODULEREF];
823 alloc_table (table, table->rows);
824 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
825 values [MONO_IMPLMAP_SCOPE] = table->rows;
828 if (mb->override_method) {
829 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
831 table = &assembly->tables [MONO_TABLE_METHODIMPL];
833 alloc_table (table, table->rows);
834 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
835 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
836 values [MONO_METHODIMPL_BODY] = METHODDEFORREF_METHODDEF | (mb->table_idx << METHODDEFORREF_BITS);
837 tok = mono_image_create_token (assembly, (MonoObject*)mb->override_method);
838 switch (mono_metadata_token_table (tok)) {
839 case MONO_TABLE_MEMBERREF:
840 tok = (mono_metadata_token_index (tok) << METHODDEFORREF_BITS ) | METHODDEFORREF_METHODREF;
842 case MONO_TABLE_METHOD:
843 tok = (mono_metadata_token_index (tok) << METHODDEFORREF_BITS ) | METHODDEFORREF_METHODDEF;
846 g_assert_not_reached ();
848 values [MONO_METHODIMPL_DECLARATION] = tok;
853 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
855 ReflectionMethodBuilder rmb;
857 rmb.ilgen = mb->ilgen;
858 rmb.rtype = mono_type_get_object (domain, &mono_defaults.void_class->byval_arg);
859 rmb.parameters = mb->parameters;
860 rmb.pinfo = mb->pinfo;
861 rmb.attrs = mb->attrs;
862 rmb.iattrs = mb->iattrs;
863 rmb.call_conv = mb->call_conv;
867 rmb.table_idx = &mb->table_idx;
868 rmb.init_locals = mb->init_locals;
870 mono_image_basic_method (&rmb, assembly);
875 fieldref_encode_signature (MonoDynamicAssembly *assembly, MonoClassField *field)
883 p = buf = g_malloc (64);
885 mono_metadata_encode_value (0x06, p, &p);
886 /* encode custom attributes before the type */
887 encode_type (assembly, field->type, p, &p);
888 g_assert (p-buf < 64);
889 mono_metadata_encode_value (p-buf, b, &b);
890 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
896 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
904 p = buf = g_malloc (64);
906 mono_metadata_encode_value (0x06, p, &p);
907 /* encode custom attributes before the type */
908 encode_reflection_type (assembly, fb->type, p, &p);
909 g_assert (p-buf < 64);
910 mono_metadata_encode_value (p-buf, b, &b);
911 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
917 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
918 * dest may be misaligned.
921 swap_with_size (char *dest, const char* val, int len, int nelem) {
922 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
925 for (elem = 0; elem < nelem; ++elem) {
951 g_assert_not_reached ();
957 memcpy (dest, val, len * nelem);
962 encode_constant (MonoDynamicAssembly *assembly, MonoObject *val, guint32 *ret_type) {
967 guint32 idx, len, dummy = 0;
969 p = buf = g_malloc (64);
971 *ret_type = MONO_TYPE_CLASS;
973 box_val = (char*)&dummy;
975 box_val = ((char*)val) + sizeof (MonoObject);
976 *ret_type = val->vtable->klass->byval_arg.type;
980 case MONO_TYPE_BOOLEAN:
1000 case MONO_TYPE_VALUETYPE:
1001 if (val->vtable->klass->enumtype) {
1002 *ret_type = val->vtable->klass->enum_basetype->type;
1005 g_error ("we can't encode valuetypes");
1006 case MONO_TYPE_CLASS:
1008 case MONO_TYPE_STRING: {
1009 MonoString *str = (MonoString*)val;
1010 /* there is no signature */
1011 len = str->length * 2;
1012 mono_metadata_encode_value (len, b, &b);
1013 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1015 char *swapped = g_malloc (2 * mono_string_length (str));
1016 const char *p = (const char*)mono_string_chars (str);
1018 swap_with_size (swapped, p, 2, mono_string_length (str));
1019 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
1023 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, (const char*)mono_string_chars (str), len);
1030 g_error ("we don't encode constant type 0x%02x yet", *ret_type);
1033 /* there is no signature */
1034 mono_metadata_encode_value (len, b, &b);
1035 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1036 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1037 swap_with_size (blob_size, box_val, len, 1);
1038 mono_image_add_stream_data (&assembly->blob, blob_size, len);
1040 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, box_val, len);
1048 encode_marshal_blob (MonoDynamicAssembly *assembly, MonoReflectionMarshal *minfo) {
1049 char blob_size [64];
1050 char *b = blob_size;
1054 p = buf = g_malloc (256);
1056 switch (minfo->type) {
1057 /* FIXME: handle ARRAY and other unmanaged types that need extra info */
1059 mono_metadata_encode_value (minfo->type, p, &p);
1063 mono_metadata_encode_value (len, b, &b);
1064 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, len);
1070 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
1072 MonoDynamicTable *table;
1076 /* maybe this fixup should be done in the C# code */
1077 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
1078 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
1079 table = &assembly->tables [MONO_TABLE_FIELD];
1080 fb->table_idx = table->next_idx ++;
1081 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
1082 name = mono_string_to_utf8 (fb->name);
1083 values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
1085 values [MONO_FIELD_FLAGS] = fb->attrs;
1086 values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
1088 if (fb->offset != -1) {
1089 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
1091 alloc_table (table, table->rows);
1092 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
1093 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
1094 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
1096 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
1097 guint32 field_type = 0;
1098 table = &assembly->tables [MONO_TABLE_CONSTANT];
1100 alloc_table (table, table->rows);
1101 values = table->values + table->rows * MONO_CONSTANT_SIZE;
1102 values [MONO_CONSTANT_PARENT] = HASCONSTANT_FIEDDEF | (fb->table_idx << HASCONSTANT_BITS);
1103 values [MONO_CONSTANT_VALUE] = encode_constant (assembly, fb->def_value, &field_type);
1104 values [MONO_CONSTANT_TYPE] = field_type;
1105 values [MONO_CONSTANT_PADDING] = 0;
1109 table = &assembly->tables [MONO_TABLE_FIELDRVA];
1111 alloc_table (table, table->rows);
1112 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
1113 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
1115 * We store it in the code section because it's simpler for now.
1117 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
1118 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
1120 if (fb->marshal_info) {
1121 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1123 alloc_table (table, table->rows);
1124 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
1125 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << HAS_FIELD_MARSHAL_BITS) | HAS_FIELD_MARSHAL_FIELDSREF;
1126 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, fb->marshal_info);
1131 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
1135 char *b = blob_size;
1136 guint32 nparams = 0;
1137 MonoReflectionMethodBuilder *mb = fb->get_method;
1138 MonoReflectionMethodBuilder *smb = fb->set_method;
1139 guint32 idx, i, size;
1141 if (mb && mb->parameters)
1142 nparams = mono_array_length (mb->parameters);
1143 if (!mb && smb && smb->parameters)
1144 nparams = mono_array_length (smb->parameters) - 1;
1145 size = 24 + nparams * 10;
1146 buf = p = g_malloc (size);
1149 mono_metadata_encode_value (nparams, p, &p);
1151 encode_reflection_type (assembly, mb->rtype, p, &p);
1152 for (i = 0; i < nparams; ++i) {
1153 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
1154 encode_reflection_type (assembly, pt, p, &p);
1157 /* the property type is the last param */
1158 encode_reflection_type (assembly, mono_array_get (smb->parameters, MonoReflectionType*, nparams), p, &p);
1159 for (i = 0; i < nparams; ++i) {
1160 MonoReflectionType *pt = mono_array_get (smb->parameters, MonoReflectionType*, i);
1161 encode_reflection_type (assembly, pt, p, &p);
1165 g_assert (p - buf < size);
1166 mono_metadata_encode_value (p-buf, b, &b);
1167 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, buf, p-buf);
1173 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
1175 MonoDynamicTable *table;
1178 guint num_methods = 0;
1182 * we need to set things in the following tables:
1183 * PROPERTYMAP (info already filled in _get_type_info ())
1184 * PROPERTY (rows already preallocated in _get_type_info ())
1185 * METHOD (method info already done with the generic method code)
1188 table = &assembly->tables [MONO_TABLE_PROPERTY];
1189 pb->table_idx = table->next_idx ++;
1190 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
1191 name = mono_string_to_utf8 (pb->name);
1192 values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
1194 values [MONO_PROPERTY_FLAGS] = pb->attrs;
1195 values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
1197 /* FIXME: we still don't handle 'other' methods */
1198 if (pb->get_method) num_methods ++;
1199 if (pb->set_method) num_methods ++;
1201 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1202 table->rows += num_methods;
1203 alloc_table (table, table->rows);
1205 if (pb->get_method) {
1206 semaidx = table->next_idx ++;
1207 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1208 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
1209 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
1210 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
1212 if (pb->set_method) {
1213 semaidx = table->next_idx ++;
1214 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1215 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
1216 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
1217 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY;
1222 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicAssembly *assembly)
1224 MonoDynamicTable *table;
1227 guint num_methods = 0;
1231 * we need to set things in the following tables:
1232 * EVENTMAP (info already filled in _get_type_info ())
1233 * EVENT (rows already preallocated in _get_type_info ())
1234 * METHOD (method info already done with the generic method code)
1237 table = &assembly->tables [MONO_TABLE_EVENT];
1238 eb->table_idx = table->next_idx ++;
1239 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
1240 name = mono_string_to_utf8 (eb->name);
1241 values [MONO_EVENT_NAME] = string_heap_insert (&assembly->sheap, name);
1243 values [MONO_EVENT_FLAGS] = eb->attrs;
1244 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, eb->type->type);
1247 * FIXME: we still don't handle 'other' methods
1249 if (eb->add_method) num_methods ++;
1250 if (eb->remove_method) num_methods ++;
1251 if (eb->raise_method) num_methods ++;
1253 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1254 table->rows += num_methods;
1255 alloc_table (table, table->rows);
1257 if (eb->add_method) {
1258 semaidx = table->next_idx ++;
1259 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1260 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
1261 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
1262 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1264 if (eb->remove_method) {
1265 semaidx = table->next_idx ++;
1266 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1267 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
1268 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
1269 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1271 if (eb->raise_method) {
1272 semaidx = table->next_idx ++;
1273 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1274 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
1275 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
1276 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT;
1281 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
1283 MonoDynamicTable *table;
1286 guint32 cols [MONO_ASSEMBLY_SIZE];
1290 if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, image))))
1293 mono_metadata_decode_row (&image->tables [MONO_TABLE_ASSEMBLY], 0, cols, MONO_ASSEMBLY_SIZE);
1295 table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
1296 token = table->next_idx ++;
1298 alloc_table (table, table->rows);
1299 values = table->values + token * MONO_ASSEMBLYREF_SIZE;
1300 if (strcmp ("corlib", image->assembly_name) == 0)
1301 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "mscorlib");
1303 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, image->assembly_name);
1304 values [MONO_ASSEMBLYREF_MAJOR_VERSION] = cols [MONO_ASSEMBLY_MAJOR_VERSION];
1305 values [MONO_ASSEMBLYREF_MINOR_VERSION] = cols [MONO_ASSEMBLY_MINOR_VERSION];
1306 values [MONO_ASSEMBLYREF_BUILD_NUMBER] = cols [MONO_ASSEMBLY_BUILD_NUMBER];
1307 values [MONO_ASSEMBLYREF_REV_NUMBER] = cols [MONO_ASSEMBLY_REV_NUMBER];
1308 values [MONO_ASSEMBLYREF_FLAGS] = 0;
1309 values [MONO_ASSEMBLYREF_CULTURE] = 0;
1310 values [MONO_ASSEMBLYREF_HASH_VALUE] = 0;
1312 if ((pubkey = mono_image_get_public_key (image, &publen))) {
1313 guchar pubtoken [9];
1315 mono_digest_get_public_token (pubtoken + 1, pubkey, publen);
1316 values [MONO_ASSEMBLYREF_PUBLIC_KEY] = mono_image_add_stream_data (&assembly->blob, pubtoken, 9);
1319 * We add the pubtoken from ms, so that the ms runtime can handle our binaries.
1320 * This is currently only a problem with references to System.Xml (see bug#27706),
1321 * but there may be other cases that makes this necessary. Note, we need to set
1322 * the version as well. When/if we sign our assemblies, we'd need to get our pubtoken
1323 * recognized by ms, yuck!
1324 * FIXME: need to add more assembly names, as needed.
1326 if (strcmp (image->assembly_name, "corlib") == 0 ||
1327 strcmp (image->assembly_name, "mscorlib") == 0 ||
1328 strcmp (image->assembly_name, "System") == 0 ||
1329 strcmp (image->assembly_name, "System.Xml") == 0 ||
1330 strcmp (image->assembly_name, "System.Data") == 0 ||
1331 strcmp (image->assembly_name, "System.Drawing") == 0 ||
1332 strcmp (image->assembly_name, "System.Web") == 0) {
1333 static const guchar ptoken [9] = {8, '\xB7', '\x7A', '\x5C', '\x56', '\x19', '\x34', '\xE0', '\x89'};
1334 values [MONO_ASSEMBLYREF_PUBLIC_KEY] = mono_image_add_stream_data (&assembly->blob, ptoken, 9);
1335 values [MONO_ASSEMBLYREF_MAJOR_VERSION] = 1;
1336 values [MONO_ASSEMBLYREF_BUILD_NUMBER] = 3300;
1338 values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0;
1341 token <<= RESOLTION_SCOPE_BITS;
1342 token |= RESOLTION_SCOPE_ASSEMBLYREF;
1343 g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
1344 g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), image);
1349 create_typespec (MonoDynamicAssembly *assembly, MonoType *type)
1351 MonoDynamicTable *table;
1357 char *b = blob_size;
1359 switch (type->type) {
1360 case MONO_TYPE_FNPTR:
1362 case MONO_TYPE_SZARRAY:
1363 case MONO_TYPE_ARRAY:
1364 encode_type (assembly, type, p, &p);
1370 g_assert (p-sig < 128);
1371 mono_metadata_encode_value (p-sig, b, &b);
1372 token = add_to_blob_cached (assembly, blob_size, b-blob_size, sig, p-sig);
1374 table = &assembly->tables [MONO_TABLE_TYPESPEC];
1375 alloc_table (table, table->rows + 1);
1376 values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
1377 values [MONO_TYPESPEC_SIGNATURE] = token;
1379 token = TYPEDEFORREF_TYPESPEC | (table->next_idx << TYPEDEFORREF_BITS);
1380 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
1386 * Despite the name, we handle also TypeSpec (with the above helper).
1389 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
1391 MonoDynamicTable *table;
1393 guint32 token, scope, enclosing;
1396 #define COMPILE_CORLIB 0
1398 /* nasty hack, need to find the proper solution */
1399 if (type->type == MONO_TYPE_OBJECT)
1400 return TYPEDEFORREF_TYPEDEF | (2 << TYPEDEFORREF_BITS);
1402 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
1405 token = create_typespec (assembly, type);
1408 klass = my_mono_class_from_mono_type (type);
1410 klass = mono_class_from_mono_type (type);
1412 * If it's in the same module:
1414 if (klass->image == assembly->assembly.image) {
1415 MonoReflectionTypeBuilder *tb = klass->reflection_info;
1416 token = TYPEDEFORREF_TYPEDEF | (tb->table_idx << TYPEDEFORREF_BITS);
1417 g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), klass);
1421 if (klass->nested_in) {
1422 enclosing = mono_image_typedef_or_ref (assembly, &klass->nested_in->byval_arg);
1423 /* get the typeref idx of the enclosing type */
1424 enclosing >>= TYPEDEFORREF_BITS;
1425 scope = (enclosing << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_TYPEREF;
1427 scope = resolution_scope_from_image (assembly, klass->image);
1429 table = &assembly->tables [MONO_TABLE_TYPEREF];
1430 alloc_table (table, table->rows + 1);
1431 values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
1432 values [MONO_TYPEREF_SCOPE] = scope;
1433 values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
1434 values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
1435 token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
1436 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
1438 g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), klass);
1443 * Insert a memberef row into the metadata: the token that point to the memberref
1444 * is returned. Caching is done in the caller (mono_image_get_methodref_token() or
1445 * mono_image_get_fieldref_token()).
1446 * The sig param is an index to an already built signature.
1449 mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoType *type, const char *name, guint32 sig)
1451 MonoDynamicTable *table;
1453 guint32 token, pclass;
1456 parent = mono_image_typedef_or_ref (assembly, type);
1457 switch (parent & TYPEDEFORREF_MASK) {
1458 case TYPEDEFORREF_TYPEREF:
1459 pclass = MEMBERREF_PARENT_TYPEREF;
1461 case TYPEDEFORREF_TYPESPEC:
1462 pclass = MEMBERREF_PARENT_TYPESPEC;
1464 case TYPEDEFORREF_TYPEDEF:
1465 /* should never get here */
1467 g_warning ("unknown typeref or def token 0x%08x for %s", parent, name);
1470 /* extract the index */
1471 parent >>= TYPEDEFORREF_BITS;
1473 table = &assembly->tables [MONO_TABLE_MEMBERREF];
1474 alloc_table (table, table->rows + 1);
1475 values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
1476 values [MONO_MEMBERREF_CLASS] = pclass | (parent << MEMBERREF_PARENT_BITS);
1477 values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
1478 values [MONO_MEMBERREF_SIGNATURE] = sig;
1479 token = MONO_TOKEN_MEMBER_REF | table->next_idx;
1486 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method)
1490 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
1493 token = mono_image_get_memberref_token (assembly, &method->klass->byval_arg,
1494 method->name, method_encode_signature (assembly, method->signature));
1495 g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
1500 mono_image_get_fieldref_token (MonoDynamicAssembly *assembly, MonoClassField *field, MonoClass *klass)
1504 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, field));
1507 field->parent = klass;
1508 token = mono_image_get_memberref_token (assembly, &klass->byval_arg,
1509 field->name, fieldref_encode_signature (assembly, field));
1510 g_hash_table_insert (assembly->handleref, field, GUINT_TO_POINTER(token));
1515 reflection_cc_to_file (int call_conv) {
1516 switch (call_conv & 0x3) {
1518 case 1: return MONO_CALL_DEFAULT;
1519 case 2: return MONO_CALL_VARARG;
1521 g_assert_not_reached ();
1528 MonoMethodSignature *sig;
1534 mono_image_get_array_token (MonoDynamicAssembly *assembly, MonoReflectionArrayMethod *m)
1539 MonoMethodSignature *sig;
1542 name = mono_string_to_utf8 (m->name);
1543 nparams = mono_array_length (m->parameters);
1544 sig = g_malloc0 (sizeof (MonoMethodSignature) + sizeof (MonoType*) * nparams);
1546 sig->call_convention = reflection_cc_to_file (m->call_conv);
1547 sig->param_count = nparams;
1548 sig->ret = m->ret? m->ret->type: &mono_defaults.void_class->byval_arg;
1549 for (i = 0; i < nparams; ++i) {
1550 MonoReflectionType *t = mono_array_get (m->parameters, gpointer, i);
1551 sig->params [i] = t->type;
1554 for (tmp = assembly->array_methods; tmp; tmp = tmp->next) {
1556 if (strcmp (name, am->name) == 0 &&
1557 mono_metadata_type_equal (am->parent, m->parent->type) &&
1558 mono_metadata_signature_equal (am->sig, sig)) {
1564 am = g_new0 (ArrayMethod, 1);
1567 am->parent = m->parent->type;
1568 am->token = mono_image_get_memberref_token (assembly, am->parent,
1569 name, method_encode_signature (assembly, sig));
1570 assembly->array_methods = g_list_prepend (assembly->array_methods, am);
1571 m->table_idx = am->token & 0xffffff;
1576 * Insert into the metadata tables all the info about the TypeBuilder tb.
1577 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
1580 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
1582 MonoDynamicTable *table;
1584 int i, is_object = 0, is_system = 0;
1587 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1588 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
1589 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
1590 n = mono_string_to_utf8 (tb->name);
1591 if (strcmp (n, "Object") == 0)
1593 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
1595 n = mono_string_to_utf8 (tb->nspace);
1596 if (strcmp (n, "System") == 0)
1598 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
1600 if (tb->parent && !(is_system && is_object)) { /* interfaces don't have a parent */
1601 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
1603 values [MONO_TYPEDEF_EXTENDS] = 0;
1604 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
1605 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
1608 * if we have explicitlayout or sequentiallayouts, output data in the
1609 * ClassLayout table.
1611 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) && (tb->class_size != -1)) {
1612 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
1614 alloc_table (table, table->rows);
1615 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
1616 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
1617 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
1618 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
1621 /* handle interfaces */
1622 if (tb->interfaces) {
1623 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
1625 table->rows += mono_array_length (tb->interfaces);
1626 alloc_table (table, table->rows);
1627 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
1628 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
1629 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
1630 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
1631 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface->type);
1632 values += MONO_INTERFACEIMPL_SIZE;
1638 table = &assembly->tables [MONO_TABLE_FIELD];
1639 table->rows += mono_array_length (tb->fields);
1640 alloc_table (table, table->rows);
1641 for (i = 0; i < mono_array_length (tb->fields); ++i)
1642 mono_image_get_field_info (
1643 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
1646 /* handle constructors */
1648 table = &assembly->tables [MONO_TABLE_METHOD];
1649 table->rows += mono_array_length (tb->ctors);
1650 alloc_table (table, table->rows);
1651 for (i = 0; i < mono_array_length (tb->ctors); ++i)
1652 mono_image_get_ctor_info (domain,
1653 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
1656 /* handle methods */
1658 table = &assembly->tables [MONO_TABLE_METHOD];
1659 table->rows += mono_array_length (tb->methods);
1660 alloc_table (table, table->rows);
1661 for (i = 0; i < mono_array_length (tb->methods); ++i)
1662 mono_image_get_method_info (
1663 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
1666 /* Do the same with properties etc.. */
1667 if (tb->events && mono_array_length (tb->events)) {
1668 table = &assembly->tables [MONO_TABLE_EVENT];
1669 table->rows += mono_array_length (tb->events);
1670 alloc_table (table, table->rows);
1671 table = &assembly->tables [MONO_TABLE_EVENTMAP];
1673 alloc_table (table, table->rows);
1674 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
1675 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
1676 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
1677 for (i = 0; i < mono_array_length (tb->events); ++i)
1678 mono_image_get_event_info (
1679 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly);
1681 if (tb->properties && mono_array_length (tb->properties)) {
1682 table = &assembly->tables [MONO_TABLE_PROPERTY];
1683 table->rows += mono_array_length (tb->properties);
1684 alloc_table (table, table->rows);
1685 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
1687 alloc_table (table, table->rows);
1688 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
1689 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
1690 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
1691 for (i = 0; i < mono_array_length (tb->properties); ++i)
1692 mono_image_get_property_info (
1693 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
1696 MonoDynamicTable *ntable;
1698 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1699 table->rows += mono_array_length (tb->subtypes);
1700 alloc_table (table, table->rows);
1702 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
1703 ntable->rows += mono_array_length (tb->subtypes);
1704 alloc_table (ntable, ntable->rows);
1705 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
1707 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1708 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
1710 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
1711 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
1712 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
1713 mono_string_to_utf8 (subtype->name), subtype->table_idx,
1714 mono_string_to_utf8 (tb->name), tb->table_idx,
1715 ntable->next_idx, ntable->rows);*/
1716 values += MONO_NESTED_CLASS_SIZE;
1719 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
1720 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
1722 mono_image_get_type_info (domain, subtype, assembly);
1728 assign_type_idx (MonoReflectionTypeBuilder *type, MonoDynamicTable *table)
1732 type->table_idx = table->next_idx ++;
1733 if (!type->subtypes)
1735 for (j = 0; j < mono_array_length (type->subtypes); ++j) {
1736 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, j);
1737 assign_type_idx (subtype, table);
1742 params_add_cattrs (MonoDynamicAssembly *assembly, MonoArray *pinfo) {
1747 for (i = 0; i < mono_array_length (pinfo); ++i) {
1748 MonoReflectionParamBuilder *pb;
1749 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
1752 mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PARAMDEF, pb->cattrs);
1757 type_add_cattrs (MonoDynamicAssembly *assembly, MonoReflectionTypeBuilder *tb) {
1760 mono_image_add_cattrs (assembly, tb->table_idx, CUSTOM_ATTR_TYPEDEF, tb->cattrs);
1762 for (i = 0; i < mono_array_length (tb->fields); ++i) {
1763 MonoReflectionFieldBuilder* fb;
1764 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
1765 mono_image_add_cattrs (assembly, fb->table_idx, CUSTOM_ATTR_FIELDDEF, fb->cattrs);
1769 for (i = 0; i < mono_array_length (tb->events); ++i) {
1770 MonoReflectionEventBuilder* eb;
1771 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
1772 mono_image_add_cattrs (assembly, eb->table_idx, CUSTOM_ATTR_EVENT, eb->cattrs);
1775 if (tb->properties) {
1776 for (i = 0; i < mono_array_length (tb->properties); ++i) {
1777 MonoReflectionPropertyBuilder* pb;
1778 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
1779 mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PROPERTY, pb->cattrs);
1783 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
1784 MonoReflectionCtorBuilder* cb;
1785 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
1786 mono_image_add_cattrs (assembly, cb->table_idx, CUSTOM_ATTR_METHODDEF, cb->cattrs);
1787 params_add_cattrs (assembly, cb->pinfo);
1792 for (i = 0; i < mono_array_length (tb->methods); ++i) {
1793 MonoReflectionMethodBuilder* mb;
1794 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
1795 mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_METHODDEF, mb->cattrs);
1796 params_add_cattrs (assembly, mb->pinfo);
1801 for (i = 0; i < mono_array_length (tb->subtypes); ++i)
1802 type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i));
1807 module_add_cattrs (MonoDynamicAssembly *assembly, MonoReflectionModuleBuilder *mb) {
1810 mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_MODULE, mb->cattrs);
1812 /* no types in the module */
1816 for (i = 0; i < mono_array_length (mb->types); ++i)
1817 type_add_cattrs (assembly, mono_array_get (mb->types, MonoReflectionTypeBuilder*, i));
1821 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
1823 MonoDynamicTable *table;
1827 table = &assembly->tables [MONO_TABLE_MODULE];
1828 mb->table_idx = table->next_idx ++;
1829 name = mono_string_to_utf8 (mb->module.name);
1830 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
1832 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
1835 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
1836 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
1837 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
1839 /* no types in the module */
1844 * fill-in info in other tables as well.
1846 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1847 table->rows += mono_array_length (mb->types);
1848 alloc_table (table, table->rows);
1850 * We assign here the typedef indexes to avoid mismatches if a type that
1851 * has not yet been stored in the tables is referenced by another type.
1853 for (i = 0; i < mono_array_length (mb->types); ++i) {
1854 MonoReflectionTypeBuilder *type = mono_array_get (mb->types, MonoReflectionTypeBuilder*, i);
1855 assign_type_idx (type, table);
1857 for (i = 0; i < mono_array_length (mb->types); ++i)
1858 mono_image_get_type_info (domain, mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
1861 #define align_pointer(base,p)\
1863 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
1865 (p) += 4 - (__diff & 3);\
1869 compare_semantics (const void *a, const void *b)
1871 const guint32 *a_values = a;
1872 const guint32 *b_values = b;
1873 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
1876 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
1880 compare_custom_attrs (const void *a, const void *b)
1882 const guint32 *a_values = a;
1883 const guint32 *b_values = b;
1885 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
1889 compare_field_marshal (const void *a, const void *b)
1891 const guint32 *a_values = a;
1892 const guint32 *b_values = b;
1894 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
1898 compare_nested (const void *a, const void *b)
1900 const guint32 *a_values = a;
1901 const guint32 *b_values = b;
1903 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
1907 * build_compressed_metadata() fills in the blob of data that represents the
1908 * raw metadata as it will be saved in the PE file. The five streams are output
1909 * and the metadata tables are comnpressed from the guint32 array representation,
1910 * to the compressed on-disk format.
1913 build_compressed_metadata (MonoDynamicAssembly *assembly)
1915 MonoDynamicTable *table;
1917 guint64 valid_mask = 0;
1918 guint64 sorted_mask;
1919 guint32 heapt_size = 0;
1920 guint32 meta_size = 256; /* allow for header and other stuff */
1921 guint32 table_offset;
1922 guint32 ntables = 0;
1929 * We need to use the current ms version or the ms runtime it won't find
1930 * the support dlls. D'oh!
1931 * const char *version = "mono-" VERSION;
1933 const char *version = "v1.0.3705";
1936 MonoDynamicStream *stream;
1937 } stream_desc [] = {
1938 {"#~", &assembly->tstream},
1939 {"#Strings", &assembly->sheap},
1940 {"#US", &assembly->us},
1941 {"#Blob", &assembly->blob},
1942 {"#GUID", &assembly->guid}
1945 /* tables that are sorted */
1946 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
1947 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
1948 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
1949 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
1950 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
1951 | ((guint64)1 << MONO_TABLE_DECLSECURITY);
1953 /* Compute table sizes */
1954 /* the MonoImage has already been created in mono_image_basic_init() */
1955 meta = assembly->assembly.image;
1957 /* Setup the info used by compute_sizes () */
1958 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
1959 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
1960 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
1962 meta_size += assembly->blob.index;
1963 meta_size += assembly->guid.index;
1964 meta_size += assembly->sheap.index;
1965 meta_size += assembly->us.index;
1967 for (i=0; i < 64; ++i)
1968 meta->tables [i].rows = assembly->tables [i].rows;
1970 for (i = 0; i < 64; i++){
1971 if (meta->tables [i].rows == 0)
1973 valid_mask |= (guint64)1 << i;
1975 meta->tables [i].row_size = mono_metadata_compute_size (
1976 meta, i, &meta->tables [i].size_bitfield);
1977 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
1979 heapt_size += 24; /* #~ header size */
1980 heapt_size += ntables * 4;
1981 meta_size += heapt_size;
1982 meta->raw_metadata = g_malloc0 (meta_size);
1983 p = meta->raw_metadata;
1984 /* the metadata signature */
1985 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
1986 /* version numbers and 4 bytes reserved */
1987 int16val = (guint16*)p;
1988 *int16val++ = GUINT16_TO_LE (1);
1989 *int16val = GUINT16_TO_LE (1);
1991 /* version string */
1992 int32val = (guint32*)p;
1993 *int32val = GUINT32_TO_LE ((strlen (version) + 3) & (~3)); /* needs to be multiple of 4 */
1995 memcpy (p, version, GUINT32_FROM_LE (*int32val));
1996 p += GUINT32_FROM_LE (*int32val);
1997 align_pointer (meta->raw_metadata, p);
1998 int16val = (guint16*)p;
1999 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
2000 *int16val = GUINT16_TO_LE (5); /* number of streams */
2004 * write the stream info.
2006 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
2007 table_offset += 3; table_offset &= ~3;
2009 assembly->tstream.index = heapt_size;
2010 for (i = 0; i < 5; ++i) {
2011 int32val = (guint32*)p;
2012 stream_desc [i].stream->offset = table_offset;
2013 *int32val++ = GUINT32_TO_LE (table_offset);
2014 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
2015 table_offset += GUINT32_FROM_LE (*int32val);
2016 table_offset += 3; table_offset &= ~3;
2018 strcpy (p, stream_desc [i].name);
2019 p += strlen (stream_desc [i].name) + 1;
2020 align_pointer (meta->raw_metadata, p);
2023 * now copy the data, the table stream header and contents goes first.
2025 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
2026 p = meta->raw_metadata + assembly->tstream.offset;
2027 int32val = (guint32*)p;
2028 *int32val = GUINT32_TO_LE (0); /* reserved */
2030 *p++ = 1; /* version */
2032 if (meta->idx_string_wide)
2034 if (meta->idx_guid_wide)
2036 if (meta->idx_blob_wide)
2039 *p++ = 0; /* reserved */
2040 int64val = (guint64*)p;
2041 *int64val++ = GUINT64_TO_LE (valid_mask);
2042 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
2044 int32val = (guint32*)p;
2045 for (i = 0; i < 64; i++){
2046 if (meta->tables [i].rows == 0)
2048 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
2050 p = (unsigned char*)int32val;
2052 /* sort the tables that still need sorting */
2053 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
2055 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
2056 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2058 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
2059 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
2061 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
2062 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
2064 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
2066 /* compress the tables */
2067 for (i = 0; i < 64; i++){
2070 guint32 bitfield = meta->tables [i].size_bitfield;
2071 if (!meta->tables [i].rows)
2073 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
2074 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
2075 meta->tables [i].base = p;
2076 for (row = 1; row <= meta->tables [i].rows; ++row) {
2077 values = assembly->tables [i].values + row * assembly->tables [i].columns;
2078 for (col = 0; col < assembly->tables [i].columns; ++col) {
2079 switch (mono_metadata_table_size (bitfield, col)) {
2081 *p++ = values [col];
2084 *p++ = values [col] & 0xff;
2085 *p++ = (values [col] >> 8) & 0xff;
2088 *p++ = values [col] & 0xff;
2089 *p++ = (values [col] >> 8) & 0xff;
2090 *p++ = (values [col] >> 16) & 0xff;
2091 *p++ = (values [col] >> 24) & 0xff;
2094 g_assert_not_reached ();
2098 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
2101 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
2102 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
2103 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
2104 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
2105 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
2107 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
2111 * Some tables in metadata need to be sorted according to some criteria, but
2112 * when methods and fields are first created with reflection, they may be assigned a token
2113 * that doesn't correspond to the final token they will get assigned after the sorting.
2114 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
2115 * with the reflection objects that represent them. Once all the tables are set up, the
2116 * reflection objects will contains the correct table index. fixup_method() will fixup the
2117 * tokens for the method with ILGenerator @ilgen.
2120 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *assembly) {
2121 guint32 code_idx = GPOINTER_TO_UINT (value);
2122 MonoReflectionILTokenInfo *iltoken;
2123 MonoReflectionFieldBuilder *field;
2124 MonoReflectionCtorBuilder *ctor;
2125 MonoReflectionMethodBuilder *method;
2126 MonoReflectionTypeBuilder *tb;
2128 unsigned char *target;
2130 for (i = 0; i < ilgen->num_token_fixups; ++i) {
2131 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
2132 target = assembly->code.data + code_idx + iltoken->code_pos;
2133 switch (target [3]) {
2134 case MONO_TABLE_FIELD:
2135 if (strcmp (iltoken->member->vtable->klass->name, "FieldBuilder"))
2136 g_assert_not_reached ();
2137 field = (MonoReflectionFieldBuilder *)iltoken->member;
2138 idx = field->table_idx;
2140 case MONO_TABLE_METHOD:
2141 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
2142 method = (MonoReflectionMethodBuilder *)iltoken->member;
2143 idx = method->table_idx;
2144 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
2145 ctor = (MonoReflectionCtorBuilder *)iltoken->member;
2146 idx = ctor->table_idx;
2148 g_assert_not_reached ();
2151 case MONO_TABLE_TYPEDEF:
2152 if (strcmp (iltoken->member->vtable->klass->name, "TypeBuilder"))
2153 g_assert_not_reached ();
2154 tb = (MonoReflectionTypeBuilder *)iltoken->member;
2155 idx = tb->table_idx;
2158 g_error ("got unexpected table 0x%02x in fixup", target [3]);
2160 target [0] = idx & 0xff;
2161 target [1] = (idx >> 8) & 0xff;
2162 target [2] = (idx >> 16) & 0xff;
2167 assembly_add_resource (MonoDynamicAssembly *assembly, MonoReflectionResource *rsrc)
2169 MonoDynamicTable *table;
2173 char *b = blob_size;
2175 guint32 idx, offset;
2177 if (rsrc->filename) {
2178 name = mono_string_to_utf8 (rsrc->filename);
2179 sname = g_path_get_basename (name);
2181 table = &assembly->tables [MONO_TABLE_FILE];
2183 alloc_table (table, table->rows);
2184 values = table->values + table->next_idx * MONO_FILE_SIZE;
2185 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
2186 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
2189 mono_sha1_get_digest_from_file (name, hash);
2190 mono_metadata_encode_value (20, b, &b);
2191 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
2192 mono_image_add_stream_data (&assembly->blob, hash, 20);
2194 idx = table->next_idx++;
2195 idx = IMPLEMENTATION_FILE | (idx << IMPLEMENTATION_BITS);
2199 offset = mono_array_length (rsrc->data);
2200 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
2201 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
2202 offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
2203 mono_image_add_stream_data (&assembly->resources, mono_array_addr (rsrc->data, char, 0), mono_array_length (rsrc->data));
2207 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
2209 alloc_table (table, table->rows);
2210 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
2211 values [MONO_MANIFEST_OFFSET] = offset;
2212 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
2213 name = mono_string_to_utf8 (rsrc->name);
2214 values [MONO_MANIFEST_NAME] = string_heap_insert (&assembly->sheap, name);
2216 values [MONO_MANIFEST_IMPLEMENTATION] = idx;
2221 set_version_from_string (MonoString *version, guint32 *values)
2223 gchar *ver, *p, *str;
2226 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
2227 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
2228 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
2229 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
2232 ver = str = mono_string_to_utf8 (version);
2233 for (i = 0; i < 4; ++i) {
2234 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
2240 /* handle Revision and Build */
2250 load_public_key (MonoString *fname, MonoDynamicAssembly *assembly) {
2251 char *name, *content;
2257 name = mono_string_to_utf8 (fname);
2258 if (g_file_get_contents (name, &content, &len, NULL)) {
2260 char *b = blob_size;
2261 /* check it's a public key or keypair */
2262 mono_metadata_encode_value (len, b, &b);
2263 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
2264 mono_image_add_stream_data (&assembly->blob, content, len);
2266 /* need to get the actual value from the key type... */
2267 assembly->strong_name_size = 128;
2268 assembly->strong_name = g_malloc0 (assembly->strong_name_size);
2270 /* FIXME: how do we tell mcs if loading fails? */
2276 * mono_image_build_metadata() will fill the info in all the needed metadata tables
2277 * for the AssemblyBuilder @assemblyb: it iterates over the assembly modules
2278 * and recursively outputs the info for a module. Each module will output all the info
2279 * about it's types etc.
2280 * At the end of the process, method and field tokens are fixed up and the on-disk
2281 * compressed metadata representation is created.
2284 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
2286 MonoDynamicTable *table;
2287 MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
2288 MonoDomain *domain = mono_object_domain (assemblyb);
2294 assembly->text_rva = START_TEXT_RVA;
2296 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
2297 alloc_table (table, 1);
2298 values = table->values + MONO_ASSEMBLY_SIZE;
2299 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
2300 name = mono_string_to_utf8 (assemblyb->name);
2301 values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
2303 if (assemblyb->culture) {
2304 name = mono_string_to_utf8 (assemblyb->culture);
2305 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, name);
2308 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
2310 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->keyfile, assembly);
2311 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
2312 set_version_from_string (assemblyb->version, values);
2314 table = &assembly->tables [MONO_TABLE_TYPEDEF];
2315 table->rows = 1; /* .<Module> */
2317 alloc_table (table, table->rows);
2319 * Set the first entry.
2321 values = table->values + table->columns;
2322 values [MONO_TYPEDEF_FLAGS] = 0;
2323 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
2324 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
2325 values [MONO_TYPEDEF_EXTENDS] = 0;
2326 values [MONO_TYPEDEF_FIELD_LIST] = 1;
2327 values [MONO_TYPEDEF_METHOD_LIST] = 1;
2330 * handle global methods
2331 * FIXME: test what to do when global methods are defined in multiple modules.
2333 if (assemblyb->modules) {
2334 MonoReflectionModuleBuilder *mod = mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, 0);
2335 if (mod->global_methods) {
2336 table = &assembly->tables [MONO_TABLE_METHOD];
2337 table->rows += mono_array_length (mod->global_methods);
2338 alloc_table (table, table->rows);
2339 for (i = 0; i < mono_array_length (mod->global_methods); ++i)
2340 mono_image_get_method_info (
2341 mono_array_get (mod->global_methods, MonoReflectionMethodBuilder*, i), assembly);
2345 if (assemblyb->modules) {
2346 len = mono_array_length (assemblyb->modules);
2347 table = &assembly->tables [MONO_TABLE_MODULE];
2348 alloc_table (table, len);
2349 for (i = 0; i < len; ++i)
2350 mono_image_fill_module_table (domain, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
2352 table = &assembly->tables [MONO_TABLE_MODULE];
2354 alloc_table (table, table->rows);
2355 table->values [table->next_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, "RefEmit_YouForgotToDefineAModule");
2360 * table->rows is already set above and in mono_image_fill_module_table.
2362 /* add all the custom attributes at the end, once all the indexes are stable */
2363 mono_image_add_cattrs (assembly, 1, CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs);
2365 if (assemblyb->modules) {
2366 len = mono_array_length (assemblyb->modules);
2367 for (i = 0; i < len; ++i)
2368 module_add_cattrs (assembly, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i));
2371 if (assemblyb->resources) {
2372 len = mono_array_length (assemblyb->resources);
2373 for (i = 0; i < len; ++i)
2374 assembly_add_resource (assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i));
2378 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
2380 build_compressed_metadata (assembly);
2384 * mono_image_insert_string:
2385 * @assembly: assembly builder object
2388 * Insert @str into the user string stream of @assembly.
2391 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
2397 MONO_ARCH_SAVE_REGS;
2399 if (!assembly->dynamic_assembly)
2400 mono_image_basic_init (assembly);
2401 mono_metadata_encode_value (1 | (str->length * 2), b, &b);
2402 idx = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
2403 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2405 char *swapped = g_malloc (2 * mono_string_length (str));
2406 const char *p = (const char*)mono_string_chars (str);
2408 swap_with_size (swapped, p, 2, mono_string_length (str));
2409 mono_image_add_stream_data (&assembly->dynamic_assembly->us, swapped, str->length * 2);
2413 mono_image_add_stream_data (&assembly->dynamic_assembly->us, (const char*)mono_string_chars (str), str->length * 2);
2415 mono_image_add_stream_data (&assembly->dynamic_assembly->us, "", 1);
2417 g_hash_table_insert (assembly->dynamic_assembly->tokens,
2418 GUINT_TO_POINTER (MONO_TOKEN_STRING | idx), str);
2420 return MONO_TOKEN_STRING | idx;
2424 * mono_image_create_token:
2425 * @assembly: a dynamic assembly
2428 * Get a token to insert in the IL code stream for the given MemberInfo.
2429 * @obj can be one of:
2430 * ConstructorBuilder
2440 mono_image_create_token (MonoDynamicAssembly *assembly, MonoObject *obj)
2446 g_error ("System.Array methods not yet supported");
2448 klass = obj->vtable->klass;
2449 if (strcmp (klass->name, "MethodBuilder") == 0) {
2450 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
2451 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
2452 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
2454 else if (strcmp (klass->name, "ConstructorBuilder") == 0) {
2455 MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
2456 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
2457 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
2459 else if (strcmp (klass->name, "FieldBuilder") == 0) {
2460 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
2461 token = mb->table_idx | MONO_TOKEN_FIELD_DEF;
2463 else if (strcmp (klass->name, "TypeBuilder") == 0) {
2464 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
2465 token = tb->table_idx | MONO_TOKEN_TYPE_DEF;
2467 else if (strcmp (klass->name, "MonoType") == 0) {
2468 MonoReflectionType *tb = (MonoReflectionType *)obj;
2469 token = mono_metadata_token_from_dor (
2470 mono_image_typedef_or_ref (assembly, tb->type));
2472 else if (strcmp (klass->name, "MonoCMethod") == 0 ||
2473 strcmp (klass->name, "MonoMethod") == 0) {
2474 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
2475 token = mono_image_get_methodref_token (assembly, m->method);
2476 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
2478 else if (strcmp (klass->name, "MonoField") == 0) {
2479 MonoReflectionField *f = (MonoReflectionField *)obj;
2480 token = mono_image_get_fieldref_token (assembly, f->field, f->klass);
2481 /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/
2483 else if (strcmp (klass->name, "MonoArrayMethod") == 0) {
2484 MonoReflectionArrayMethod *m = (MonoReflectionArrayMethod *)obj;
2485 token = mono_image_get_array_token (assembly, m);
2488 g_print ("requested token for %s\n", klass->name);
2490 g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token),
2497 guint32 import_lookup_table;
2501 guint32 import_address_table_rva;
2510 * mono_image_basic_init:
2511 * @assembly: an assembly builder object
2513 * Create the MonoImage that represents the assembly builder and setup some
2514 * of the helper hash table and the basic metadata streams.
2517 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
2519 static const guchar entrycode [16] = {0xff, 0x25, 0};
2520 MonoDynamicAssembly *assembly;
2524 MONO_ARCH_SAVE_REGS;
2526 if (assemblyb->dynamic_assembly)
2530 assembly = assemblyb->dynamic_assembly = GC_MALLOC (sizeof (MonoDynamicAssembly));
2532 assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
2535 assembly->assembly.dynamic = assembly;
2536 assemblyb->assembly.assembly = (MonoAssembly*)assembly;
2537 assembly->token_fixups = mono_g_hash_table_new (g_direct_hash, g_direct_equal);
2538 assembly->handleref = g_hash_table_new (g_direct_hash, g_direct_equal);
2539 assembly->tokens = g_hash_table_new (g_direct_hash, g_direct_equal);
2540 assembly->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
2541 assembly->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
2543 string_heap_init (&assembly->sheap);
2544 mono_image_add_stream_data (&assembly->us, "", 1);
2545 add_to_blob_cached (assembly, "", 1, NULL, 0);
2546 /* import tables... */
2547 mono_image_add_stream_data (&assembly->code, entrycode, sizeof (entrycode));
2548 assembly->iat_offset = mono_image_add_stream_zero (&assembly->code, 8); /* two IAT entries */
2549 assembly->idt_offset = mono_image_add_stream_zero (&assembly->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
2550 mono_image_add_stream_zero (&assembly->code, 2); /* flags for name entry */
2551 assembly->imp_names_offset = mono_image_add_stream_data (&assembly->code, "_CorExeMain", 12);
2552 mono_image_add_stream_data (&assembly->code, "mscoree.dll", 12);
2553 assembly->ilt_offset = mono_image_add_stream_zero (&assembly->code, 8); /* two ILT entries */
2554 stream_data_align (&assembly->code);
2556 assembly->cli_header_offset = mono_image_add_stream_zero (&assembly->code, sizeof (MonoCLIHeader));
2558 for (i=0; i < 64; ++i) {
2559 assembly->tables [i].next_idx = 1;
2560 assembly->tables [i].columns = table_sizes [i];
2563 image = g_new0 (MonoImage, 1);
2565 /* keep in sync with image.c */
2566 assembly->assembly.aname.name = image->name = mono_string_to_utf8 (assemblyb->name);
2567 image->assembly_name = image->name; /* they may be different */
2568 image->assembly = (MonoAssembly*)assembly;
2570 image->method_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2571 image->class_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2572 image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
2573 image->array_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2575 image->delegate_begin_invoke_cache =
2576 g_hash_table_new ((GHashFunc)mono_signature_hash,
2577 (GCompareFunc)mono_metadata_signature_equal);
2578 image->delegate_end_invoke_cache =
2579 g_hash_table_new ((GHashFunc)mono_signature_hash,
2580 (GCompareFunc)mono_metadata_signature_equal);
2581 image->delegate_invoke_cache =
2582 g_hash_table_new ((GHashFunc)mono_signature_hash,
2583 (GCompareFunc)mono_metadata_signature_equal);
2585 image->runtime_invoke_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2586 image->managed_wrapper_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2587 image->native_wrapper_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2588 image->remoting_invoke_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
2589 assembly->assembly.image = image;
2593 calc_section_size (MonoDynamicAssembly *assembly)
2597 /* alignment constraints */
2598 assembly->code.index += 3;
2599 assembly->code.index &= ~3;
2600 assembly->meta_size += 3;
2601 assembly->meta_size &= ~3;
2602 assembly->resources.index += 3;
2603 assembly->resources.index &= ~3;
2605 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
2606 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
2609 assembly->sections [MONO_SECTION_RELOC].size = 12;
2610 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
2617 * mono_image_create_pefile:
2618 * @assemblyb: an assembly builder object
2620 * When we need to save an assembly, we first call this function that ensures the metadata
2621 * tables are built for all the modules in the assembly. This function creates the PE-COFF
2622 * header, the image sections, the CLI header etc. all the data is written in
2623 * assembly->pefile where it can be easily retrieved later in chunks.
2626 mono_image_create_pefile (MonoReflectionAssemblyBuilder *assemblyb) {
2627 MonoMSDOSHeader *msdos;
2628 MonoDotNetHeader *header;
2629 MonoSectionTable *section;
2630 MonoCLIHeader *cli_header;
2631 guint32 size, image_size, virtual_base, text_offset;
2632 guint32 header_start, section_start, file_offset, virtual_offset;
2633 MonoDynamicAssembly *assembly;
2634 MonoDynamicStream *pefile;
2636 guint32 *rva, value;
2639 static const unsigned char msheader[] = {
2640 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
2641 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
2644 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
2645 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
2646 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
2647 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2650 mono_image_basic_init (assemblyb);
2651 assembly = assemblyb->dynamic_assembly;
2653 /* already created */
2654 if (assembly->pefile.index)
2657 mono_image_build_metadata (assemblyb);
2658 nsections = calc_section_size (assembly);
2660 pefile = &assembly->pefile;
2662 /* The DOS header and stub */
2663 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
2664 mono_image_add_stream_data (pefile, msheader, sizeof (msheader));
2666 /* the dotnet header */
2667 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
2669 /* the section tables */
2670 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
2672 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
2673 virtual_offset = VIRT_ALIGN;
2676 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2677 if (!assembly->sections [i].size)
2680 file_offset += FILE_ALIGN - 1;
2681 file_offset &= ~(FILE_ALIGN - 1);
2682 virtual_offset += VIRT_ALIGN - 1;
2683 virtual_offset &= ~(VIRT_ALIGN - 1);
2685 assembly->sections [i].offset = file_offset;
2686 assembly->sections [i].rva = virtual_offset;
2688 file_offset += assembly->sections [i].size;
2689 virtual_offset += assembly->sections [i].size;
2690 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
2693 file_offset += FILE_ALIGN - 1;
2694 file_offset &= ~(FILE_ALIGN - 1);
2695 mono_image_add_stream_zero (pefile, file_offset - pefile->index);
2697 image_size += section_start + sizeof (MonoSectionTable) * nsections;
2699 /* back-patch info */
2700 msdos = (MonoMSDOSHeader*)pefile->data;
2701 msdos->nlast_page = GUINT16_FROM_LE (file_offset & (512 - 1));
2702 msdos->npages = GUINT16_FROM_LE ((file_offset + (512 - 1)) / 512);
2703 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
2705 header = (MonoDotNetHeader*)(pefile->data + header_start);
2706 header->pesig [0] = 'P';
2707 header->pesig [1] = 'E';
2709 header->coff.coff_machine = GUINT16_FROM_LE (0x14c);
2710 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
2711 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
2712 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
2713 if (assemblyb->pekind == 1) {
2715 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
2718 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
2721 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
2723 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
2724 header->pe.pe_major = 6;
2725 header->pe.pe_minor = 0;
2726 size = assembly->sections [MONO_SECTION_TEXT].size;
2727 size += FILE_ALIGN - 1;
2728 size &= ~(FILE_ALIGN - 1);
2729 header->pe.pe_code_size = size;
2730 size = assembly->sections [MONO_SECTION_RSRC].size;
2731 size += FILE_ALIGN - 1;
2732 size &= ~(FILE_ALIGN - 1);
2733 header->pe.pe_data_size = size;
2734 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
2735 header->pe.pe_rva_code_base = assembly->sections [MONO_SECTION_TEXT].rva;
2736 header->pe.pe_rva_data_base = assembly->sections [MONO_SECTION_RSRC].rva;
2737 /* pe_rva_entry_point always at the beginning of the text section */
2738 header->pe.pe_rva_entry_point = assembly->sections [MONO_SECTION_TEXT].rva;
2740 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
2741 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
2742 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
2743 header->nt.pe_os_major = GUINT16_FROM_LE (4);
2744 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
2745 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
2746 size = section_start;
2747 size += FILE_ALIGN - 1;
2748 size &= ~(FILE_ALIGN - 1);
2749 header->nt.pe_header_size = GUINT32_FROM_LE (size);
2751 size += VIRT_ALIGN - 1;
2752 size &= ~(VIRT_ALIGN - 1);
2753 header->nt.pe_image_size = GUINT32_FROM_LE (size);
2756 // Translate the PEFileKind value to the value expected by the Windows loader
2759 short kind = assemblyb->pekind;
2762 // PEFileKinds.ConsoleApplication == 2
2763 // PEFileKinds.WindowApplication == 3
2766 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
2767 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
2773 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
2775 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
2776 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
2777 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
2778 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
2779 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
2780 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
2782 /* fill data directory entries */
2784 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
2785 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
2787 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
2788 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
2790 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
2791 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
2792 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
2793 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2794 /* patch imported function RVA name */
2795 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
2796 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
2798 /* the import table */
2799 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
2800 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
2801 /* patch imported dll RVA name and other entries in the dir */
2802 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
2803 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 12); /* 12 is strlen+1 of func name */
2804 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
2805 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
2806 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
2807 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
2809 p = (assembly->code.data + assembly->ilt_offset);
2810 value = (assembly->text_rva + assembly->imp_names_offset - 2);
2811 *p++ = (value) & 0xff;
2812 *p++ = (value >> 8) & (0xff);
2813 *p++ = (value >> 16) & (0xff);
2814 *p++ = (value >> 24) & (0xff);
2816 /* the CLI header info */
2817 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
2818 cli_header->ch_size = GUINT32_FROM_LE (72);
2819 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
2820 cli_header->ch_flags = GUINT32_FROM_LE (CLI_FLAGS_ILONLY);
2821 if (assemblyb->entry_point)
2822 cli_header->ch_entry_point = GUINT32_FROM_LE (assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF);
2824 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
2825 /* The embedded managed resources */
2826 text_offset = assembly->text_rva + assembly->code.index;
2827 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
2828 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
2829 text_offset += assembly->resources.index;
2830 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
2831 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
2832 text_offset += assembly->meta_size;
2833 if (assembly->strong_name_size) {
2834 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
2835 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
2836 text_offset += assembly->strong_name_size;
2839 /* write the section tables and section content */
2840 section = (MonoSectionTable*)(pefile->data + section_start);
2841 for (i = 0; i < MONO_SECTION_MAX; ++i) {
2842 static const char *section_names [] = {
2843 ".text", ".rsrc", ".reloc"
2845 if (!assembly->sections [i].size)
2847 strcpy (section->st_name, section_names [i]);
2848 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
2849 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
2850 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
2851 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
2852 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
2853 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
2854 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
2856 case MONO_SECTION_TEXT:
2857 /* patch entry point */
2858 p = (assembly->code.data + 2);
2859 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
2860 *p++ = (value) & 0xff;
2861 *p++ = (value >> 8) & 0xff;
2862 *p++ = (value >> 16) & 0xff;
2863 *p++ = (value >> 24) & 0xff;
2865 text_offset = assembly->sections [i].offset;
2866 memcpy (pefile->data + text_offset, assembly->code.data, assembly->code.index);
2867 text_offset += assembly->code.index;
2868 memcpy (pefile->data + text_offset, assembly->resources.data, assembly->resources.index);
2869 text_offset += assembly->resources.index;
2870 memcpy (pefile->data + text_offset, assembly->assembly.image->raw_metadata, assembly->meta_size);
2871 text_offset += assembly->meta_size;
2872 memcpy (pefile->data + text_offset, assembly->strong_name, assembly->strong_name_size);
2874 case MONO_SECTION_RELOC:
2875 rva = (guint32*)(pefile->data + assembly->sections [i].offset);
2876 *rva = GUINT32_FROM_LE (assembly->text_rva);
2878 *rva = GUINT32_FROM_LE (12);
2880 data16 = (guint16*)rva;
2882 * the entrypoint is always at the start of the text section
2883 * 3 is IMAGE_REL_BASED_HIGHLOW
2884 * 2 is patch_size_rva - text_rva
2886 *data16 = GUINT16_FROM_LE ((3 << 12) + (2));
2888 *data16 = 0; /* terminate */
2890 case MONO_SECTION_RSRC:
2892 g_assert_not_reached ();
2897 /* check that the file is properly padded */
2900 FILE *f = fopen ("mypetest.exe", "w");
2901 fwrite (pefile->data, pefile->index, 1, f);
2908 * We need to return always the same object for MethodInfo, FieldInfo etc..
2909 * but we need to consider the reflected type.
2910 * type uses a different hash, since it uses custom hash/equal functions.
2915 MonoClass *refclass;
2919 reflected_equal (gconstpointer a, gconstpointer b) {
2920 const ReflectedEntry *ea = a;
2921 const ReflectedEntry *eb = b;
2923 return (ea->item == eb->item) && (ea->refclass == eb->refclass);
2927 reflected_hash (gconstpointer a) {
2928 const ReflectedEntry *ea = a;
2929 return GPOINTER_TO_UINT (ea->item);
2932 #define CHECK_OBJECT(t,p,k) \
2938 mono_domain_lock (domain); \
2939 if (!domain->refobject_hash) \
2940 domain->refobject_hash = mono_g_hash_table_new (reflected_hash, reflected_equal); \
2941 if ((_obj = mono_g_hash_table_lookup (domain->refobject_hash, &e))) { \
2942 mono_domain_unlock (domain); \
2948 #define ALLOC_REFENTRY GC_MALLOC (sizeof (ReflectedEntry))
2950 #define ALLOC_REFENTRY mono_mempool_alloc (domain->mp, sizeof (ReflectedEntry))
2953 #define CACHE_OBJECT(p,o,k) \
2955 ReflectedEntry *e = ALLOC_REFENTRY; \
2957 e->refclass = (k); \
2958 mono_g_hash_table_insert (domain->refobject_hash, e,o); \
2959 mono_domain_unlock (domain); \
2963 * mono_assembly_get_object:
2964 * @domain: an app domain
2965 * @assembly: an assembly
2967 * Return an System.Reflection.Assembly object representing the MonoAssembly @assembly.
2969 MonoReflectionAssembly*
2970 mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly)
2972 static MonoClass *System_Reflection_Assembly;
2973 MonoReflectionAssembly *res;
2975 CHECK_OBJECT (MonoReflectionAssembly *, assembly, NULL);
2976 if (!System_Reflection_Assembly)
2977 System_Reflection_Assembly = mono_class_from_name (
2978 mono_defaults.corlib, "System.Reflection", "Assembly");
2979 res = (MonoReflectionAssembly *)mono_object_new (domain, System_Reflection_Assembly);
2980 res->assembly = assembly;
2981 CACHE_OBJECT (assembly, res, NULL);
2986 MonoReflectionModule*
2987 mono_module_get_object (MonoDomain *domain, MonoImage *image)
2989 static MonoClass *System_Reflection_Module;
2990 MonoReflectionModule *res;
2992 CHECK_OBJECT (MonoReflectionModule *, image, NULL);
2993 if (!System_Reflection_Module)
2994 System_Reflection_Module = mono_class_from_name (
2995 mono_defaults.corlib, "System.Reflection", "Module");
2996 res = (MonoReflectionModule *)mono_object_new (domain, System_Reflection_Module);
2999 res->assembly = (MonoReflectionAssembly *) mono_assembly_get_object(domain, image->assembly);
3001 res->fqname = mono_string_new (domain, image->name);
3002 res->name = mono_string_new (domain, image->name);
3003 res->scopename = mono_string_new (domain, image->module_name);
3005 CACHE_OBJECT (image, res, NULL);
3011 mymono_metadata_type_equal (MonoType *t1, MonoType *t2)
3013 if ((t1->type != t2->type) ||
3014 (t1->byref != t2->byref))
3018 case MONO_TYPE_VOID:
3019 case MONO_TYPE_BOOLEAN:
3020 case MONO_TYPE_CHAR:
3031 case MONO_TYPE_STRING:
3034 case MONO_TYPE_OBJECT:
3036 case MONO_TYPE_VALUETYPE:
3037 case MONO_TYPE_CLASS:
3038 return t1->data.klass == t2->data.klass;
3040 case MONO_TYPE_SZARRAY:
3041 return mymono_metadata_type_equal (t1->data.type, t2->data.type);
3042 case MONO_TYPE_ARRAY:
3043 if (t1->data.array->rank != t2->data.array->rank)
3045 return mymono_metadata_type_equal (t1->data.array->type, t2->data.array->type);
3047 g_error ("implement type compare for %0x!", t1->type);
3055 mymono_metadata_type_hash (MonoType *t1)
3061 hash |= t1->byref << 6; /* do not collide with t1->type values */
3063 case MONO_TYPE_VALUETYPE:
3064 case MONO_TYPE_CLASS:
3065 /* check if the distribution is good enough */
3066 return hash << 7 | g_str_hash (t1->data.klass->name);
3068 case MONO_TYPE_SZARRAY:
3069 return hash << 7 | mymono_metadata_type_hash (t1->data.type);
3075 * mono_type_get_object:
3076 * @domain: an app domain
3079 * Return an System.MonoType object representing the type @type.
3082 mono_type_get_object (MonoDomain *domain, MonoType *type)
3084 MonoReflectionType *res;
3085 MonoClass *klass = mono_class_from_mono_type (type);
3087 mono_domain_lock (domain);
3088 if (!domain->type_hash)
3089 domain->type_hash = mono_g_hash_table_new ((GHashFunc)mymono_metadata_type_hash,
3090 (GCompareFunc)mymono_metadata_type_equal);
3091 if ((res = mono_g_hash_table_lookup (domain->type_hash, type))) {
3092 mono_domain_unlock (domain);
3095 if (klass->reflection_info && !klass->wastypebuilder) {
3096 //g_assert_not_reached ();
3097 /* should this be considered an error condition? */
3099 mono_domain_unlock (domain);
3100 return klass->reflection_info;
3103 mono_class_init (klass);
3104 res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class);
3106 mono_g_hash_table_insert (domain->type_hash, type, res);
3107 mono_domain_unlock (domain);
3112 * mono_method_get_object:
3113 * @domain: an app domain
3115 * @refclass: the reflected type (can be NULL)
3117 * Return an System.Reflection.MonoMethod object representing the method @method.
3119 MonoReflectionMethod*
3120 mono_method_get_object (MonoDomain *domain, MonoMethod *method, MonoClass *refclass)
3123 * We use the same C representation for methods and constructors, but the type
3124 * name in C# is different.
3128 MonoReflectionMethod *ret;
3131 refclass = method->klass;
3133 CHECK_OBJECT (MonoReflectionMethod *, method, refclass);
3134 if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
3135 cname = "MonoCMethod";
3137 cname = "MonoMethod";
3138 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
3140 ret = (MonoReflectionMethod*)mono_object_new (domain, klass);
3141 ret->method = method;
3142 ret->name = mono_string_new (domain, method->name);
3143 ret->reftype = mono_type_get_object (domain, &refclass->byval_arg);
3144 CACHE_OBJECT (method, ret, refclass);
3149 * mono_field_get_object:
3150 * @domain: an app domain
3154 * Return an System.Reflection.MonoField object representing the field @field
3157 MonoReflectionField*
3158 mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *field)
3160 MonoReflectionField *res;
3163 CHECK_OBJECT (MonoReflectionField *, field, klass);
3164 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
3165 res = (MonoReflectionField *)mono_object_new (domain, oklass);
3168 CACHE_OBJECT (field, res, klass);
3173 * mono_property_get_object:
3174 * @domain: an app domain
3176 * @property: a property
3178 * Return an System.Reflection.MonoProperty object representing the property @property
3181 MonoReflectionProperty*
3182 mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *property)
3184 MonoReflectionProperty *res;
3187 CHECK_OBJECT (MonoReflectionProperty *, property, klass);
3188 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
3189 res = (MonoReflectionProperty *)mono_object_new (domain, oklass);
3191 res->property = property;
3192 CACHE_OBJECT (property, res, klass);
3197 * mono_event_get_object:
3198 * @domain: an app domain
3202 * Return an System.Reflection.MonoEvent object representing the event @event
3205 MonoReflectionEvent*
3206 mono_event_get_object (MonoDomain *domain, MonoClass *klass, MonoEvent *event)
3208 MonoReflectionEvent *res;
3211 CHECK_OBJECT (MonoReflectionEvent *, event, klass);
3212 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoEvent");
3213 res = (MonoReflectionEvent *)mono_object_new (domain, oklass);
3216 CACHE_OBJECT (event, res, klass);
3221 * mono_param_get_objects:
3222 * @domain: an app domain
3225 * Return an System.Reflection.ParameterInfo array object representing the parameters
3226 * in the method @method.
3228 MonoReflectionParameter**
3229 mono_param_get_objects (MonoDomain *domain, MonoMethod *method)
3231 MonoReflectionParameter **res;
3232 MonoReflectionMethod *member;
3237 if (!method->signature->param_count)
3240 member = mono_method_get_object (domain, method, NULL);
3241 names = g_new (char *, method->signature->param_count);
3242 mono_method_get_param_names (method, (const char **) names);
3244 /* Note: the cache is based on the address of the signature into the method
3245 * since we already cache MethodInfos with the method as keys.
3247 CHECK_OBJECT (MonoReflectionParameter**, &(method->signature), NULL);
3248 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
3250 res = GC_MALLOC (sizeof (MonoReflectionParameter*) * method->signature->param_count);
3252 res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
3254 for (i = 0; i < method->signature->param_count; ++i) {
3255 res [i] = (MonoReflectionParameter *)mono_object_new (domain, oklass);
3256 res [i]->ClassImpl = mono_type_get_object (domain, method->signature->params [i]);
3257 res [i]->DefaultValueImpl = NULL; /* FIXME */
3258 res [i]->MemberImpl = (MonoObject*)member;
3259 res [i]->NameImpl = mono_string_new (domain, names [i]);
3260 res [i]->PositionImpl = i + 1;
3261 res [i]->AttrsImpl = method->signature->params [i]->attrs;
3264 CACHE_OBJECT (&(method->signature), res, NULL);
3269 assembly_name_to_aname (MonoAssemblyName *assembly, char *p) {
3273 memset (assembly, 0, sizeof (MonoAssemblyName));
3275 assembly->culture = "";
3277 while (*p && (isalnum (*p) || *p == '.'))
3280 while (*p == ' ' || *p == ',') {
3289 if (*p == 'V' && strncmp (p, "Version=", 8) == 0) {
3291 assembly->major = strtoul (p, &s, 10);
3292 if (s == p || *s != '.')
3295 assembly->minor = strtoul (p, &s, 10);
3296 if (s == p || *s != '.')
3299 assembly->build = strtoul (p, &s, 10);
3300 if (s == p || *s != '.')
3303 assembly->revision = strtoul (p, &s, 10);
3306 } else if (*p == 'C' && strncmp (p, "Culture=", 8) == 0) {
3308 if (strncmp (p, "neutral", 7) == 0) {
3309 assembly->culture = "";
3312 assembly->culture = p;
3313 while (*p && *p != ',') {
3317 } else if (*p == 'P' && strncmp (p, "PublicKeyToken=", 15) == 0) {
3320 while (*s && isxdigit (*s)) {
3324 assembly->hash_len = s - p;
3325 if (!(s-p) || ((s-p) & 1))
3327 assembly->hash_value = s = p;
3328 while (*s && isxdigit (*s)) {
3330 val = *s >= '0' && *s <= '9'? *s - '0': *s - 'a' + 10;
3333 *p |= *s >= '0' && *s <= '9'? *s - '0': *s - 'a' + 10;
3341 while (*p == ' ' || *p == ',') {
3355 * mono_reflection_parse_type:
3358 * Parse a type name as accepted by the GetType () method and output the info
3359 * extracted in the info structure.
3360 * the name param will be mangled, so, make a copy before passing it to this function.
3361 * The fields in info will be valid until the memory pointed to by name is valid.
3362 * Returns 0 on parse error.
3363 * See also mono_type_get_name () below.
3366 mono_reflection_parse_type (char *name, MonoTypeNameParse *info) {
3368 char *start, *p, *w, *last_point, *startn;
3369 int in_modifiers = 0;
3370 int isbyref = 0, rank;
3372 start = p = w = name;
3374 memset (&info->assembly, 0, sizeof (MonoAssemblyName));
3375 info->name = info->name_space = NULL;
3376 info->nested = NULL;
3377 info->modifiers = NULL;
3379 /* last_point separates the namespace from the name */
3385 *p = 0; /* NULL terminate the name */
3387 /* we have parsed the nesting namespace + name */
3389 info->nested = g_list_append (info->nested, startn);
3393 info->name_space = start;
3395 info->name = last_point + 1;
3397 info->name_space = (char *)"";
3422 info->nested = g_list_append (info->nested, startn);
3425 info->name_space = start;
3427 info->name = last_point + 1;
3429 info->name_space = (char *)"";
3436 if (isbyref) /* only one level allowed by the spec */
3439 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (0));
3443 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-1));
3454 else if (*p != '*') /* '*' means unknown lower bound */
3460 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank));
3472 return 0; /* missing assembly name */
3473 if (!assembly_name_to_aname (&info->assembly, p))
3479 if (info->assembly.name)
3482 *w = 0; /* terminate class name */
3483 if (!info->name || !*info->name)
3485 /* add other consistency checks */
3490 mono_type_get_name_recurse (MonoType *type, GString *str)
3494 switch (type->type) {
3495 case MONO_TYPE_ARRAY: {
3496 int i, rank = type->data.array->rank;
3498 mono_type_get_name_recurse (type->data.array->type, str);
3499 g_string_append_c (str, '[');
3500 for (i = 1; i < rank; i++)
3501 g_string_append_c (str, ',');
3502 g_string_append_c (str, ']');
3505 case MONO_TYPE_SZARRAY:
3506 mono_type_get_name_recurse (type->data.type, str);
3507 g_string_append (str, "[]");
3510 mono_type_get_name_recurse (type->data.type, str);
3511 g_string_append_c (str, '*');
3514 klass = mono_class_from_mono_type (type);
3515 if (klass->nested_in) {
3516 mono_type_get_name_recurse (&klass->nested_in->byval_arg, str);
3517 g_string_append_c (str, '+');
3519 if (*klass->name_space) {
3520 g_string_append (str, klass->name_space);
3521 g_string_append_c (str, '.');
3523 g_string_append (str, klass->name);
3529 * mono_type_get_name:
3532 * Returns the string representation for type as required by System.Reflection.
3533 * The inverse of mono_reflection_parse_type ().
3536 mono_type_get_name (MonoType *type)
3538 GString* result = g_string_new ("");
3539 mono_type_get_name_recurse (type, result);
3542 g_string_append_c (result, '&');
3544 return g_string_free (result, FALSE);
3548 * mono_reflection_get_type:
3549 * @image: a metadata context
3550 * @info: type description structure
3551 * @ignorecase: flag for case-insensitive string compares
3553 * Build a MonoType from the type description in @info.
3557 mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase)
3564 image = mono_defaults.corlib;
3567 klass = mono_class_from_name_case (image, info->name_space, info->name);
3569 klass = mono_class_from_name (image, info->name_space, info->name);
3572 for (mod = info->nested; mod; mod = mod->next) {
3575 mono_class_init (klass);
3576 nested = klass->nested_classes;
3579 klass = nested->data;
3581 if (g_strcasecmp (klass->name, mod->data) == 0)
3584 if (strcmp (klass->name, mod->data) == 0)
3588 nested = nested->next;
3595 mono_class_init (klass);
3596 for (mod = info->modifiers; mod; mod = mod->next) {
3597 modval = GPOINTER_TO_UINT (mod->data);
3598 if (!modval) { /* byref: must be last modifier */
3599 return &klass->this_arg;
3600 } else if (modval == -1) {
3601 klass = mono_ptr_class_get (&klass->byval_arg);
3602 } else { /* array rank */
3603 klass = mono_array_class_get (&klass->byval_arg, modval);
3605 mono_class_init (klass);
3607 return &klass->byval_arg;
3611 * mono_reflection_type_from_name:
3613 * @image: a metadata context (can be NULL).
3615 * Retrieves a MonoType from its @name. If the name is not fully qualified,
3616 * it defaults to get the type from @image or, if @image is NULL or loading
3617 * from it fails, uses corlib.
3621 mono_reflection_type_from_name (char *name, MonoImage *image)
3624 MonoTypeNameParse info;
3626 /*g_print ("requested type %s\n", str);*/
3627 if (!mono_reflection_parse_type (name, &info)) {
3628 g_list_free (info.modifiers);
3629 g_list_free (info.nested);
3633 if (info.assembly.name) {
3634 image = mono_image_loaded (info.assembly.name);
3635 /* do we need to load if it's not already loaded? */
3637 g_list_free (info.modifiers);
3638 g_list_free (info.nested);
3641 } else if (image == NULL) {
3642 image = mono_defaults.corlib;
3645 type = mono_reflection_get_type (image, &info, FALSE);
3646 if (type == NULL && !info.assembly.name && image != mono_defaults.corlib) {
3647 image = mono_defaults.corlib;
3648 type = mono_reflection_get_type (image, &info, FALSE);
3651 g_list_free (info.modifiers);
3652 g_list_free (info.nested);
3657 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end)
3659 int slen, type = t->type;
3664 case MONO_TYPE_BOOLEAN: {
3665 MonoBoolean *bval = g_malloc (sizeof (MonoBoolean));
3670 case MONO_TYPE_CHAR:
3672 case MONO_TYPE_I2: {
3673 guint16 *val = g_malloc (sizeof (guint16));
3678 #if SIZEOF_VOID_P == 4
3684 case MONO_TYPE_I4: {
3685 guint32 *val = g_malloc (sizeof (guint32));
3690 #if SIZEOF_VOID_P == 8
3691 case MONO_TYPE_U: /* error out instead? this should probably not happen */
3696 case MONO_TYPE_I8: {
3697 guint64 *val = g_malloc (sizeof (guint64));
3702 case MONO_TYPE_VALUETYPE:
3703 if (t->data.klass->enumtype) {
3704 type = t->data.klass->enum_basetype->type;
3707 g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
3710 case MONO_TYPE_STRING:
3711 if (*p == (char)0xFF) {
3715 slen = mono_metadata_decode_value (p, &p);
3717 return mono_string_new_len (mono_domain_get (), p, slen);
3718 case MONO_TYPE_CLASS: {
3722 slen = mono_metadata_decode_value (p, &p);
3723 n = g_memdup (p, slen + 1);
3725 t = mono_reflection_type_from_name (n, image);
3727 g_warning ("Cannot load type '%s'", n);
3730 return mono_type_get_object (mono_domain_get (), t);
3732 case MONO_TYPE_OBJECT: {
3740 } else if (subt == 0x55) {
3743 slen = mono_metadata_decode_value (p, &p);
3744 n = g_memdup (p, slen + 1);
3746 t = mono_reflection_type_from_name (n, image);
3748 g_warning ("Cannot load type '%s'", n);
3751 subc = mono_class_from_mono_type (t);
3752 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
3753 MonoType simple_type = {{0}};
3754 simple_type.type = subt;
3755 subc = mono_class_from_mono_type (&simple_type);
3757 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
3759 val = load_cattr_value (image, &subc->byval_arg, p, end);
3760 obj = mono_object_new (mono_domain_get (), subc);
3761 memcpy ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
3765 case MONO_TYPE_SZARRAY:
3771 arr=mono_array_new(mono_domain_get(),mono_class_from_mono_type(t->data.type),alen);
3772 switch (t->data.type->type)
3776 case MONO_TYPE_BOOLEAN:
3777 for (i=0;i<alen;i++)
3779 MonoBoolean val=*p++;
3780 mono_array_set(arr,MonoBoolean,i,val);
3783 case MONO_TYPE_CHAR:
3786 for (i=0;i<alen;i++)
3788 guint16 val=read16(p);
3789 mono_array_set(arr,guint16,i,val);
3796 for (i=0;i<alen;i++)
3798 guint32 val=read32(p);
3799 mono_array_set(arr,guint32,i,val);
3806 for (i=0;i<alen;i++)
3808 guint64 val=read64(p);
3809 mono_array_set(arr,guint64,i,val);
3813 case MONO_TYPE_STRING:
3814 for (i=0;i<alen;i++)
3818 mono_array_set(arr,gpointer,i,NULL);
3823 slen=mono_metadata_decode_value(p,&p);
3824 mono_array_set(arr,gpointer,i,mono_string_new_len(mono_domain_get(),p,slen));
3830 g_error("Type 0x%02x not handled in custom attr array decoding",t->data.type->type);
3836 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
3842 * Optimization we could avoid mallocing() an little-endian archs that
3843 * don't crash with unaligned accesses.
3846 fill_param_data (MonoImage *image, MonoMethodSignature *sig, guint32 blobidx, void **params) {
3848 const char *p = mono_metadata_blob_heap (image, blobidx);
3850 len = mono_metadata_decode_value (p, &p);
3851 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
3856 for (i = 0; i < sig->param_count; ++i) {
3857 params [i] = load_cattr_value (image, sig->params [i], p, &p);
3863 type_is_reference (MonoType *type)
3865 switch (type->type) {
3866 case MONO_TYPE_BOOLEAN:
3867 case MONO_TYPE_CHAR:
3880 case MONO_TYPE_VALUETYPE:
3888 free_param_data (MonoMethodSignature *sig, void **params) {
3890 for (i = 0; i < sig->param_count; ++i) {
3891 if (!type_is_reference (sig->params [i]))
3892 g_free (params [i]);
3897 * Find the method index in the metadata methodDef table.
3898 * Later put these three helper methods in metadata and export them.
3901 find_method_index (MonoMethod *method) {
3902 MonoClass *klass = method->klass;
3905 for (i = 0; i < klass->method.count; ++i) {
3906 if (method == klass->methods [i])
3907 return klass->method.first + 1 + i;
3913 * Find the field index in the metadata FieldDef table.
3916 find_field_index (MonoClass *klass, MonoClassField *field) {
3919 for (i = 0; i < klass->field.count; ++i) {
3920 if (field == &klass->fields [i])
3921 return klass->field.first + 1 + i;
3927 * Find the property index in the metadata Property table.
3930 find_property_index (MonoClass *klass, MonoProperty *property) {
3933 for (i = 0; i < klass->property.count; ++i) {
3934 if (property == &klass->properties [i])
3935 return klass->property.first + 1 + i;
3941 * Find the event index in the metadata Event table.
3944 find_event_index (MonoClass *klass, MonoEvent *event) {
3947 for (i = 0; i < klass->event.count; ++i) {
3948 if (event == &klass->events [i])
3949 return klass->event.first + 1 + i;
3955 * mono_reflection_get_custom_attrs:
3956 * @obj: a reflection object handle
3958 * Return an array with all the custom attributes defined of the
3959 * reflection handle @obj. The objects are fully build.
3962 mono_reflection_get_custom_attrs (MonoObject *obj)
3964 guint32 idx, mtoken, i, len;
3965 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
3975 MONO_ARCH_SAVE_REGS;
3977 klass = obj->vtable->klass;
3978 /* FIXME: need to handle: Module */
3979 if (klass == mono_defaults.monotype_class) {
3980 MonoReflectionType *rtype = (MonoReflectionType*)obj;
3981 klass = mono_class_from_mono_type (rtype->type);
3982 idx = mono_metadata_token_index (klass->type_token);
3983 idx <<= CUSTOM_ATTR_BITS;
3984 idx |= CUSTOM_ATTR_TYPEDEF;
3985 image = klass->image;
3986 } else if (strcmp ("Assembly", klass->name) == 0) {
3987 MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
3988 idx = 1; /* there is only one assembly */
3989 idx <<= CUSTOM_ATTR_BITS;
3990 idx |= CUSTOM_ATTR_ASSEMBLY;
3991 image = rassembly->assembly->image;
3992 } else if (strcmp ("MonoProperty", klass->name) == 0) {
3993 MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj;
3994 idx = find_property_index (rprop->klass, rprop->property);
3995 idx <<= CUSTOM_ATTR_BITS;
3996 idx |= CUSTOM_ATTR_PROPERTY;
3997 image = rprop->klass->image;
3998 } else if (strcmp ("MonoEvent", klass->name) == 0) {
3999 MonoReflectionEvent *revent = (MonoReflectionEvent*)obj;
4000 idx = find_event_index (revent->klass, revent->event);
4001 idx <<= CUSTOM_ATTR_BITS;
4002 idx |= CUSTOM_ATTR_EVENT;
4003 image = revent->klass->image;
4004 } else if (strcmp ("MonoField", klass->name) == 0) {
4005 MonoReflectionField *rfield = (MonoReflectionField*)obj;
4006 idx = find_field_index (rfield->klass, rfield->field);
4007 idx <<= CUSTOM_ATTR_BITS;
4008 idx |= CUSTOM_ATTR_FIELDDEF;
4009 image = rfield->klass->image;
4010 } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
4011 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
4012 idx = find_method_index (rmethod->method);
4013 idx <<= CUSTOM_ATTR_BITS;
4014 idx |= CUSTOM_ATTR_METHODDEF;
4015 image = rmethod->method->klass->image;
4016 } else if (strcmp ("ParameterInfo", klass->name) == 0) {
4017 MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
4018 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl;
4019 guint32 method_index = find_method_index (rmethod->method);
4020 guint32 param_list, param_last, param_pos, found;
4022 image = rmethod->method->klass->image;
4023 ca = &image->tables [MONO_TABLE_METHOD];
4025 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
4026 if (method_index == ca->rows) {
4027 ca = &image->tables [MONO_TABLE_PARAM];
4028 param_last = ca->rows + 1;
4030 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
4031 ca = &image->tables [MONO_TABLE_PARAM];
4034 for (i = param_list; i < param_last; ++i) {
4035 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
4036 if (param_pos == param->PositionImpl) {
4042 return mono_array_new (mono_domain_get (), mono_defaults.object_class, 0);
4044 idx <<= CUSTOM_ATTR_BITS;
4045 idx |= CUSTOM_ATTR_PARAMDEF;
4046 } else { /* handle other types here... */
4047 g_error ("get custom attrs not yet supported for %s", klass->name);
4050 /* at this point image and index are set correctly for searching the custom attr */
4051 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
4052 /* the table is not sorted */
4053 for (i = 0; i < ca->rows; ++i) {
4056 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
4057 if (cols [MONO_CUSTOM_ATTR_PARENT] != idx)
4059 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> CUSTOM_ATTR_TYPE_BITS;
4060 switch (cols [MONO_CUSTOM_ATTR_TYPE] & CUSTOM_ATTR_TYPE_MASK) {
4061 case CUSTOM_ATTR_TYPE_METHODDEF:
4062 mtoken |= MONO_TOKEN_METHOD_DEF;
4064 case CUSTOM_ATTR_TYPE_MEMBERREF:
4065 mtoken |= MONO_TOKEN_MEMBER_REF;
4068 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
4071 method = mono_get_method (image, mtoken, NULL);
4073 g_error ("Can't find custom attr constructor image: %s mtoken: 0x%08x", image->name, mtoken);
4074 mono_class_init (method->klass);
4075 /*g_print ("got attr %s\n", method->klass->name);*/
4076 params = g_new (void*, method->signature->param_count);
4077 named = fill_param_data (image, method->signature, cols [MONO_CUSTOM_ATTR_VALUE], params);
4078 attr = mono_object_new (mono_domain_get (), method->klass);
4079 mono_runtime_invoke (method, attr, params, NULL);
4080 free_param_data (method->signature, params);
4082 num_named = read16 (named);
4084 for (j = 0; j < num_named; j++) {
4086 char *name, named_type;
4087 named_type = *named++;
4088 named++; /* type of data */
4089 name_len = mono_metadata_decode_blob_size (named, &named);
4090 name = g_malloc (name_len + 1);
4091 memcpy (name, named, name_len);
4092 name [name_len] = 0;
4094 if (named_type == 0x53) {
4095 MonoClassField *field = mono_class_get_field_from_name (mono_object_class (attr), name);
4096 void *val = load_cattr_value (image, field->type, named, &named);
4097 mono_field_set_value (attr, field, val);
4098 if (!type_is_reference (field->type))
4100 } else if (named_type == 0x54) {
4101 MonoProperty *prop = mono_class_get_property_from_name (mono_object_class (attr), name);
4103 MonoType *prop_type;
4104 /* can we have more that 1 arg in a custom attr named property? */
4105 prop_type = prop->get? prop->get->signature->ret: prop->set->signature->params [prop->set->signature->param_count - 1];
4106 pparams [0] = load_cattr_value (image, prop_type, named, &named);
4107 mono_property_set_value (prop, attr, pparams, NULL);
4108 if (!type_is_reference (prop_type))
4109 g_free (pparams [0]);
4113 list = g_list_prepend (list, attr);
4116 len = g_list_length (list);
4118 * The return type is really object[], but System/Attribute.cs does a cast
4119 * to (Attribute []) and that is not allowed: I'm lazy for now, but we should
4120 * probably fix that.
4122 klass = mono_class_from_name (mono_defaults.corlib, "System", "Attribute");
4123 result = mono_array_new (mono_domain_get (), klass, len);
4124 for (i = 0; i < len; ++i) {
4125 mono_array_set (result, gpointer, i, list->data);
4128 g_list_free (g_list_first (list));
4133 static MonoMethodSignature*
4134 parameters_to_signature (MonoArray *parameters) {
4135 MonoMethodSignature *sig;
4138 count = parameters? mono_array_length (parameters): 0;
4140 sig = g_malloc0 (sizeof (MonoMethodSignature) + sizeof (MonoType*) * count);
4141 sig->param_count = count;
4142 sig->sentinelpos = -1; /* FIXME */
4143 for (i = 0; i < count; ++i) {
4144 MonoReflectionType *pt = mono_array_get (parameters, MonoReflectionType*, i);
4145 sig->params [i] = pt->type;
4150 static MonoMethodSignature*
4151 ctor_builder_to_signature (MonoReflectionCtorBuilder *ctor) {
4152 MonoMethodSignature *sig;
4154 sig = parameters_to_signature (ctor->parameters);
4155 sig->hasthis = ctor->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
4156 sig->ret = &mono_defaults.void_class->byval_arg;
4160 static MonoMethodSignature*
4161 method_builder_to_signature (MonoReflectionMethodBuilder *method) {
4162 MonoMethodSignature *sig;
4164 sig = parameters_to_signature (method->parameters);
4165 sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
4166 sig->ret = method->rtype? method->rtype->type: &mono_defaults.void_class->byval_arg;
4171 get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type)
4173 MonoClass *klass = mono_object_class (prop);
4174 if (strcmp (klass->name, "PropertyBuilder") == 0) {
4175 MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *)prop;
4176 *name = mono_string_to_utf8 (pb->name);
4177 *type = pb->type->type;
4179 MonoReflectionProperty *p = (MonoReflectionProperty *)prop;
4180 *name = g_strdup (p->property->name);
4181 if (p->property->get)
4182 *type = p->property->get->signature->ret;
4184 *type = p->property->set->signature->params [p->property->set->signature->param_count - 1];
4189 get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
4191 MonoClass *klass = mono_object_class (field);
4192 if (strcmp (klass->name, "FieldBuilder") == 0) {
4193 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)field;
4194 *name = mono_string_to_utf8 (fb->name);
4195 *type = fb->type->type;
4197 MonoReflectionField *f = (MonoReflectionField *)field;
4198 *name = g_strdup (f->field->name);
4199 *type = f->field->type;
4204 type_get_qualified_name (MonoType *type, MonoAssembly *ass) {
4205 char *name, *result;
4209 name = mono_type_get_name (type);
4210 klass = my_mono_class_from_mono_type (type);
4211 ta = klass->image->assembly;
4212 if (ta == ass || klass->image == mono_defaults.corlib)
4215 /* missing public key */
4216 result = g_strdup_printf ("%s, %s, Version=%d.%d.%d.%d, Culture=%s",
4217 name, ta->aname.name,
4218 ta->aname.major, ta->aname.minor, ta->aname.build, ta->aname.revision,
4219 ta->aname.culture && *ta->aname.culture? ta->aname.culture: "neutral");
4225 encode_cattr_value (char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg)
4228 MonoTypeEnum simple_type;
4230 if ((p-buffer) + 10 >= *buflen) {
4233 newbuf = g_realloc (buffer, *buflen);
4234 p = newbuf + (p-buffer);
4237 argval = ((char*)arg + sizeof (MonoObject));
4238 simple_type = type->type;
4240 switch (simple_type) {
4241 case MONO_TYPE_BOOLEAN:
4246 case MONO_TYPE_CHAR:
4249 swap_with_size (p, argval, 2, 1);
4255 swap_with_size (p, argval, 4, 1);
4261 swap_with_size (p, argval, 8, 1);
4264 case MONO_TYPE_VALUETYPE:
4265 if (type->data.klass->enumtype) {
4266 simple_type = type->data.klass->enum_basetype->type;
4269 g_warning ("generic valutype %s not handled in custom attr value decoding", type->data.klass->name);
4272 case MONO_TYPE_STRING: {
4279 str = mono_string_to_utf8 ((MonoString*)arg);
4280 slen = strlen (str);
4281 if ((p-buffer) + 10 + slen >= *buflen) {
4285 newbuf = g_realloc (buffer, *buflen);
4286 p = newbuf + (p-buffer);
4289 mono_metadata_encode_value (slen, p, &p);
4290 memcpy (p, str, slen);
4295 case MONO_TYPE_CLASS: {
4298 MonoClass *k = mono_object_class (arg);
4299 if (!mono_object_isinst (arg, mono_defaults.monotype_class) &&
4300 (strcmp (k->name, "TypeBuilder") || strcmp (k->name_space, "System.Reflection.Emit")))
4301 g_error ("only types allowed, not %s.%s", k->name_space, k->name);
4303 str = type_get_qualified_name (((MonoReflectionType*)arg)->type, NULL);
4304 slen = strlen (str);
4305 if ((p-buffer) + 10 + slen >= *buflen) {
4309 newbuf = g_realloc (buffer, *buflen);
4310 p = newbuf + (p-buffer);
4313 mono_metadata_encode_value (slen, p, &p);
4314 memcpy (p, str, slen);
4319 /* it may be a boxed value or a Type */
4320 case MONO_TYPE_OBJECT: {
4321 MonoClass *klass = mono_object_class (arg);
4325 if (mono_object_isinst (arg, mono_defaults.monotype_class)) {
4328 } else if (klass->enumtype) {
4330 } else if (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8) {
4331 *p++ = simple_type = klass->byval_arg.type;
4334 g_error ("unhandled type in custom attr");
4336 str = type_get_qualified_name (klass->enum_basetype, NULL);
4337 slen = strlen (str);
4338 if ((p-buffer) + 10 + slen >= *buflen) {
4342 newbuf = g_realloc (buffer, *buflen);
4343 p = newbuf + (p-buffer);
4346 mono_metadata_encode_value (slen, p, &p);
4347 memcpy (p, str, slen);
4350 simple_type = klass->enum_basetype->type;
4354 g_error ("type 0x%02x not yet supported in custom attr encoder", simple_type);
4357 *retbuffer = buffer;
4361 * mono_reflection_get_custom_attrs_blob:
4362 * @ctor: custom attribute constructor
4363 * @ctorArgs: arguments o the constructor
4369 * Creates the blob of data that needs to be saved in the metadata and that represents
4370 * the custom attributed described by @ctor, @ctorArgs etc.
4371 * Returns: a Byte array representing the blob of data.
4374 mono_reflection_get_custom_attrs_blob (MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
4377 MonoMethodSignature *sig;
4382 MONO_ARCH_SAVE_REGS;
4384 if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
4385 sig = ctor_builder_to_signature ((MonoReflectionCtorBuilder*)ctor);
4387 sig = ((MonoReflectionMethod*)ctor)->method->signature;
4390 p = buffer = g_malloc (buflen);
4391 /* write the prolog */
4394 for (i = 0; i < sig->param_count; ++i) {
4395 if (sig->params[i]->type==MONO_TYPE_SZARRAY)
4397 guint32 alen=mono_array_length(ctorArgs) - i;
4399 if ((p-buffer) + 10 >= buflen) {
4402 newbuf = g_realloc (buffer, buflen);
4403 p = newbuf + (p-buffer);
4407 *p++=(alen>>8)&0xff;
4408 *p++=(alen>>16)&0xff;
4409 *p++=(alen>>24)&0xff;
4410 for (j=0;j<alen;j++)
4412 arg=(MonoObject*)mono_array_get(ctorArgs,gpointer,i+j);
4413 encode_cattr_value(buffer,p,&buffer,&p,&buflen,sig->params[i]->data.type,arg);
4418 arg = (MonoObject*)mono_array_get (ctorArgs, gpointer, i);
4419 encode_cattr_value (buffer, p, &buffer, &p, &buflen, sig->params [i], arg);
4424 i += mono_array_length (properties);
4426 i += mono_array_length (fields);
4428 *p++ = (i >> 8) & 0xff;
4431 for (i = 0; i < mono_array_length (properties); ++i) {
4436 prop = mono_array_get (properties, gpointer, i);
4437 get_prop_name_and_type (prop, &pname, &ptype);
4438 *p++ = 0x54; /* PROPERTY signature */
4439 mono_metadata_encode_value (ptype->type, p, &p);
4440 len = strlen (pname);
4441 mono_metadata_encode_value (len, p, &p);
4442 memcpy (p, pname, len);
4444 encode_cattr_value (buffer, p, &buffer, &p, &buflen, ptype, (MonoObject*)mono_array_get (propValues, gpointer, i));
4451 for (i = 0; i < mono_array_length (fields); ++i) {
4456 field = mono_array_get (fields, gpointer, i);
4457 get_field_name_and_type (field, &fname, &ftype);
4458 *p++ = 0x53; /* FIELD signature */
4459 mono_metadata_encode_value (ftype->type, p, &p);
4460 len = strlen (fname);
4461 mono_metadata_encode_value (len, p, &p);
4462 memcpy (p, fname, len);
4464 encode_cattr_value (buffer, p, &buffer, &p, &buflen, ftype, (MonoObject*)mono_array_get (fieldValues, gpointer, i));
4469 g_assert (p - buffer <= buflen);
4470 buflen = p - buffer;
4471 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
4472 p = mono_array_addr (result, char, 0);
4473 memcpy (p, buffer, buflen);
4475 if (strcmp (ctor->vtable->klass->name, "MonoCMethod"))
4481 * mono_reflection_setup_internal_class:
4482 * @tb: a TypeBuilder object
4484 * Creates a MonoClass that represents the TypeBuilder.
4485 * This is a trick that lets us simplify a lot of reflection code
4486 * (and will allow us to support Build and Run assemblies easier).
4489 mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
4491 MonoClass *klass, *parent;
4493 MONO_ARCH_SAVE_REGS;
4495 klass = g_new0 (MonoClass, 1);
4497 klass->image = tb->module->assemblyb->dynamic_assembly->assembly.image;
4500 /* check so we can compile corlib correctly */
4501 if (strcmp (mono_object_class (tb->parent)->name, "TypeBuilder") == 0) {
4502 /* mono_class_setup_mono_type () guaranteess type->data.klass is valid */
4503 parent = tb->parent->type->data.klass;
4505 parent = my_mono_class_from_mono_type (tb->parent->type);
4509 klass->inited = 1; /* we lie to the runtime */
4510 klass->name = mono_string_to_utf8 (tb->name);
4511 klass->name_space = mono_string_to_utf8 (tb->nspace);
4512 klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx;
4513 klass->flags = tb->attrs;
4515 klass->element_class = klass;
4516 klass->reflection_info = tb; /* need to pin. */
4519 mono_class_setup_parent (klass, parent);
4520 else if (strcmp (klass->name, "Object") == 0 && strcmp (klass->name_space, "System") == 0) {
4521 const char *old_n = klass->name;
4522 /* trick to get relative numbering right when compiling corlib */
4523 klass->name = "BuildingObject";
4524 mono_class_setup_parent (klass, mono_defaults.object_class);
4525 klass->name = old_n;
4527 mono_class_setup_mono_type (klass);
4530 * FIXME: handle interfaces.
4533 tb->type.type = &klass->byval_arg;
4535 /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/
4539 * mono_reflection_create_internal_class:
4540 * @tb: a TypeBuilder object
4542 * Actually create the MonoClass that is associated with the TypeBuilder.
4545 mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
4549 MONO_ARCH_SAVE_REGS;
4551 klass = my_mono_class_from_mono_type (tb->type.type);
4553 if (klass->enumtype && klass->enum_basetype == NULL) {
4554 MonoReflectionFieldBuilder *fb;
4556 g_assert (tb->fields != NULL);
4557 g_assert (mono_array_length (tb->fields) >= 1);
4559 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, 0);
4561 klass->enum_basetype = fb->type->type;
4562 klass->element_class = my_mono_class_from_mono_type (klass->enum_basetype);
4563 if (!klass->element_class)
4564 klass->element_class = mono_class_from_mono_type (klass->enum_basetype);
4565 klass->instance_size = klass->element_class->instance_size;
4566 klass->size_inited = 1;
4568 * this is almost safe to do with enums and it's needed to be able
4569 * to create objects of the enum type (for use in SetConstant).
4571 mono_class_setup_vtable (klass);
4576 reflection_methodbuilder_to_mono_method (MonoClass *klass,
4577 ReflectionMethodBuilder *rmb,
4578 MonoMethodSignature *sig)
4581 MonoMethodNormal *pm;
4583 if ((rmb->attrs & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
4584 (rmb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
4585 m = (MonoMethod *)g_new0 (MonoMethodPInvoke, 1);
4587 m = (MonoMethod *)g_new0 (MonoMethodNormal, 1);
4589 pm = (MonoMethodNormal*)m;
4592 m->flags = rmb->attrs;
4593 m->iflags = rmb->iattrs;
4594 m->name = mono_string_to_utf8 (rmb->name);
4598 /* TODO: What about m->token ? */
4599 if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
4600 if (klass == mono_defaults.string_class && !strcmp (m->name, ".ctor"))
4603 m->addr = mono_lookup_internal_call (m);
4604 } else if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
4607 } else if (!m->klass->dummy &&
4608 !(m->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
4609 !(m->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
4610 MonoMethodHeader *header;
4612 gint32 max_stack, i;
4613 gint32 num_locals = 0;
4614 gint32 num_clauses = 0;
4618 code = mono_array_addr (rmb->ilgen->code, guint8, 0);
4619 code_size = rmb->ilgen->code_len;
4620 max_stack = rmb->ilgen->max_stack;
4621 num_locals = rmb->ilgen->locals ? mono_array_length (rmb->ilgen->locals) : 0;
4622 if (rmb->ilgen->ex_handlers)
4623 num_clauses = method_count_clauses (rmb->ilgen);
4626 code = mono_array_addr (rmb->code, guint8, 0);
4627 code_size = mono_array_length (rmb->code);
4628 /* we probably need to run a verifier on the code... */
4638 header = g_malloc0 (sizeof (MonoMethodHeader) +
4639 (num_locals - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
4640 header->code_size = code_size;
4641 header->code = g_malloc (code_size);
4642 memcpy ((char*)header->code, code, code_size);
4643 header->max_stack = max_stack;
4644 header->init_locals = rmb->init_locals;
4645 header->num_locals = num_locals;
4647 for (i = 0; i < num_locals; ++i) {
4648 MonoReflectionLocalBuilder *lb =
4649 mono_array_get (rmb->ilgen->locals,
4650 MonoReflectionLocalBuilder*, i);
4652 header->locals [i] = g_new0 (MonoType, 1);
4653 memcpy (header->locals [i], lb->type->type, sizeof (MonoType));
4656 header->num_clauses = num_clauses;
4658 header->clauses = method_encode_clauses (klass->image->assembly->dynamic,
4663 pm->header = header;
4670 ctorbuilder_to_mono_method (MonoClass *klass, MonoReflectionCtorBuilder* mb)
4672 ReflectionMethodBuilder rmb;
4674 MonoMethodSignature *sig;
4676 name = mb->attrs & METHOD_ATTRIBUTE_STATIC ? ".cctor": ".ctor";
4678 sig = ctor_builder_to_signature (mb);
4680 rmb.ilgen = mb->ilgen;
4681 rmb.parameters = mb->parameters;
4682 rmb.pinfo = mb->pinfo;
4683 rmb.attrs = mb->attrs;
4684 rmb.iattrs = mb->iattrs;
4685 rmb.call_conv = mb->call_conv;
4686 rmb.type = mb->type;
4687 rmb.name = mono_string_new (mono_domain_get (), name);
4688 rmb.table_idx = &mb->table_idx;
4689 rmb.init_locals = mb->init_locals;
4692 mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
4697 methodbuilder_to_mono_method (MonoClass *klass, MonoReflectionMethodBuilder* mb)
4699 ReflectionMethodBuilder rmb;
4700 MonoMethodSignature *sig;
4702 sig = method_builder_to_signature (mb);
4704 rmb.ilgen = mb->ilgen;
4705 rmb.parameters = mb->parameters;
4706 rmb.pinfo = mb->pinfo;
4707 rmb.attrs = mb->attrs;
4708 rmb.iattrs = mb->iattrs;
4709 rmb.call_conv = mb->call_conv;
4710 rmb.type = mb->type;
4711 rmb.name = mb->name;
4712 rmb.table_idx = &mb->table_idx;
4713 rmb.init_locals = mb->init_locals;
4714 rmb.code = mb->code;
4716 mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
4721 ensure_runtime_vtable (MonoClass *klass)
4723 MonoReflectionTypeBuilder *tb = klass->reflection_info;
4726 if (!tb || klass->wastypebuilder)
4729 ensure_runtime_vtable (klass->parent);
4731 num = tb->ctors? mono_array_length (tb->ctors): 0;
4732 num += tb->methods? mono_array_length (tb->methods): 0;
4733 klass->method.count = num;
4734 klass->methods = g_new (MonoMethod*, num);
4735 num = tb->ctors? mono_array_length (tb->ctors): 0;
4736 for (i = 0; i < num; ++i)
4737 klass->methods [i] = ctorbuilder_to_mono_method (klass, mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i));
4738 num = tb->methods? mono_array_length (tb->methods): 0;
4740 for (i = 0; i < num; ++i)
4741 klass->methods [j++] = methodbuilder_to_mono_method (klass, mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i));
4743 klass->wastypebuilder = TRUE;
4744 if (tb->interfaces) {
4745 klass->interface_count = mono_array_length (tb->interfaces);
4746 klass->interfaces = g_new (MonoClass*, klass->interface_count);
4747 for (i = 0; i < klass->interface_count; ++i) {
4748 MonoReflectionType *iface = mono_array_get (tb->interfaces, gpointer, i);
4749 klass->interfaces [i] = mono_class_from_mono_type (iface->type);
4752 mono_class_setup_vtable (klass);
4756 typebuilder_setup_fields (MonoClass *klass)
4758 MonoReflectionTypeBuilder *tb = klass->reflection_info;
4759 MonoReflectionFieldBuilder *fb;
4760 MonoClassField *field;
4763 klass->field.count = tb->fields? mono_array_length (tb->fields): 0;
4765 if (!klass->field.count)
4768 klass->fields = g_new0 (MonoClassField, klass->field.count);
4770 for (i = 0; i < klass->field.count; ++i) {
4771 fb = mono_array_get (tb->fields, gpointer, i);
4772 field = &klass->fields [i];
4773 field->name = mono_string_to_utf8 (fb->name);
4775 /* FIXME: handle type modifiers */
4776 field->type = g_memdup (fb->type->type, sizeof (MonoType));
4777 field->type->attrs = fb->attrs;
4779 field->type = fb->type->type;
4781 if ((fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) && fb->rva_data)
4782 field->data = mono_array_addr (fb->rva_data, char, 0);
4783 if (fb->offset != -1)
4784 field->offset = fb->offset;
4785 field->parent = klass;
4788 mono_class_layout_fields (klass);
4792 mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb)
4795 MonoReflectionType* res;
4797 MONO_ARCH_SAVE_REGS;
4799 klass = my_mono_class_from_mono_type (tb->type.type);
4802 * Fields to set in klass:
4803 * the various flags: delegate/unicode/contextbound etc.
4809 klass->flags = tb->attrs;
4810 klass->element_class = klass;
4812 /* enums are done right away */
4813 if (!klass->enumtype)
4814 ensure_runtime_vtable (klass);
4816 /* fields and object layout */
4817 if (klass->parent) {
4818 if (!klass->parent->size_inited)
4819 mono_class_init (klass->parent);
4820 klass->instance_size += klass->parent->instance_size;
4821 klass->class_size += klass->parent->class_size;
4822 klass->min_align = klass->parent->min_align;
4824 klass->instance_size = sizeof (MonoObject);
4825 klass->min_align = 1;
4827 /* FIXME: handle packing_size and instance_size */
4828 typebuilder_setup_fields (klass);
4830 /* FIXME: properties */
4832 res = mono_type_get_object (mono_object_domain (tb), &klass->byval_arg);
4833 /* with enums res == tb: need to fix that. */
4834 if (!klass->enumtype)
4835 g_assert (res != tb);
4840 mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
4842 MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly;
4843 guint32 na = mono_array_length (sig->arguments);
4848 MONO_ARCH_SAVE_REGS;
4850 p = buf = g_malloc (10 + na * 10);
4852 mono_metadata_encode_value (0x07, p, &p);
4853 mono_metadata_encode_value (na, p, &p);
4854 for (i = 0; i < na; ++i) {
4855 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i);
4856 encode_reflection_type (assembly, type, p, &p);
4860 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
4861 p = mono_array_addr (result, char, 0);
4862 memcpy (p, buf, buflen);
4869 mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig)
4871 MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly;
4872 guint32 na = mono_array_length (sig->arguments);
4877 MONO_ARCH_SAVE_REGS;
4879 p = buf = g_malloc (10 + na * 10);
4881 mono_metadata_encode_value (0x06, p, &p);
4882 for (i = 0; i < na; ++i) {
4883 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i);
4884 encode_reflection_type (assembly, type, p, &p);
4888 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
4889 p = mono_array_addr (result, char, 0);
4890 memcpy (p, buf, buflen);