2009-07-26 Miguel de Icaza <miguel@novell.com>
[mono-project.git] / mono / metadata / reflection.c
bloba6e4d1ef13cf54fd8106255a7c793d593dafc69a
1 /*
2 * reflection.c: Routines for creating an image at runtime.
3 *
4 * Author:
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 #include <config.h>
12 #include "mono/utils/mono-digest.h"
13 #include "mono/utils/mono-membar.h"
14 #include "mono/metadata/reflection.h"
15 #include "mono/metadata/tabledefs.h"
16 #include "mono/metadata/metadata-internals.h"
17 #include <mono/metadata/profiler-private.h>
18 #include "mono/metadata/class-internals.h"
19 #include "mono/metadata/gc-internal.h"
20 #include "mono/metadata/tokentype.h"
21 #include "mono/metadata/domain-internals.h"
22 #include "mono/metadata/opcodes.h"
23 #include "mono/metadata/assembly.h"
24 #include "mono/metadata/object-internals.h"
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/marshal.h>
27 #include <mono/metadata/security-manager.h>
28 #include <stdio.h>
29 #include <glib.h>
30 #include <errno.h>
31 #include <time.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include "image.h"
35 #include "cil-coff.h"
36 #include "mono-endian.h"
37 #include <mono/metadata/gc-internal.h>
38 #include <mono/metadata/mempool-internals.h>
39 #include <mono/metadata/security-core-clr.h>
40 #include <mono/metadata/debug-helpers.h>
42 #if HAVE_SGEN_GC
43 static void* reflection_info_desc = NULL;
44 #define MOVING_GC_REGISTER(addr) do { \
45 if (!reflection_info_desc) { \
46 gsize bmap = 1; \
47 reflection_info_desc = mono_gc_make_descr_from_bitmap (&bmap, 1); \
48 } \
49 mono_gc_register_root ((char*)(addr), sizeof (gpointer), reflection_info_desc); \
50 } while (0)
51 #else
52 #define MOVING_GC_REGISTER(addr)
53 #endif
55 typedef struct {
56 char *p;
57 char *buf;
58 char *end;
59 } SigBuffer;
61 #define TEXT_OFFSET 512
62 #define CLI_H_SIZE 136
63 #define FILE_ALIGN 512
64 #define VIRT_ALIGN 8192
65 #define START_TEXT_RVA 0x00002000
67 typedef struct {
68 MonoReflectionILGen *ilgen;
69 MonoReflectionType *rtype;
70 MonoArray *parameters;
71 MonoArray *generic_params;
72 MonoGenericContainer *generic_container;
73 MonoArray *pinfo;
74 MonoArray *opt_types;
75 guint32 attrs;
76 guint32 iattrs;
77 guint32 call_conv;
78 guint32 *table_idx; /* note: it's a pointer */
79 MonoArray *code;
80 MonoObject *type;
81 MonoString *name;
82 MonoBoolean init_locals;
83 MonoBoolean skip_visibility;
84 MonoArray *return_modreq;
85 MonoArray *return_modopt;
86 MonoArray *param_modreq;
87 MonoArray *param_modopt;
88 MonoArray *permissions;
89 MonoMethod *mhandle;
90 guint32 nrefs;
91 gpointer *refs;
92 /* for PInvoke */
93 int charset, extra_flags, native_cc;
94 MonoString *dll, *dllentry;
95 } ReflectionMethodBuilder;
97 typedef struct {
98 guint32 owner;
99 MonoReflectionGenericParam *gparam;
100 } GenericParamTableEntry;
102 const unsigned char table_sizes [MONO_TABLE_NUM] = {
103 MONO_MODULE_SIZE,
104 MONO_TYPEREF_SIZE,
105 MONO_TYPEDEF_SIZE,
107 MONO_FIELD_SIZE,
109 MONO_METHOD_SIZE,
111 MONO_PARAM_SIZE,
112 MONO_INTERFACEIMPL_SIZE,
113 MONO_MEMBERREF_SIZE, /* 0x0A */
114 MONO_CONSTANT_SIZE,
115 MONO_CUSTOM_ATTR_SIZE,
116 MONO_FIELD_MARSHAL_SIZE,
117 MONO_DECL_SECURITY_SIZE,
118 MONO_CLASS_LAYOUT_SIZE,
119 MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
120 MONO_STAND_ALONE_SIGNATURE_SIZE,
121 MONO_EVENT_MAP_SIZE,
123 MONO_EVENT_SIZE,
124 MONO_PROPERTY_MAP_SIZE,
126 MONO_PROPERTY_SIZE,
127 MONO_METHOD_SEMA_SIZE,
128 MONO_METHODIMPL_SIZE,
129 MONO_MODULEREF_SIZE, /* 0x1A */
130 MONO_TYPESPEC_SIZE,
131 MONO_IMPLMAP_SIZE,
132 MONO_FIELD_RVA_SIZE,
135 MONO_ASSEMBLY_SIZE, /* 0x20 */
136 MONO_ASSEMBLY_PROCESSOR_SIZE,
137 MONO_ASSEMBLYOS_SIZE,
138 MONO_ASSEMBLYREF_SIZE,
139 MONO_ASSEMBLYREFPROC_SIZE,
140 MONO_ASSEMBLYREFOS_SIZE,
141 MONO_FILE_SIZE,
142 MONO_EXP_TYPE_SIZE,
143 MONO_MANIFEST_SIZE,
144 MONO_NESTED_CLASS_SIZE,
146 MONO_GENERICPARAM_SIZE, /* 0x2A */
147 MONO_METHODSPEC_SIZE,
148 MONO_GENPARCONSTRAINT_SIZE
152 #ifndef DISABLE_REFLECTION_EMIT
153 static guint32 mono_image_get_methodref_token (MonoDynamicImage *assembly, MonoMethod *method, gboolean create_typespec);
154 static guint32 mono_image_get_methodbuilder_token (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, gboolean create_methodspec);
155 static guint32 mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *cb);
156 static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper);
157 static void ensure_runtime_vtable (MonoClass *klass);
158 static gpointer resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context);
159 static guint32 mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method);
160 static guint32 encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context);
161 static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
162 #endif
164 static void reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb, MonoReflectionMethodBuilder *mb);
165 static void reflection_methodbuilder_from_ctor_builder (ReflectionMethodBuilder *rmb, MonoReflectionCtorBuilder *mb);
166 static guint32 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type);
167 static guint32 mono_image_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboolean try_typespec);
168 static void mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly);
169 static guint32 encode_marshal_blob (MonoDynamicImage *assembly, MonoReflectionMarshal *minfo);
170 static guint32 encode_constant (MonoDynamicImage *assembly, MonoObject *val, guint32 *ret_type);
171 static char* type_get_qualified_name (MonoType *type, MonoAssembly *ass);
172 static void encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf);
173 static void get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types);
174 static MonoObject *mono_get_object_from_blob (MonoDomain *domain, MonoType *type, const char *blob);
175 static MonoReflectionType *mono_reflection_type_get_underlying_system_type (MonoReflectionType* t);
176 static MonoType* mono_reflection_get_type_with_rootimage (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve);
177 static MonoReflectionType* mono_reflection_type_resolve_user_types (MonoReflectionType *type);
178 static gboolean is_sre_array (MonoClass *class);
179 static gboolean is_sre_byref (MonoClass *class);
180 static gboolean is_sre_pointer (MonoClass *class);
182 #define RESOLVE_TYPE(type) do { type = (void*)mono_reflection_type_resolve_user_types ((MonoReflectionType*)type); } while (0)
183 #define RESOLVE_ARRAY_TYPE_ELEMENT(array, index) do { \
184 MonoReflectionType *__type = mono_array_get (array, MonoReflectionType*, index); \
185 __type = mono_reflection_type_resolve_user_types (__type); \
186 mono_array_set (arr, MonoReflectionType*, index, __type); \
187 } while (0)
189 #define mono_type_array_get_and_resolve(array, index) mono_reflection_type_get_handle ((MonoReflectionType*)mono_array_get (array, gpointer, index))
191 void
192 mono_reflection_init (void)
196 static void
197 sigbuffer_init (SigBuffer *buf, int size)
199 buf->buf = g_malloc (size);
200 buf->p = buf->buf;
201 buf->end = buf->buf + size;
204 static void
205 sigbuffer_make_room (SigBuffer *buf, int size)
207 if (buf->end - buf->p < size) {
208 int new_size = buf->end - buf->buf + size + 32;
209 char *p = g_realloc (buf->buf, new_size);
210 size = buf->p - buf->buf;
211 buf->buf = p;
212 buf->p = p + size;
213 buf->end = buf->buf + new_size;
217 static void
218 sigbuffer_add_value (SigBuffer *buf, guint32 val)
220 sigbuffer_make_room (buf, 6);
221 mono_metadata_encode_value (val, buf->p, &buf->p);
224 static void
225 sigbuffer_add_byte (SigBuffer *buf, guint8 val)
227 sigbuffer_make_room (buf, 1);
228 buf->p [0] = val;
229 buf->p++;
232 static void
233 sigbuffer_add_mem (SigBuffer *buf, char *p, guint32 size)
235 sigbuffer_make_room (buf, size);
236 memcpy (buf->p, p, size);
237 buf->p += size;
240 static void
241 sigbuffer_free (SigBuffer *buf)
243 g_free (buf->buf);
246 #ifndef DISABLE_REFLECTION_EMIT
248 * mp_g_alloc:
250 * Allocate memory from the @image mempool if it is non-NULL. Otherwise, allocate memory
251 * from the C heap.
253 static gpointer
254 image_g_malloc (MonoImage *image, guint size)
256 if (image)
257 return mono_image_alloc (image, size);
258 else
259 return g_malloc (size);
261 #endif /* !DISABLE_REFLECTION_EMIT */
264 * image_g_alloc0:
266 * Allocate memory from the @image mempool if it is non-NULL. Otherwise, allocate memory
267 * from the C heap.
269 static gpointer
270 image_g_malloc0 (MonoImage *image, guint size)
272 if (image)
273 return mono_image_alloc0 (image, size);
274 else
275 return g_malloc0 (size);
278 #ifndef DISABLE_REFLECTION_EMIT
279 static char*
280 image_strdup (MonoImage *image, const char *s)
282 if (image)
283 return mono_image_strdup (image, s);
284 else
285 return g_strdup (s);
287 #endif
289 #define image_g_new(image,struct_type, n_structs) \
290 ((struct_type *) image_g_malloc (image, ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
292 #define image_g_new0(image,struct_type, n_structs) \
293 ((struct_type *) image_g_malloc0 (image, ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
296 static void
297 alloc_table (MonoDynamicTable *table, guint nrows)
299 table->rows = nrows;
300 g_assert (table->columns);
301 if (nrows + 1 >= table->alloc_rows) {
302 while (nrows + 1 >= table->alloc_rows) {
303 if (table->alloc_rows == 0)
304 table->alloc_rows = 16;
305 else
306 table->alloc_rows *= 2;
309 table->values = g_renew (guint32, table->values, (table->alloc_rows) * table->columns);
313 static void
314 make_room_in_stream (MonoDynamicStream *stream, int size)
316 if (size <= stream->alloc_size)
317 return;
319 while (stream->alloc_size <= size) {
320 if (stream->alloc_size < 4096)
321 stream->alloc_size = 4096;
322 else
323 stream->alloc_size *= 2;
326 stream->data = g_realloc (stream->data, stream->alloc_size);
329 static guint32
330 string_heap_insert (MonoDynamicStream *sh, const char *str)
332 guint32 idx;
333 guint32 len;
334 gpointer oldkey, oldval;
336 if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
337 return GPOINTER_TO_UINT (oldval);
339 len = strlen (str) + 1;
340 idx = sh->index;
342 make_room_in_stream (sh, idx + len);
345 * We strdup the string even if we already copy them in sh->data
346 * so that the string pointers in the hash remain valid even if
347 * we need to realloc sh->data. We may want to avoid that later.
349 g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
350 memcpy (sh->data + idx, str, len);
351 sh->index += len;
352 return idx;
355 static guint32
356 string_heap_insert_mstring (MonoDynamicStream *sh, MonoString *str)
358 char *name = mono_string_to_utf8 (str);
359 guint32 idx;
360 idx = string_heap_insert (sh, name);
361 g_free (name);
362 return idx;
365 #ifndef DISABLE_REFLECTION_EMIT
366 static void
367 string_heap_init (MonoDynamicStream *sh)
369 sh->index = 0;
370 sh->alloc_size = 4096;
371 sh->data = g_malloc (4096);
372 sh->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
373 string_heap_insert (sh, "");
375 #endif
377 static guint32
378 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
380 guint32 idx;
382 make_room_in_stream (stream, stream->index + len);
383 memcpy (stream->data + stream->index, data, len);
384 idx = stream->index;
385 stream->index += len;
387 * align index? Not without adding an additional param that controls it since
388 * we may store a blob value in pieces.
390 return idx;
393 static guint32
394 mono_image_add_stream_zero (MonoDynamicStream *stream, guint32 len)
396 guint32 idx;
398 make_room_in_stream (stream, stream->index + len);
399 memset (stream->data + stream->index, 0, len);
400 idx = stream->index;
401 stream->index += len;
402 return idx;
405 static void
406 stream_data_align (MonoDynamicStream *stream)
408 char buf [4] = {0};
409 guint32 count = stream->index % 4;
411 /* we assume the stream data will be aligned */
412 if (count)
413 mono_image_add_stream_data (stream, buf, 4 - count);
416 #ifndef DISABLE_REFLECTION_EMIT
417 static int
418 mono_blob_entry_hash (const char* str)
420 guint len, h;
421 const char *end;
422 len = mono_metadata_decode_blob_size (str, &str);
423 if (len > 0) {
424 end = str + len;
425 h = *str;
426 for (str += 1; str < end; str++)
427 h = (h << 5) - h + *str;
428 return h;
429 } else {
430 return 0;
434 static gboolean
435 mono_blob_entry_equal (const char *str1, const char *str2) {
436 int len, len2;
437 const char *end1;
438 const char *end2;
439 len = mono_metadata_decode_blob_size (str1, &end1);
440 len2 = mono_metadata_decode_blob_size (str2, &end2);
441 if (len != len2)
442 return 0;
443 return memcmp (end1, end2, len) == 0;
445 #endif
446 static guint32
447 add_to_blob_cached (MonoDynamicImage *assembly, char *b1, int s1, char *b2, int s2)
449 guint32 idx;
450 char *copy;
451 gpointer oldkey, oldval;
453 copy = g_malloc (s1+s2);
454 memcpy (copy, b1, s1);
455 memcpy (copy + s1, b2, s2);
456 if (g_hash_table_lookup_extended (assembly->blob_cache, copy, &oldkey, &oldval)) {
457 g_free (copy);
458 idx = GPOINTER_TO_UINT (oldval);
459 } else {
460 idx = mono_image_add_stream_data (&assembly->blob, b1, s1);
461 mono_image_add_stream_data (&assembly->blob, b2, s2);
462 g_hash_table_insert (assembly->blob_cache, copy, GUINT_TO_POINTER (idx));
464 return idx;
467 static guint32
468 sigbuffer_add_to_blob_cached (MonoDynamicImage *assembly, SigBuffer *buf)
470 char blob_size [8];
471 char *b = blob_size;
472 guint32 size = buf->p - buf->buf;
473 /* store length */
474 g_assert (size <= (buf->end - buf->buf));
475 mono_metadata_encode_value (size, b, &b);
476 return add_to_blob_cached (assembly, blob_size, b-blob_size, buf->buf, size);
480 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
481 * dest may be misaligned.
483 static void
484 swap_with_size (char *dest, const char* val, int len, int nelem) {
485 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
486 int elem;
488 for (elem = 0; elem < nelem; ++elem) {
489 switch (len) {
490 case 1:
491 *dest = *val;
492 break;
493 case 2:
494 dest [0] = val [1];
495 dest [1] = val [0];
496 break;
497 case 4:
498 dest [0] = val [3];
499 dest [1] = val [2];
500 dest [2] = val [1];
501 dest [3] = val [0];
502 break;
503 case 8:
504 dest [0] = val [7];
505 dest [1] = val [6];
506 dest [2] = val [5];
507 dest [3] = val [4];
508 dest [4] = val [3];
509 dest [5] = val [2];
510 dest [6] = val [1];
511 dest [7] = val [0];
512 break;
513 default:
514 g_assert_not_reached ();
516 dest += len;
517 val += len;
519 #else
520 memcpy (dest, val, len * nelem);
521 #endif
524 static guint32
525 add_mono_string_to_blob_cached (MonoDynamicImage *assembly, MonoString *str)
527 char blob_size [64];
528 char *b = blob_size;
529 guint32 idx = 0, len;
531 len = str->length * 2;
532 mono_metadata_encode_value (len, b, &b);
533 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
535 char *swapped = g_malloc (2 * mono_string_length (str));
536 const char *p = (const char*)mono_string_chars (str);
538 swap_with_size (swapped, p, 2, mono_string_length (str));
539 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
540 g_free (swapped);
542 #else
543 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
544 #endif
545 return idx;
548 #ifndef DISABLE_REFLECTION_EMIT
549 static MonoClass *
550 default_class_from_mono_type (MonoType *type)
552 switch (type->type) {
553 case MONO_TYPE_OBJECT:
554 return mono_defaults.object_class;
555 case MONO_TYPE_VOID:
556 return mono_defaults.void_class;
557 case MONO_TYPE_BOOLEAN:
558 return mono_defaults.boolean_class;
559 case MONO_TYPE_CHAR:
560 return mono_defaults.char_class;
561 case MONO_TYPE_I1:
562 return mono_defaults.sbyte_class;
563 case MONO_TYPE_U1:
564 return mono_defaults.byte_class;
565 case MONO_TYPE_I2:
566 return mono_defaults.int16_class;
567 case MONO_TYPE_U2:
568 return mono_defaults.uint16_class;
569 case MONO_TYPE_I4:
570 return mono_defaults.int32_class;
571 case MONO_TYPE_U4:
572 return mono_defaults.uint32_class;
573 case MONO_TYPE_I:
574 return mono_defaults.int_class;
575 case MONO_TYPE_U:
576 return mono_defaults.uint_class;
577 case MONO_TYPE_I8:
578 return mono_defaults.int64_class;
579 case MONO_TYPE_U8:
580 return mono_defaults.uint64_class;
581 case MONO_TYPE_R4:
582 return mono_defaults.single_class;
583 case MONO_TYPE_R8:
584 return mono_defaults.double_class;
585 case MONO_TYPE_STRING:
586 return mono_defaults.string_class;
587 default:
588 g_warning ("default_class_from_mono_type: implement me 0x%02x\n", type->type);
589 g_assert_not_reached ();
592 return NULL;
594 #endif
596 static void
597 encode_generic_class (MonoDynamicImage *assembly, MonoGenericClass *gclass, SigBuffer *buf)
599 int i;
600 MonoGenericInst *class_inst;
601 MonoClass *klass;
603 g_assert (gclass);
605 class_inst = gclass->context.class_inst;
607 sigbuffer_add_value (buf, MONO_TYPE_GENERICINST);
608 klass = gclass->container_class;
609 sigbuffer_add_value (buf, klass->byval_arg.type);
610 sigbuffer_add_value (buf, mono_image_typedef_or_ref_full (assembly, &klass->byval_arg, FALSE));
612 sigbuffer_add_value (buf, class_inst->type_argc);
613 for (i = 0; i < class_inst->type_argc; ++i)
614 encode_type (assembly, class_inst->type_argv [i], buf);
618 static void
619 encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf)
621 if (!type) {
622 g_assert_not_reached ();
623 return;
626 if (type->byref)
627 sigbuffer_add_value (buf, MONO_TYPE_BYREF);
629 switch (type->type){
630 case MONO_TYPE_VOID:
631 case MONO_TYPE_BOOLEAN:
632 case MONO_TYPE_CHAR:
633 case MONO_TYPE_I1:
634 case MONO_TYPE_U1:
635 case MONO_TYPE_I2:
636 case MONO_TYPE_U2:
637 case MONO_TYPE_I4:
638 case MONO_TYPE_U4:
639 case MONO_TYPE_I8:
640 case MONO_TYPE_U8:
641 case MONO_TYPE_R4:
642 case MONO_TYPE_R8:
643 case MONO_TYPE_I:
644 case MONO_TYPE_U:
645 case MONO_TYPE_STRING:
646 case MONO_TYPE_OBJECT:
647 case MONO_TYPE_TYPEDBYREF:
648 sigbuffer_add_value (buf, type->type);
649 break;
650 case MONO_TYPE_PTR:
651 sigbuffer_add_value (buf, type->type);
652 encode_type (assembly, type->data.type, buf);
653 break;
654 case MONO_TYPE_SZARRAY:
655 sigbuffer_add_value (buf, type->type);
656 encode_type (assembly, &type->data.klass->byval_arg, buf);
657 break;
658 case MONO_TYPE_VALUETYPE:
659 case MONO_TYPE_CLASS: {
660 MonoClass *k = mono_class_from_mono_type (type);
662 if (k->generic_container) {
663 MonoGenericClass *gclass = mono_metadata_lookup_generic_class (k, k->generic_container->context.class_inst, TRUE);
664 encode_generic_class (assembly, gclass, buf);
665 } else {
667 * Make sure we use the correct type.
669 sigbuffer_add_value (buf, k->byval_arg.type);
671 * ensure only non-byref gets passed to mono_image_typedef_or_ref(),
672 * otherwise two typerefs could point to the same type, leading to
673 * verification errors.
675 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, &k->byval_arg));
677 break;
679 case MONO_TYPE_ARRAY:
680 sigbuffer_add_value (buf, type->type);
681 encode_type (assembly, &type->data.array->eklass->byval_arg, buf);
682 sigbuffer_add_value (buf, type->data.array->rank);
683 sigbuffer_add_value (buf, 0); /* FIXME: set to 0 for now */
684 sigbuffer_add_value (buf, 0);
685 break;
686 case MONO_TYPE_GENERICINST:
687 encode_generic_class (assembly, type->data.generic_class, buf);
688 break;
689 case MONO_TYPE_VAR:
690 case MONO_TYPE_MVAR:
691 sigbuffer_add_value (buf, type->type);
692 sigbuffer_add_value (buf, mono_type_get_generic_param_num (type));
693 break;
694 default:
695 g_error ("need to encode type %x", type->type);
699 static void
700 encode_reflection_type (MonoDynamicImage *assembly, MonoReflectionType *type, SigBuffer *buf)
702 if (!type) {
703 sigbuffer_add_value (buf, MONO_TYPE_VOID);
704 return;
707 encode_type (assembly, mono_reflection_type_get_handle (type), buf);
710 static void
711 encode_custom_modifiers (MonoDynamicImage *assembly, MonoArray *modreq, MonoArray *modopt, SigBuffer *buf)
713 int i;
715 if (modreq) {
716 for (i = 0; i < mono_array_length (modreq); ++i) {
717 MonoType *mod = mono_type_array_get_and_resolve (modreq, i);
718 sigbuffer_add_byte (buf, MONO_TYPE_CMOD_REQD);
719 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, mod));
722 if (modopt) {
723 for (i = 0; i < mono_array_length (modopt); ++i) {
724 MonoType *mod = mono_type_array_get_and_resolve (modopt, i);
725 sigbuffer_add_byte (buf, MONO_TYPE_CMOD_OPT);
726 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, mod));
731 #ifndef DISABLE_REFLECTION_EMIT
732 static guint32
733 method_encode_signature (MonoDynamicImage *assembly, MonoMethodSignature *sig)
735 SigBuffer buf;
736 int i;
737 guint32 nparams = sig->param_count;
738 guint32 idx;
740 if (!assembly->save)
741 return 0;
743 sigbuffer_init (&buf, 32);
745 * FIXME: vararg, explicit_this, differenc call_conv values...
747 idx = sig->call_convention;
748 if (sig->hasthis)
749 idx |= 0x20; /* hasthis */
750 if (sig->generic_param_count)
751 idx |= 0x10; /* generic */
752 sigbuffer_add_byte (&buf, idx);
753 if (sig->generic_param_count)
754 sigbuffer_add_value (&buf, sig->generic_param_count);
755 sigbuffer_add_value (&buf, nparams);
756 encode_type (assembly, sig->ret, &buf);
757 for (i = 0; i < nparams; ++i) {
758 if (i == sig->sentinelpos)
759 sigbuffer_add_byte (&buf, MONO_TYPE_SENTINEL);
760 encode_type (assembly, sig->params [i], &buf);
762 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
763 sigbuffer_free (&buf);
764 return idx;
766 #endif
768 static guint32
769 method_builder_encode_signature (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb)
772 * FIXME: reuse code from method_encode_signature().
774 SigBuffer buf;
775 int i;
776 guint32 nparams = mb->parameters ? mono_array_length (mb->parameters): 0;
777 guint32 ngparams = mb->generic_params ? mono_array_length (mb->generic_params): 0;
778 guint32 notypes = mb->opt_types ? mono_array_length (mb->opt_types): 0;
779 guint32 idx;
781 sigbuffer_init (&buf, 32);
782 /* LAMESPEC: all the call conv spec is foobared */
783 idx = mb->call_conv & 0x60; /* has-this, explicit-this */
784 if (mb->call_conv & 2)
785 idx |= 0x5; /* vararg */
786 if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
787 idx |= 0x20; /* hasthis */
788 if (ngparams)
789 idx |= 0x10; /* generic */
790 sigbuffer_add_byte (&buf, idx);
791 if (ngparams)
792 sigbuffer_add_value (&buf, ngparams);
793 sigbuffer_add_value (&buf, nparams + notypes);
794 encode_custom_modifiers (assembly, mb->return_modreq, mb->return_modopt, &buf);
795 encode_reflection_type (assembly, mb->rtype, &buf);
796 for (i = 0; i < nparams; ++i) {
797 MonoArray *modreq = NULL;
798 MonoArray *modopt = NULL;
799 MonoReflectionType *pt;
801 if (mb->param_modreq && (i < mono_array_length (mb->param_modreq)))
802 modreq = mono_array_get (mb->param_modreq, MonoArray*, i);
803 if (mb->param_modopt && (i < mono_array_length (mb->param_modopt)))
804 modopt = mono_array_get (mb->param_modopt, MonoArray*, i);
805 encode_custom_modifiers (assembly, modreq, modopt, &buf);
806 pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
807 encode_reflection_type (assembly, pt, &buf);
809 if (notypes)
810 sigbuffer_add_byte (&buf, MONO_TYPE_SENTINEL);
811 for (i = 0; i < notypes; ++i) {
812 MonoReflectionType *pt;
814 pt = mono_array_get (mb->opt_types, MonoReflectionType*, i);
815 encode_reflection_type (assembly, pt, &buf);
818 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
819 sigbuffer_free (&buf);
820 return idx;
823 static guint32
824 encode_locals (MonoDynamicImage *assembly, MonoReflectionILGen *ilgen)
826 MonoDynamicTable *table;
827 guint32 *values;
828 guint32 idx, sig_idx;
829 guint nl = mono_array_length (ilgen->locals);
830 SigBuffer buf;
831 int i;
833 sigbuffer_init (&buf, 32);
834 sigbuffer_add_value (&buf, 0x07);
835 sigbuffer_add_value (&buf, nl);
836 for (i = 0; i < nl; ++i) {
837 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
839 if (lb->is_pinned)
840 sigbuffer_add_value (&buf, MONO_TYPE_PINNED);
842 encode_reflection_type (assembly, (MonoReflectionType*)lb->type, &buf);
844 sig_idx = sigbuffer_add_to_blob_cached (assembly, &buf);
845 sigbuffer_free (&buf);
847 if (assembly->standalonesig_cache == NULL)
848 assembly->standalonesig_cache = g_hash_table_new (NULL, NULL);
849 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx)));
850 if (idx)
851 return idx;
853 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
854 idx = table->next_idx ++;
855 table->rows ++;
856 alloc_table (table, table->rows);
857 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
859 values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
861 g_hash_table_insert (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx), GUINT_TO_POINTER (idx));
863 return idx;
866 static guint32
867 method_count_clauses (MonoReflectionILGen *ilgen)
869 guint32 num_clauses = 0;
870 int i;
872 MonoILExceptionInfo *ex_info;
873 for (i = 0; i < mono_array_length (ilgen->ex_handlers); ++i) {
874 ex_info = (MonoILExceptionInfo*)mono_array_addr (ilgen->ex_handlers, MonoILExceptionInfo, i);
875 if (ex_info->handlers)
876 num_clauses += mono_array_length (ex_info->handlers);
877 else
878 num_clauses++;
881 return num_clauses;
884 #ifndef DISABLE_REFLECTION_EMIT
885 static MonoExceptionClause*
886 method_encode_clauses (MonoImage *image, MonoDynamicImage *assembly, MonoReflectionILGen *ilgen, guint32 num_clauses)
888 MonoExceptionClause *clauses;
889 MonoExceptionClause *clause;
890 MonoILExceptionInfo *ex_info;
891 MonoILExceptionBlock *ex_block;
892 guint32 finally_start;
893 int i, j, clause_index;;
895 clauses = image_g_new0 (image, MonoExceptionClause, num_clauses);
897 clause_index = 0;
898 for (i = mono_array_length (ilgen->ex_handlers) - 1; i >= 0; --i) {
899 ex_info = (MonoILExceptionInfo*)mono_array_addr (ilgen->ex_handlers, MonoILExceptionInfo, i);
900 finally_start = ex_info->start + ex_info->len;
901 if (!ex_info->handlers)
902 continue;
903 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
904 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
905 clause = &(clauses [clause_index]);
907 clause->flags = ex_block->type;
908 clause->try_offset = ex_info->start;
910 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
911 clause->try_len = finally_start - ex_info->start;
912 else
913 clause->try_len = ex_info->len;
914 clause->handler_offset = ex_block->start;
915 clause->handler_len = ex_block->len;
916 if (ex_block->extype) {
917 clause->data.catch_class = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype));
918 } else {
919 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
920 clause->data.filter_offset = ex_block->filter_offset;
921 else
922 clause->data.filter_offset = 0;
924 finally_start = ex_block->start + ex_block->len;
926 clause_index ++;
930 return clauses;
932 #endif /* !DISABLE_REFLECTION_EMIT */
934 static guint32
935 method_encode_code (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb)
937 char flags = 0;
938 guint32 idx;
939 guint32 code_size;
940 gint32 max_stack, i;
941 gint32 num_locals = 0;
942 gint32 num_exception = 0;
943 gint maybe_small;
944 guint32 fat_flags;
945 char fat_header [12];
946 guint32 int_value;
947 guint16 short_value;
948 guint32 local_sig = 0;
949 guint32 header_size = 12;
950 MonoArray *code;
952 if ((mb->attrs & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT)) ||
953 (mb->iattrs & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)))
954 return 0;
956 /*if (mb->name)
957 g_print ("Encode method %s\n", mono_string_to_utf8 (mb->name));*/
958 if (mb->ilgen) {
959 code = mb->ilgen->code;
960 code_size = mb->ilgen->code_len;
961 max_stack = mb->ilgen->max_stack;
962 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
963 if (mb->ilgen->ex_handlers)
964 num_exception = method_count_clauses (mb->ilgen);
965 } else {
966 code = mb->code;
967 if (code == NULL){
968 char *name = mono_string_to_utf8 (mb->name);
969 char *str = g_strdup_printf ("Method %s does not have any IL associated", name);
970 MonoException *exception = mono_get_exception_argument (NULL, "a method does not have any IL associated");
971 g_free (str);
972 g_free (name);
973 mono_raise_exception (exception);
976 code_size = mono_array_length (code);
977 max_stack = 8; /* we probably need to run a verifier on the code... */
980 stream_data_align (&assembly->code);
982 /* check for exceptions, maxstack, locals */
983 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
984 if (maybe_small) {
985 if (code_size < 64 && !(code_size & 1)) {
986 flags = (code_size << 2) | 0x2;
987 } else if (code_size < 32 && (code_size & 1)) {
988 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
989 } else {
990 goto fat_header;
992 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
993 /* add to the fixup todo list */
994 if (mb->ilgen && mb->ilgen->num_token_fixups)
995 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1));
996 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
997 return assembly->text_rva + idx;
999 fat_header:
1000 if (num_locals)
1001 local_sig = MONO_TOKEN_SIGNATURE | encode_locals (assembly, mb->ilgen);
1003 * FIXME: need to set also the header size in fat_flags.
1004 * (and more sects and init locals flags)
1006 fat_flags = 0x03;
1007 if (num_exception)
1008 fat_flags |= METHOD_HEADER_MORE_SECTS;
1009 if (mb->init_locals)
1010 fat_flags |= METHOD_HEADER_INIT_LOCALS;
1011 fat_header [0] = fat_flags;
1012 fat_header [1] = (header_size / 4 ) << 4;
1013 short_value = GUINT16_TO_LE (max_stack);
1014 memcpy (fat_header + 2, &short_value, 2);
1015 int_value = GUINT32_TO_LE (code_size);
1016 memcpy (fat_header + 4, &int_value, 4);
1017 int_value = GUINT32_TO_LE (local_sig);
1018 memcpy (fat_header + 8, &int_value, 4);
1019 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
1020 /* add to the fixup todo list */
1021 if (mb->ilgen && mb->ilgen->num_token_fixups)
1022 mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12));
1024 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
1025 if (num_exception) {
1026 unsigned char sheader [4];
1027 MonoILExceptionInfo * ex_info;
1028 MonoILExceptionBlock * ex_block;
1029 int j;
1031 stream_data_align (&assembly->code);
1032 /* always use fat format for now */
1033 sheader [0] = METHOD_HEADER_SECTION_FAT_FORMAT | METHOD_HEADER_SECTION_EHTABLE;
1034 num_exception *= 6 * sizeof (guint32);
1035 num_exception += 4; /* include the size of the header */
1036 sheader [1] = num_exception & 0xff;
1037 sheader [2] = (num_exception >> 8) & 0xff;
1038 sheader [3] = (num_exception >> 16) & 0xff;
1039 mono_image_add_stream_data (&assembly->code, (char*)sheader, 4);
1040 /* fat header, so we are already aligned */
1041 /* reverse order */
1042 for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) {
1043 ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i);
1044 if (ex_info->handlers) {
1045 int finally_start = ex_info->start + ex_info->len;
1046 for (j = 0; j < mono_array_length (ex_info->handlers); ++j) {
1047 guint32 val;
1048 ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j);
1049 /* the flags */
1050 val = GUINT32_TO_LE (ex_block->type);
1051 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1052 /* try offset */
1053 val = GUINT32_TO_LE (ex_info->start);
1054 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1055 /* need fault, too, probably */
1056 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FINALLY)
1057 val = GUINT32_TO_LE (finally_start - ex_info->start);
1058 else
1059 val = GUINT32_TO_LE (ex_info->len);
1060 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1061 /* handler offset */
1062 val = GUINT32_TO_LE (ex_block->start);
1063 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1064 /* handler len */
1065 val = GUINT32_TO_LE (ex_block->len);
1066 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1067 finally_start = ex_block->start + ex_block->len;
1068 if (ex_block->extype) {
1069 val = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)ex_block->extype)));
1070 } else {
1071 if (ex_block->type == MONO_EXCEPTION_CLAUSE_FILTER)
1072 val = ex_block->filter_offset;
1073 else
1074 val = 0;
1076 val = GUINT32_TO_LE (val);
1077 mono_image_add_stream_data (&assembly->code, (char*)&val, sizeof (guint32));
1078 /*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",
1079 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);*/
1081 } else {
1082 g_error ("No clauses for ex info block %d", i);
1086 return assembly->text_rva + idx;
1089 static guint32
1090 find_index_in_table (MonoDynamicImage *assembly, int table_idx, int col, guint32 token)
1092 int i;
1093 MonoDynamicTable *table;
1094 guint32 *values;
1096 table = &assembly->tables [table_idx];
1098 g_assert (col < table->columns);
1100 values = table->values + table->columns;
1101 for (i = 1; i <= table->rows; ++i) {
1102 if (values [col] == token)
1103 return i;
1104 values += table->columns;
1106 return 0;
1110 * LOCKING: Acquires the loader lock.
1112 static MonoCustomAttrInfo*
1113 lookup_custom_attr (MonoImage *image, gpointer member)
1115 MonoCustomAttrInfo* res;
1117 res = mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
1119 if (!res)
1120 return NULL;
1122 return g_memdup (res, sizeof (MonoCustomAttrInfo) + sizeof (MonoCustomAttrEntry) * (res->num_attrs - MONO_ZERO_LEN_ARRAY));
1125 static gboolean
1126 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
1128 /* FIXME: Need to do more checks */
1129 if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
1130 int visibility = cattr->ctor->method->klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
1132 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
1133 return FALSE;
1136 return TRUE;
1139 static MonoCustomAttrInfo*
1140 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
1142 int i, index, count, not_visible;
1143 MonoCustomAttrInfo *ainfo;
1144 MonoReflectionCustomAttr *cattr;
1146 if (!cattrs)
1147 return NULL;
1148 /* FIXME: check in assembly the Run flag is set */
1150 count = mono_array_length (cattrs);
1152 /* Skip nonpublic attributes since MS.NET seems to do the same */
1153 /* FIXME: This needs to be done more globally */
1154 not_visible = 0;
1155 for (i = 0; i < count; ++i) {
1156 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
1157 if (!custom_attr_visible (image, cattr))
1158 not_visible ++;
1160 count -= not_visible;
1162 ainfo = image_g_malloc0 (alloc_img, sizeof (MonoCustomAttrInfo) + sizeof (MonoCustomAttrEntry) * (count - MONO_ZERO_LEN_ARRAY));
1164 ainfo->image = image;
1165 ainfo->num_attrs = count;
1166 ainfo->cached = alloc_img != NULL;
1167 index = 0;
1168 for (i = 0; i < count; ++i) {
1169 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
1170 if (custom_attr_visible (image, cattr)) {
1171 unsigned char *saved = mono_image_alloc (image, mono_array_length (cattr->data));
1172 memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
1173 ainfo->attrs [index].ctor = cattr->ctor->method;
1174 ainfo->attrs [index].data = saved;
1175 ainfo->attrs [index].data_size = mono_array_length (cattr->data);
1176 index ++;
1180 return ainfo;
1183 #ifndef DISABLE_REFLECTION_EMIT
1185 * LOCKING: Acquires the loader lock.
1187 static void
1188 mono_save_custom_attrs (MonoImage *image, void *obj, MonoArray *cattrs)
1190 MonoCustomAttrInfo *ainfo, *tmp;
1192 if (!cattrs || !mono_array_length (cattrs))
1193 return;
1195 ainfo = mono_custom_attrs_from_builders (image, image, cattrs);
1197 mono_loader_lock ();
1198 tmp = mono_image_property_lookup (image, obj, MONO_PROP_DYNAMIC_CATTR);
1199 if (tmp)
1200 mono_custom_attrs_free (tmp);
1201 mono_image_property_insert (image, obj, MONO_PROP_DYNAMIC_CATTR, ainfo);
1202 mono_loader_unlock ();
1205 #endif
1207 void
1208 mono_custom_attrs_free (MonoCustomAttrInfo *ainfo)
1210 if (!ainfo->cached)
1211 g_free (ainfo);
1215 * idx is the table index of the object
1216 * type is one of MONO_CUSTOM_ATTR_*
1218 static void
1219 mono_image_add_cattrs (MonoDynamicImage *assembly, guint32 idx, guint32 type, MonoArray *cattrs)
1221 MonoDynamicTable *table;
1222 MonoReflectionCustomAttr *cattr;
1223 guint32 *values;
1224 guint32 count, i, token;
1225 char blob_size [6];
1226 char *p = blob_size;
1228 /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */
1229 if (!cattrs)
1230 return;
1231 count = mono_array_length (cattrs);
1232 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1233 table->rows += count;
1234 alloc_table (table, table->rows);
1235 values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE;
1236 idx <<= MONO_CUSTOM_ATTR_BITS;
1237 idx |= type;
1238 for (i = 0; i < count; ++i) {
1239 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
1240 values [MONO_CUSTOM_ATTR_PARENT] = idx;
1241 token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor, FALSE, FALSE);
1242 type = mono_metadata_token_index (token);
1243 type <<= MONO_CUSTOM_ATTR_TYPE_BITS;
1244 switch (mono_metadata_token_table (token)) {
1245 case MONO_TABLE_METHOD:
1246 type |= MONO_CUSTOM_ATTR_TYPE_METHODDEF;
1247 break;
1248 case MONO_TABLE_MEMBERREF:
1249 type |= MONO_CUSTOM_ATTR_TYPE_MEMBERREF;
1250 break;
1251 default:
1252 g_warning ("got wrong token in custom attr");
1253 continue;
1255 values [MONO_CUSTOM_ATTR_TYPE] = type;
1256 p = blob_size;
1257 mono_metadata_encode_value (mono_array_length (cattr->data), p, &p);
1258 values [MONO_CUSTOM_ATTR_VALUE] = add_to_blob_cached (assembly, blob_size, p - blob_size,
1259 mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
1260 values += MONO_CUSTOM_ATTR_SIZE;
1261 ++table->next_idx;
1265 static void
1266 mono_image_add_decl_security (MonoDynamicImage *assembly, guint32 parent_token, MonoArray *permissions)
1268 MonoDynamicTable *table;
1269 guint32 *values;
1270 guint32 count, i, idx;
1271 MonoReflectionPermissionSet *perm;
1273 if (!permissions)
1274 return;
1276 count = mono_array_length (permissions);
1277 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
1278 table->rows += count;
1279 alloc_table (table, table->rows);
1281 for (i = 0; i < mono_array_length (permissions); ++i) {
1282 perm = (MonoReflectionPermissionSet*)mono_array_addr (permissions, MonoReflectionPermissionSet, i);
1284 values = table->values + table->next_idx * MONO_DECL_SECURITY_SIZE;
1286 idx = mono_metadata_token_index (parent_token);
1287 idx <<= MONO_HAS_DECL_SECURITY_BITS;
1288 switch (mono_metadata_token_table (parent_token)) {
1289 case MONO_TABLE_TYPEDEF:
1290 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
1291 break;
1292 case MONO_TABLE_METHOD:
1293 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
1294 break;
1295 case MONO_TABLE_ASSEMBLY:
1296 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
1297 break;
1298 default:
1299 g_assert_not_reached ();
1302 values [MONO_DECL_SECURITY_ACTION] = perm->action;
1303 values [MONO_DECL_SECURITY_PARENT] = idx;
1304 values [MONO_DECL_SECURITY_PERMISSIONSET] = add_mono_string_to_blob_cached (assembly, perm->pset);
1306 ++table->next_idx;
1311 * Fill in the MethodDef and ParamDef tables for a method.
1312 * This is used for both normal methods and constructors.
1314 static void
1315 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicImage *assembly)
1317 MonoDynamicTable *table;
1318 guint32 *values;
1319 guint i, count;
1321 /* room in this table is already allocated */
1322 table = &assembly->tables [MONO_TABLE_METHOD];
1323 *mb->table_idx = table->next_idx ++;
1324 g_hash_table_insert (assembly->method_to_table_idx, mb->mhandle, GUINT_TO_POINTER ((*mb->table_idx)));
1325 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
1326 values [MONO_METHOD_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name);
1327 values [MONO_METHOD_FLAGS] = mb->attrs;
1328 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
1329 values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
1330 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
1332 table = &assembly->tables [MONO_TABLE_PARAM];
1333 values [MONO_METHOD_PARAMLIST] = table->next_idx;
1335 mono_image_add_decl_security (assembly,
1336 mono_metadata_make_token (MONO_TABLE_METHOD, *mb->table_idx), mb->permissions);
1338 if (mb->pinfo) {
1339 MonoDynamicTable *mtable;
1340 guint32 *mvalues;
1342 mtable = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1343 mvalues = mtable->values + mtable->next_idx * MONO_FIELD_MARSHAL_SIZE;
1345 count = 0;
1346 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
1347 if (mono_array_get (mb->pinfo, gpointer, i))
1348 count++;
1350 table->rows += count;
1351 alloc_table (table, table->rows);
1352 values = table->values + table->next_idx * MONO_PARAM_SIZE;
1353 for (i = 0; i < mono_array_length (mb->pinfo); ++i) {
1354 MonoReflectionParamBuilder *pb;
1355 if ((pb = mono_array_get (mb->pinfo, MonoReflectionParamBuilder*, i))) {
1356 values [MONO_PARAM_FLAGS] = pb->attrs;
1357 values [MONO_PARAM_SEQUENCE] = i;
1358 if (pb->name != NULL) {
1359 values [MONO_PARAM_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name);
1360 } else {
1361 values [MONO_PARAM_NAME] = 0;
1363 values += MONO_PARAM_SIZE;
1364 if (pb->marshal_info) {
1365 mtable->rows++;
1366 alloc_table (mtable, mtable->rows);
1367 mvalues = mtable->values + mtable->rows * MONO_FIELD_MARSHAL_SIZE;
1368 mvalues [MONO_FIELD_MARSHAL_PARENT] = (table->next_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_PARAMDEF;
1369 mvalues [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, pb->marshal_info);
1371 pb->table_idx = table->next_idx++;
1372 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
1373 guint32 field_type = 0;
1374 mtable = &assembly->tables [MONO_TABLE_CONSTANT];
1375 mtable->rows ++;
1376 alloc_table (mtable, mtable->rows);
1377 mvalues = mtable->values + mtable->rows * MONO_CONSTANT_SIZE;
1378 mvalues [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_PARAM | (pb->table_idx << MONO_HASCONSTANT_BITS);
1379 mvalues [MONO_CONSTANT_VALUE] = encode_constant (assembly, pb->def_value, &field_type);
1380 mvalues [MONO_CONSTANT_TYPE] = field_type;
1381 mvalues [MONO_CONSTANT_PADDING] = 0;
1388 static void
1389 reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb, MonoReflectionMethodBuilder *mb)
1391 memset (rmb, 0, sizeof (ReflectionMethodBuilder));
1393 rmb->ilgen = mb->ilgen;
1394 rmb->rtype = mono_reflection_type_resolve_user_types ((MonoReflectionType*)mb->rtype);
1395 rmb->parameters = mb->parameters;
1396 rmb->generic_params = mb->generic_params;
1397 rmb->generic_container = mb->generic_container;
1398 rmb->opt_types = NULL;
1399 rmb->pinfo = mb->pinfo;
1400 rmb->attrs = mb->attrs;
1401 rmb->iattrs = mb->iattrs;
1402 rmb->call_conv = mb->call_conv;
1403 rmb->code = mb->code;
1404 rmb->type = mb->type;
1405 rmb->name = mb->name;
1406 rmb->table_idx = &mb->table_idx;
1407 rmb->init_locals = mb->init_locals;
1408 rmb->skip_visibility = FALSE;
1409 rmb->return_modreq = mb->return_modreq;
1410 rmb->return_modopt = mb->return_modopt;
1411 rmb->param_modreq = mb->param_modreq;
1412 rmb->param_modopt = mb->param_modopt;
1413 rmb->permissions = mb->permissions;
1414 rmb->mhandle = mb->mhandle;
1415 rmb->nrefs = 0;
1416 rmb->refs = NULL;
1418 if (mb->dll) {
1419 rmb->charset = mb->charset;
1420 rmb->extra_flags = mb->extra_flags;
1421 rmb->native_cc = mb->native_cc;
1422 rmb->dllentry = mb->dllentry;
1423 rmb->dll = mb->dll;
1427 static void
1428 reflection_methodbuilder_from_ctor_builder (ReflectionMethodBuilder *rmb, MonoReflectionCtorBuilder *mb)
1430 const char *name = mb->attrs & METHOD_ATTRIBUTE_STATIC ? ".cctor": ".ctor";
1432 memset (rmb, 0, sizeof (ReflectionMethodBuilder));
1434 rmb->ilgen = mb->ilgen;
1435 rmb->rtype = mono_type_get_object (mono_domain_get (), &mono_defaults.void_class->byval_arg);
1436 rmb->parameters = mb->parameters;
1437 rmb->generic_params = NULL;
1438 rmb->generic_container = NULL;
1439 rmb->opt_types = NULL;
1440 rmb->pinfo = mb->pinfo;
1441 rmb->attrs = mb->attrs;
1442 rmb->iattrs = mb->iattrs;
1443 rmb->call_conv = mb->call_conv;
1444 rmb->code = NULL;
1445 rmb->type = mb->type;
1446 rmb->name = mono_string_new (mono_domain_get (), name);
1447 rmb->table_idx = &mb->table_idx;
1448 rmb->init_locals = mb->init_locals;
1449 rmb->skip_visibility = FALSE;
1450 rmb->return_modreq = NULL;
1451 rmb->return_modopt = NULL;
1452 rmb->param_modreq = mb->param_modreq;
1453 rmb->param_modopt = mb->param_modopt;
1454 rmb->permissions = mb->permissions;
1455 rmb->mhandle = mb->mhandle;
1456 rmb->nrefs = 0;
1457 rmb->refs = NULL;
1460 #ifndef DISABLE_REFLECTION_EMIT
1461 static void
1462 reflection_methodbuilder_from_dynamic_method (ReflectionMethodBuilder *rmb, MonoReflectionDynamicMethod *mb)
1464 memset (rmb, 0, sizeof (ReflectionMethodBuilder));
1466 rmb->ilgen = mb->ilgen;
1467 rmb->rtype = mb->rtype;
1468 rmb->parameters = mb->parameters;
1469 rmb->generic_params = NULL;
1470 rmb->generic_container = NULL;
1471 rmb->opt_types = NULL;
1472 rmb->pinfo = NULL;
1473 rmb->attrs = mb->attrs;
1474 rmb->iattrs = 0;
1475 rmb->call_conv = mb->call_conv;
1476 rmb->code = NULL;
1477 rmb->type = (MonoObject *) mb->owner;
1478 rmb->name = mb->name;
1479 rmb->table_idx = NULL;
1480 rmb->init_locals = mb->init_locals;
1481 rmb->skip_visibility = mb->skip_visibility;
1482 rmb->return_modreq = NULL;
1483 rmb->return_modopt = NULL;
1484 rmb->param_modreq = NULL;
1485 rmb->param_modopt = NULL;
1486 rmb->permissions = NULL;
1487 rmb->mhandle = mb->mhandle;
1488 rmb->nrefs = 0;
1489 rmb->refs = NULL;
1491 #endif
1493 static void
1494 mono_image_add_methodimpl (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb)
1496 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
1497 MonoDynamicTable *table;
1498 guint32 *values;
1499 guint32 tok;
1501 if (!mb->override_method)
1502 return;
1504 table = &assembly->tables [MONO_TABLE_METHODIMPL];
1505 table->rows ++;
1506 alloc_table (table, table->rows);
1507 values = table->values + table->rows * MONO_METHODIMPL_SIZE;
1508 values [MONO_METHODIMPL_CLASS] = tb->table_idx;
1509 values [MONO_METHODIMPL_BODY] = MONO_METHODDEFORREF_METHODDEF | (mb->table_idx << MONO_METHODDEFORREF_BITS);
1511 tok = mono_image_create_token (assembly, (MonoObject*)mb->override_method, FALSE, FALSE);
1512 switch (mono_metadata_token_table (tok)) {
1513 case MONO_TABLE_MEMBERREF:
1514 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODREF;
1515 break;
1516 case MONO_TABLE_METHOD:
1517 tok = (mono_metadata_token_index (tok) << MONO_METHODDEFORREF_BITS ) | MONO_METHODDEFORREF_METHODDEF;
1518 break;
1519 default:
1520 g_assert_not_reached ();
1522 values [MONO_METHODIMPL_DECLARATION] = tok;
1525 static void
1526 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicImage *assembly)
1528 MonoDynamicTable *table;
1529 guint32 *values;
1530 ReflectionMethodBuilder rmb;
1531 int i;
1533 reflection_methodbuilder_from_method_builder (&rmb, mb);
1535 mono_image_basic_method (&rmb, assembly);
1536 mb->table_idx = *rmb.table_idx;
1538 if (mb->dll) { /* It's a P/Invoke method */
1539 guint32 moduleref;
1540 /* map CharSet values to on-disk values */
1541 int ncharset = (mb->charset ? (mb->charset - 1) * 2 : 0);
1542 int extra_flags = mb->extra_flags;
1543 table = &assembly->tables [MONO_TABLE_IMPLMAP];
1544 table->rows ++;
1545 alloc_table (table, table->rows);
1546 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
1548 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | ncharset | extra_flags;
1549 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
1550 if (mb->dllentry)
1551 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->dllentry);
1552 else
1553 values [MONO_IMPLMAP_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->name);
1554 moduleref = string_heap_insert_mstring (&assembly->sheap, mb->dll);
1555 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
1556 table = &assembly->tables [MONO_TABLE_MODULEREF];
1557 table->rows ++;
1558 alloc_table (table, table->rows);
1559 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
1560 values [MONO_IMPLMAP_SCOPE] = table->rows;
1564 if (mb->generic_params) {
1565 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
1566 table->rows += mono_array_length (mb->generic_params);
1567 alloc_table (table, table->rows);
1568 for (i = 0; i < mono_array_length (mb->generic_params); ++i) {
1569 guint32 owner = MONO_TYPEORMETHOD_METHOD | (mb->table_idx << MONO_TYPEORMETHOD_BITS);
1571 mono_image_get_generic_param_info (
1572 mono_array_get (mb->generic_params, gpointer, i), owner, assembly);
1578 static void
1579 mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, MonoDynamicImage *assembly)
1581 ReflectionMethodBuilder rmb;
1583 reflection_methodbuilder_from_ctor_builder (&rmb, mb);
1585 mono_image_basic_method (&rmb, assembly);
1586 mb->table_idx = *rmb.table_idx;
1589 static char*
1590 type_get_fully_qualified_name (MonoType *type)
1592 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
1595 static char*
1596 type_get_qualified_name (MonoType *type, MonoAssembly *ass) {
1597 MonoClass *klass;
1598 MonoAssembly *ta;
1600 klass = mono_class_from_mono_type (type);
1601 if (!klass)
1602 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_REFLECTION);
1603 ta = klass->image->assembly;
1604 if (ta->dynamic || (ta == ass)) {
1605 if (klass->generic_class || klass->generic_container)
1606 /* For generic type definitions, we want T, while REFLECTION returns T<K> */
1607 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_FULL_NAME);
1608 else
1609 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_REFLECTION);
1612 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
1615 #ifndef DISABLE_REFLECTION_EMIT
1616 static guint32
1617 fieldref_encode_signature (MonoDynamicImage *assembly, MonoType *type)
1619 SigBuffer buf;
1620 guint32 idx, i;
1622 if (!assembly->save)
1623 return 0;
1625 sigbuffer_init (&buf, 32);
1627 sigbuffer_add_value (&buf, 0x06);
1628 /* encode custom attributes before the type */
1629 /* FIXME: This should probably go in encode_type () */
1630 if (type->num_mods) {
1631 for (i = 0; i < type->num_mods; ++i) {
1632 if (type->modifiers [i].required)
1633 sigbuffer_add_byte (&buf, MONO_TYPE_CMOD_REQD);
1634 else
1635 sigbuffer_add_byte (&buf, MONO_TYPE_CMOD_OPT);
1636 sigbuffer_add_value (&buf, type->modifiers [i].token);
1639 encode_type (assembly, type, &buf);
1640 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1641 sigbuffer_free (&buf);
1642 return idx;
1644 #endif
1646 static guint32
1647 field_encode_signature (MonoDynamicImage *assembly, MonoReflectionFieldBuilder *fb)
1649 SigBuffer buf;
1650 guint32 idx;
1652 sigbuffer_init (&buf, 32);
1654 sigbuffer_add_value (&buf, 0x06);
1655 encode_custom_modifiers (assembly, fb->modreq, fb->modopt, &buf);
1656 /* encode custom attributes before the type */
1657 encode_reflection_type (assembly, (MonoReflectionType*)fb->type, &buf);
1658 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1659 sigbuffer_free (&buf);
1660 return idx;
1663 static guint32
1664 encode_constant (MonoDynamicImage *assembly, MonoObject *val, guint32 *ret_type) {
1665 char blob_size [64];
1666 char *b = blob_size;
1667 char *p, *box_val;
1668 char* buf;
1669 guint32 idx = 0, len = 0, dummy = 0;
1670 #ifdef ARM_FPU_FPA
1671 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1672 guint32 fpa_double [2];
1673 guint32 *fpa_p;
1674 #endif
1675 #endif
1677 p = buf = g_malloc (64);
1678 if (!val) {
1679 *ret_type = MONO_TYPE_CLASS;
1680 len = 4;
1681 box_val = (char*)&dummy;
1682 } else {
1683 box_val = ((char*)val) + sizeof (MonoObject);
1684 *ret_type = val->vtable->klass->byval_arg.type;
1686 handle_enum:
1687 switch (*ret_type) {
1688 case MONO_TYPE_BOOLEAN:
1689 case MONO_TYPE_U1:
1690 case MONO_TYPE_I1:
1691 len = 1;
1692 break;
1693 case MONO_TYPE_CHAR:
1694 case MONO_TYPE_U2:
1695 case MONO_TYPE_I2:
1696 len = 2;
1697 break;
1698 case MONO_TYPE_U4:
1699 case MONO_TYPE_I4:
1700 case MONO_TYPE_R4:
1701 len = 4;
1702 break;
1703 case MONO_TYPE_U8:
1704 case MONO_TYPE_I8:
1705 len = 8;
1706 break;
1707 case MONO_TYPE_R8:
1708 len = 8;
1709 #ifdef ARM_FPU_FPA
1710 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1711 fpa_p = (guint32*)box_val;
1712 fpa_double [0] = fpa_p [1];
1713 fpa_double [1] = fpa_p [0];
1714 box_val = (char*)fpa_double;
1715 #endif
1716 #endif
1717 break;
1718 case MONO_TYPE_VALUETYPE:
1719 if (val->vtable->klass->enumtype) {
1720 *ret_type = mono_class_enum_basetype (val->vtable->klass)->type;
1721 goto handle_enum;
1722 } else
1723 g_error ("we can't encode valuetypes");
1724 case MONO_TYPE_CLASS:
1725 break;
1726 case MONO_TYPE_STRING: {
1727 MonoString *str = (MonoString*)val;
1728 /* there is no signature */
1729 len = str->length * 2;
1730 mono_metadata_encode_value (len, b, &b);
1731 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1733 char *swapped = g_malloc (2 * mono_string_length (str));
1734 const char *p = (const char*)mono_string_chars (str);
1736 swap_with_size (swapped, p, 2, mono_string_length (str));
1737 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
1738 g_free (swapped);
1740 #else
1741 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, (char*)mono_string_chars (str), len);
1742 #endif
1744 g_free (buf);
1745 return idx;
1747 case MONO_TYPE_GENERICINST:
1748 *ret_type = val->vtable->klass->generic_class->container_class->byval_arg.type;
1749 goto handle_enum;
1750 default:
1751 g_error ("we don't encode constant type 0x%02x yet", *ret_type);
1754 /* there is no signature */
1755 mono_metadata_encode_value (len, b, &b);
1756 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1757 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
1758 swap_with_size (blob_size, box_val, len, 1);
1759 mono_image_add_stream_data (&assembly->blob, blob_size, len);
1760 #else
1761 idx = add_to_blob_cached (assembly, blob_size, b-blob_size, box_val, len);
1762 #endif
1764 g_free (buf);
1765 return idx;
1768 static guint32
1769 encode_marshal_blob (MonoDynamicImage *assembly, MonoReflectionMarshal *minfo) {
1770 char *str;
1771 SigBuffer buf;
1772 guint32 idx, len;
1774 sigbuffer_init (&buf, 32);
1776 sigbuffer_add_value (&buf, minfo->type);
1778 switch (minfo->type) {
1779 case MONO_NATIVE_BYVALTSTR:
1780 case MONO_NATIVE_BYVALARRAY:
1781 sigbuffer_add_value (&buf, minfo->count);
1782 break;
1783 case MONO_NATIVE_LPARRAY:
1784 if (minfo->eltype || minfo->has_size) {
1785 sigbuffer_add_value (&buf, minfo->eltype);
1786 if (minfo->has_size) {
1787 sigbuffer_add_value (&buf, minfo->param_num != -1? minfo->param_num: 0);
1788 sigbuffer_add_value (&buf, minfo->count != -1? minfo->count: 0);
1790 /* LAMESPEC: ElemMult is undocumented */
1791 sigbuffer_add_value (&buf, minfo->param_num != -1? 1: 0);
1794 break;
1795 case MONO_NATIVE_SAFEARRAY:
1796 if (minfo->eltype)
1797 sigbuffer_add_value (&buf, minfo->eltype);
1798 break;
1799 case MONO_NATIVE_CUSTOM:
1800 if (minfo->guid) {
1801 str = mono_string_to_utf8 (minfo->guid);
1802 len = strlen (str);
1803 sigbuffer_add_value (&buf, len);
1804 sigbuffer_add_mem (&buf, str, len);
1805 g_free (str);
1806 } else {
1807 sigbuffer_add_value (&buf, 0);
1809 /* native type name */
1810 sigbuffer_add_value (&buf, 0);
1811 /* custom marshaler type name */
1812 if (minfo->marshaltype || minfo->marshaltyperef) {
1813 if (minfo->marshaltyperef)
1814 str = type_get_fully_qualified_name (mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef));
1815 else
1816 str = mono_string_to_utf8 (minfo->marshaltype);
1817 len = strlen (str);
1818 sigbuffer_add_value (&buf, len);
1819 sigbuffer_add_mem (&buf, str, len);
1820 g_free (str);
1821 } else {
1822 /* FIXME: Actually a bug, since this field is required. Punting for now ... */
1823 sigbuffer_add_value (&buf, 0);
1825 if (minfo->mcookie) {
1826 str = mono_string_to_utf8 (minfo->mcookie);
1827 len = strlen (str);
1828 sigbuffer_add_value (&buf, len);
1829 sigbuffer_add_mem (&buf, str, len);
1830 g_free (str);
1831 } else {
1832 sigbuffer_add_value (&buf, 0);
1834 break;
1835 default:
1836 break;
1838 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1839 sigbuffer_free (&buf);
1840 return idx;
1843 static void
1844 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *assembly)
1846 MonoDynamicTable *table;
1847 guint32 *values;
1849 /* maybe this fixup should be done in the C# code */
1850 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL)
1851 fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
1852 table = &assembly->tables [MONO_TABLE_FIELD];
1853 fb->table_idx = table->next_idx ++;
1854 g_hash_table_insert (assembly->field_to_table_idx, fb->handle, GUINT_TO_POINTER (fb->table_idx));
1855 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
1856 values [MONO_FIELD_NAME] = string_heap_insert_mstring (&assembly->sheap, fb->name);
1857 values [MONO_FIELD_FLAGS] = fb->attrs;
1858 values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
1860 if (fb->offset != -1) {
1861 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
1862 table->rows ++;
1863 alloc_table (table, table->rows);
1864 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
1865 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
1866 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
1868 if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) {
1869 guint32 field_type = 0;
1870 table = &assembly->tables [MONO_TABLE_CONSTANT];
1871 table->rows ++;
1872 alloc_table (table, table->rows);
1873 values = table->values + table->rows * MONO_CONSTANT_SIZE;
1874 values [MONO_CONSTANT_PARENT] = MONO_HASCONSTANT_FIEDDEF | (fb->table_idx << MONO_HASCONSTANT_BITS);
1875 values [MONO_CONSTANT_VALUE] = encode_constant (assembly, fb->def_value, &field_type);
1876 values [MONO_CONSTANT_TYPE] = field_type;
1877 values [MONO_CONSTANT_PADDING] = 0;
1879 if (fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
1880 guint32 rva_idx;
1881 table = &assembly->tables [MONO_TABLE_FIELDRVA];
1882 table->rows ++;
1883 alloc_table (table, table->rows);
1884 values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
1885 values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
1887 * We store it in the code section because it's simpler for now.
1889 if (fb->rva_data) {
1890 if (mono_array_length (fb->rva_data) >= 10)
1891 stream_data_align (&assembly->code);
1892 rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data));
1893 } else
1894 rva_idx = mono_image_add_stream_zero (&assembly->code, mono_class_value_size (fb->handle->parent, NULL));
1895 values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva;
1897 if (fb->marshal_info) {
1898 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
1899 table->rows ++;
1900 alloc_table (table, table->rows);
1901 values = table->values + table->rows * MONO_FIELD_MARSHAL_SIZE;
1902 values [MONO_FIELD_MARSHAL_PARENT] = (fb->table_idx << MONO_HAS_FIELD_MARSHAL_BITS) | MONO_HAS_FIELD_MARSHAL_FIELDSREF;
1903 values [MONO_FIELD_MARSHAL_NATIVE_TYPE] = encode_marshal_blob (assembly, fb->marshal_info);
1907 static guint32
1908 property_encode_signature (MonoDynamicImage *assembly, MonoReflectionPropertyBuilder *fb)
1910 SigBuffer buf;
1911 guint32 nparams = 0;
1912 MonoReflectionMethodBuilder *mb = fb->get_method;
1913 MonoReflectionMethodBuilder *smb = fb->set_method;
1914 guint32 idx, i;
1916 if (mb && mb->parameters)
1917 nparams = mono_array_length (mb->parameters);
1918 if (!mb && smb && smb->parameters)
1919 nparams = mono_array_length (smb->parameters) - 1;
1920 sigbuffer_init (&buf, 32);
1921 sigbuffer_add_byte (&buf, 0x08);
1922 sigbuffer_add_value (&buf, nparams);
1923 if (mb) {
1924 encode_reflection_type (assembly, (MonoReflectionType*)mb->rtype, &buf);
1925 for (i = 0; i < nparams; ++i) {
1926 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
1927 encode_reflection_type (assembly, pt, &buf);
1929 } else if (smb && smb->parameters) {
1930 /* the property type is the last param */
1931 encode_reflection_type (assembly, mono_array_get (smb->parameters, MonoReflectionType*, nparams), &buf);
1932 for (i = 0; i < nparams; ++i) {
1933 MonoReflectionType *pt = mono_array_get (smb->parameters, MonoReflectionType*, i);
1934 encode_reflection_type (assembly, pt, &buf);
1936 } else {
1937 encode_reflection_type (assembly, (MonoReflectionType*)fb->type, &buf);
1940 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1941 sigbuffer_free (&buf);
1942 return idx;
1945 static void
1946 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicImage *assembly)
1948 MonoDynamicTable *table;
1949 guint32 *values;
1950 guint num_methods = 0;
1951 guint32 semaidx;
1954 * we need to set things in the following tables:
1955 * PROPERTYMAP (info already filled in _get_type_info ())
1956 * PROPERTY (rows already preallocated in _get_type_info ())
1957 * METHOD (method info already done with the generic method code)
1958 * METHODSEMANTICS
1960 table = &assembly->tables [MONO_TABLE_PROPERTY];
1961 pb->table_idx = table->next_idx ++;
1962 values = table->values + pb->table_idx * MONO_PROPERTY_SIZE;
1963 values [MONO_PROPERTY_NAME] = string_heap_insert_mstring (&assembly->sheap, pb->name);
1964 values [MONO_PROPERTY_FLAGS] = pb->attrs;
1965 values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
1967 /* FIXME: we still don't handle 'other' methods */
1968 if (pb->get_method) num_methods ++;
1969 if (pb->set_method) num_methods ++;
1971 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
1972 table->rows += num_methods;
1973 alloc_table (table, table->rows);
1975 if (pb->get_method) {
1976 semaidx = table->next_idx ++;
1977 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1978 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
1979 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
1980 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
1982 if (pb->set_method) {
1983 semaidx = table->next_idx ++;
1984 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
1985 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
1986 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
1987 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_PROPERTY;
1991 static void
1992 mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicImage *assembly)
1994 MonoDynamicTable *table;
1995 guint32 *values;
1996 guint num_methods = 0;
1997 guint32 semaidx;
2000 * we need to set things in the following tables:
2001 * EVENTMAP (info already filled in _get_type_info ())
2002 * EVENT (rows already preallocated in _get_type_info ())
2003 * METHOD (method info already done with the generic method code)
2004 * METHODSEMANTICS
2006 table = &assembly->tables [MONO_TABLE_EVENT];
2007 eb->table_idx = table->next_idx ++;
2008 values = table->values + eb->table_idx * MONO_EVENT_SIZE;
2009 values [MONO_EVENT_NAME] = string_heap_insert_mstring (&assembly->sheap, eb->name);
2010 values [MONO_EVENT_FLAGS] = eb->attrs;
2011 values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, mono_reflection_type_get_handle (eb->type));
2014 * FIXME: we still don't handle 'other' methods
2016 if (eb->add_method) num_methods ++;
2017 if (eb->remove_method) num_methods ++;
2018 if (eb->raise_method) num_methods ++;
2020 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
2021 table->rows += num_methods;
2022 alloc_table (table, table->rows);
2024 if (eb->add_method) {
2025 semaidx = table->next_idx ++;
2026 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
2027 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON;
2028 values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx;
2029 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
2031 if (eb->remove_method) {
2032 semaidx = table->next_idx ++;
2033 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
2034 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON;
2035 values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx;
2036 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
2038 if (eb->raise_method) {
2039 semaidx = table->next_idx ++;
2040 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
2041 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE;
2042 values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx;
2043 values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << MONO_HAS_SEMANTICS_BITS) | MONO_HAS_SEMANTICS_EVENT;
2047 static void
2048 encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
2050 MonoDynamicTable *table;
2051 guint32 num_constraints, i;
2052 guint32 *values;
2053 guint32 table_idx;
2055 table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2056 num_constraints = gparam->iface_constraints ?
2057 mono_array_length (gparam->iface_constraints) : 0;
2058 table->rows += num_constraints;
2059 if (gparam->base_type)
2060 table->rows++;
2061 alloc_table (table, table->rows);
2063 if (gparam->base_type) {
2064 table_idx = table->next_idx ++;
2065 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
2067 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
2068 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (
2069 assembly, mono_reflection_type_get_handle (gparam->base_type));
2072 for (i = 0; i < num_constraints; i++) {
2073 MonoReflectionType *constraint = mono_array_get (
2074 gparam->iface_constraints, gpointer, i);
2076 table_idx = table->next_idx ++;
2077 values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;
2079 values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
2080 values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (
2081 assembly, mono_reflection_type_get_handle (constraint));
2085 static void
2086 mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
2088 GenericParamTableEntry *entry;
2091 * The GenericParam table must be sorted according to the `owner' field.
2092 * We need to do this sorting prior to writing the GenericParamConstraint
2093 * table, since we have to use the final GenericParam table indices there
2094 * and they must also be sorted.
2097 entry = g_new0 (GenericParamTableEntry, 1);
2098 entry->owner = owner;
2099 /* FIXME: track where gen_params should be freed and remove the GC root as well */
2100 MOVING_GC_REGISTER (&entry->gparam);
2101 entry->gparam = gparam;
2103 g_ptr_array_add (assembly->gen_params, entry);
2106 static void
2107 write_generic_param_entry (MonoDynamicImage *assembly, GenericParamTableEntry *entry)
2109 MonoDynamicTable *table;
2110 MonoGenericParam *param;
2111 guint32 *values;
2112 guint32 table_idx;
2114 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
2115 table_idx = table->next_idx ++;
2116 values = table->values + table_idx * MONO_GENERICPARAM_SIZE;
2118 param = mono_reflection_type_get_handle ((MonoReflectionType*)entry->gparam)->data.generic_param;
2120 values [MONO_GENERICPARAM_OWNER] = entry->owner;
2121 values [MONO_GENERICPARAM_FLAGS] = entry->gparam->attrs;
2122 values [MONO_GENERICPARAM_NUMBER] = mono_generic_param_num (param);
2123 values [MONO_GENERICPARAM_NAME] = string_heap_insert (&assembly->sheap, mono_generic_param_info (param)->name);
2125 mono_image_add_cattrs (assembly, table_idx, MONO_CUSTOM_ATTR_GENERICPAR, entry->gparam->cattrs);
2127 encode_constraints (entry->gparam, table_idx, assembly);
2130 static guint32
2131 resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image)
2133 MonoDynamicTable *table;
2134 guint32 token;
2135 guint32 *values;
2136 guint32 cols [MONO_ASSEMBLY_SIZE];
2137 const char *pubkey;
2138 guint32 publen;
2140 if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, image))))
2141 return token;
2143 if (image->assembly->dynamic && (image->assembly == assembly->image.assembly)) {
2144 table = &assembly->tables [MONO_TABLE_MODULEREF];
2145 token = table->next_idx ++;
2146 table->rows ++;
2147 alloc_table (table, table->rows);
2148 values = table->values + token * MONO_MODULEREF_SIZE;
2149 values [MONO_MODULEREF_NAME] = string_heap_insert (&assembly->sheap, image->module_name);
2151 token <<= MONO_RESOLTION_SCOPE_BITS;
2152 token |= MONO_RESOLTION_SCOPE_MODULEREF;
2153 g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
2155 return token;
2158 if (image->assembly->dynamic)
2159 /* FIXME: */
2160 memset (cols, 0, sizeof (cols));
2161 else {
2162 /* image->assembly->image is the manifest module */
2163 image = image->assembly->image;
2164 mono_metadata_decode_row (&image->tables [MONO_TABLE_ASSEMBLY], 0, cols, MONO_ASSEMBLY_SIZE);
2167 table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
2168 token = table->next_idx ++;
2169 table->rows ++;
2170 alloc_table (table, table->rows);
2171 values = table->values + token * MONO_ASSEMBLYREF_SIZE;
2172 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, image->assembly_name);
2173 values [MONO_ASSEMBLYREF_MAJOR_VERSION] = cols [MONO_ASSEMBLY_MAJOR_VERSION];
2174 values [MONO_ASSEMBLYREF_MINOR_VERSION] = cols [MONO_ASSEMBLY_MINOR_VERSION];
2175 values [MONO_ASSEMBLYREF_BUILD_NUMBER] = cols [MONO_ASSEMBLY_BUILD_NUMBER];
2176 values [MONO_ASSEMBLYREF_REV_NUMBER] = cols [MONO_ASSEMBLY_REV_NUMBER];
2177 values [MONO_ASSEMBLYREF_FLAGS] = 0;
2178 values [MONO_ASSEMBLYREF_CULTURE] = 0;
2179 values [MONO_ASSEMBLYREF_HASH_VALUE] = 0;
2181 if (strcmp ("", image->assembly->aname.culture)) {
2182 values [MONO_ASSEMBLYREF_CULTURE] = string_heap_insert (&assembly->sheap,
2183 image->assembly->aname.culture);
2186 if ((pubkey = mono_image_get_public_key (image, &publen))) {
2187 guchar pubtoken [9];
2188 pubtoken [0] = 8;
2189 mono_digest_get_public_token (pubtoken + 1, (guchar*)pubkey, publen);
2190 values [MONO_ASSEMBLYREF_PUBLIC_KEY] = mono_image_add_stream_data (&assembly->blob, (char*)pubtoken, 9);
2191 } else {
2192 values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0;
2194 token <<= MONO_RESOLTION_SCOPE_BITS;
2195 token |= MONO_RESOLTION_SCOPE_ASSEMBLYREF;
2196 g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
2197 return token;
2200 static guint32
2201 create_typespec (MonoDynamicImage *assembly, MonoType *type)
2203 MonoDynamicTable *table;
2204 guint32 *values;
2205 guint32 token;
2206 SigBuffer buf;
2208 if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typespec, type))))
2209 return token;
2211 sigbuffer_init (&buf, 32);
2212 switch (type->type) {
2213 case MONO_TYPE_FNPTR:
2214 case MONO_TYPE_PTR:
2215 case MONO_TYPE_SZARRAY:
2216 case MONO_TYPE_ARRAY:
2217 case MONO_TYPE_VAR:
2218 case MONO_TYPE_MVAR:
2219 case MONO_TYPE_GENERICINST:
2220 encode_type (assembly, type, &buf);
2221 break;
2222 case MONO_TYPE_CLASS:
2223 case MONO_TYPE_VALUETYPE: {
2224 MonoClass *k = mono_class_from_mono_type (type);
2225 if (!k || !k->generic_container) {
2226 sigbuffer_free (&buf);
2227 return 0;
2229 encode_type (assembly, type, &buf);
2230 break;
2232 default:
2233 sigbuffer_free (&buf);
2234 return 0;
2237 table = &assembly->tables [MONO_TABLE_TYPESPEC];
2238 if (assembly->save) {
2239 token = sigbuffer_add_to_blob_cached (assembly, &buf);
2240 alloc_table (table, table->rows + 1);
2241 values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
2242 values [MONO_TYPESPEC_SIGNATURE] = token;
2244 sigbuffer_free (&buf);
2246 token = MONO_TYPEDEFORREF_TYPESPEC | (table->next_idx << MONO_TYPEDEFORREF_BITS);
2247 g_hash_table_insert (assembly->typespec, type, GUINT_TO_POINTER(token));
2248 table->next_idx ++;
2249 return token;
2252 static guint32
2253 mono_image_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboolean try_typespec)
2255 MonoDynamicTable *table;
2256 guint32 *values;
2257 guint32 token, scope, enclosing;
2258 MonoClass *klass;
2260 /* if the type requires a typespec, we must try that first*/
2261 if (try_typespec && (token = create_typespec (assembly, type)))
2262 return token;
2263 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
2264 if (token)
2265 return token;
2266 klass = mono_class_from_mono_type (type);
2267 if (!klass)
2268 klass = mono_class_from_mono_type (type);
2271 * If it's in the same module and not a generic type parameter:
2273 if ((klass->image == &assembly->image) && (type->type != MONO_TYPE_VAR) &&
2274 (type->type != MONO_TYPE_MVAR)) {
2275 MonoReflectionTypeBuilder *tb = klass->reflection_info;
2276 token = MONO_TYPEDEFORREF_TYPEDEF | (tb->table_idx << MONO_TYPEDEFORREF_BITS);
2277 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), klass->reflection_info);
2278 return token;
2281 if (klass->nested_in) {
2282 enclosing = mono_image_typedef_or_ref_full (assembly, &klass->nested_in->byval_arg, FALSE);
2283 /* get the typeref idx of the enclosing type */
2284 enclosing >>= MONO_TYPEDEFORREF_BITS;
2285 scope = (enclosing << MONO_RESOLTION_SCOPE_BITS) | MONO_RESOLTION_SCOPE_TYPEREF;
2286 } else {
2287 scope = resolution_scope_from_image (assembly, klass->image);
2289 table = &assembly->tables [MONO_TABLE_TYPEREF];
2290 if (assembly->save) {
2291 alloc_table (table, table->rows + 1);
2292 values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
2293 values [MONO_TYPEREF_SCOPE] = scope;
2294 values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
2295 values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
2297 token = MONO_TYPEDEFORREF_TYPEREF | (table->next_idx << MONO_TYPEDEFORREF_BITS); /* typeref */
2298 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
2299 table->next_idx ++;
2300 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), klass->reflection_info);
2301 return token;
2305 * Despite the name, we handle also TypeSpec (with the above helper).
2307 static guint32
2308 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
2310 return mono_image_typedef_or_ref_full (assembly, type, TRUE);
2313 #ifndef DISABLE_REFLECTION_EMIT
2315 * Insert a memberef row into the metadata: the token that point to the memberref
2316 * is returned. Caching is done in the caller (mono_image_get_methodref_token() or
2317 * mono_image_get_fieldref_token()).
2318 * The sig param is an index to an already built signature.
2320 static guint32
2321 mono_image_get_memberref_token (MonoDynamicImage *assembly, MonoType *type, const char *name, guint32 sig)
2323 MonoDynamicTable *table;
2324 guint32 *values;
2325 guint32 token, pclass;
2326 guint32 parent;
2328 parent = mono_image_typedef_or_ref (assembly, type);
2329 switch (parent & MONO_TYPEDEFORREF_MASK) {
2330 case MONO_TYPEDEFORREF_TYPEREF:
2331 pclass = MONO_MEMBERREF_PARENT_TYPEREF;
2332 break;
2333 case MONO_TYPEDEFORREF_TYPESPEC:
2334 pclass = MONO_MEMBERREF_PARENT_TYPESPEC;
2335 break;
2336 case MONO_TYPEDEFORREF_TYPEDEF:
2337 pclass = MONO_MEMBERREF_PARENT_TYPEDEF;
2338 break;
2339 default:
2340 g_warning ("unknown typeref or def token 0x%08x for %s", parent, name);
2341 return 0;
2343 /* extract the index */
2344 parent >>= MONO_TYPEDEFORREF_BITS;
2346 table = &assembly->tables [MONO_TABLE_MEMBERREF];
2348 if (assembly->save) {
2349 alloc_table (table, table->rows + 1);
2350 values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
2351 values [MONO_MEMBERREF_CLASS] = pclass | (parent << MONO_MEMBERREF_PARENT_BITS);
2352 values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
2353 values [MONO_MEMBERREF_SIGNATURE] = sig;
2356 token = MONO_TOKEN_MEMBER_REF | table->next_idx;
2357 table->next_idx ++;
2359 return token;
2362 static guint32
2363 mono_image_get_methodref_token (MonoDynamicImage *assembly, MonoMethod *method, gboolean create_typespec)
2365 guint32 token;
2366 MonoMethodSignature *sig;
2368 create_typespec = create_typespec && method->is_generic && method->klass->image != &assembly->image;
2370 if (create_typespec) {
2371 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, GUINT_TO_POINTER (GPOINTER_TO_UINT (method) + 1)));
2372 if (token)
2373 return token;
2376 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
2377 if (token && !create_typespec)
2378 return token;
2380 g_assert (!method->is_inflated);
2381 if (!token) {
2383 * A methodref signature can't contain an unmanaged calling convention.
2385 sig = mono_metadata_signature_dup (mono_method_signature (method));
2386 if ((sig->call_convention != MONO_CALL_DEFAULT) && (sig->call_convention != MONO_CALL_VARARG))
2387 sig->call_convention = MONO_CALL_DEFAULT;
2388 token = mono_image_get_memberref_token (assembly, &method->klass->byval_arg,
2389 method->name, method_encode_signature (assembly, sig));
2390 g_free (sig);
2391 g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
2394 if (create_typespec) {
2395 MonoDynamicTable *table = &assembly->tables [MONO_TABLE_METHODSPEC];
2396 g_assert (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF);
2397 token = (mono_metadata_token_index (token) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODREF;
2399 if (assembly->save) {
2400 guint32 *values;
2402 alloc_table (table, table->rows + 1);
2403 values = table->values + table->next_idx * MONO_METHODSPEC_SIZE;
2404 values [MONO_METHODSPEC_METHOD] = token;
2405 values [MONO_METHODSPEC_SIGNATURE] = encode_generic_method_sig (assembly, &mono_method_get_generic_container (method)->context);
2408 token = MONO_TOKEN_METHOD_SPEC | table->next_idx;
2409 table->next_idx ++;
2410 /*methodspec and memberef tokens are diferent, */
2411 g_hash_table_insert (assembly->handleref, GUINT_TO_POINTER (GPOINTER_TO_UINT (method) + 1), GUINT_TO_POINTER (token));
2412 return token;
2414 return token;
2417 static guint32
2418 mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method)
2420 guint32 token;
2421 ReflectionMethodBuilder rmb;
2422 char *name;
2424 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
2425 if (token)
2426 return token;
2428 name = mono_string_to_utf8 (method->name);
2429 reflection_methodbuilder_from_method_builder (&rmb, method);
2432 * A methodref signature can't contain an unmanaged calling convention.
2433 * Since some flags are encoded as part of call_conv, we need to check against it.
2435 if ((rmb.call_conv & ~0x60) != MONO_CALL_DEFAULT && (rmb.call_conv & ~0x60) != MONO_CALL_VARARG)
2436 rmb.call_conv = (rmb.call_conv & 0x60) | MONO_CALL_DEFAULT;
2437 token = mono_image_get_memberref_token (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)rmb.type),
2438 name, method_builder_encode_signature (assembly, &rmb));
2440 g_free (name);
2441 g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
2442 return token;
2445 static guint32
2446 mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 original,
2447 const gchar *name, guint32 sig)
2449 MonoDynamicTable *table;
2450 guint32 token;
2451 guint32 *values;
2453 table = &assembly->tables [MONO_TABLE_MEMBERREF];
2455 if (assembly->save) {
2456 alloc_table (table, table->rows + 1);
2457 values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
2458 values [MONO_MEMBERREF_CLASS] = original;
2459 values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
2460 values [MONO_MEMBERREF_SIGNATURE] = sig;
2463 token = MONO_TOKEN_MEMBER_REF | table->next_idx;
2464 table->next_idx ++;
2466 return token;
2469 static guint32
2470 encode_generic_method_definition_sig (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb)
2472 SigBuffer buf;
2473 int i;
2474 guint32 nparams = mono_array_length (mb->generic_params);
2475 guint32 idx;
2477 if (!assembly->save)
2478 return 0;
2480 sigbuffer_init (&buf, 32);
2482 sigbuffer_add_value (&buf, 0xa);
2483 sigbuffer_add_value (&buf, nparams);
2485 for (i = 0; i < nparams; i++) {
2486 sigbuffer_add_value (&buf, MONO_TYPE_MVAR);
2487 sigbuffer_add_value (&buf, i);
2490 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
2491 sigbuffer_free (&buf);
2492 return idx;
2495 static guint32
2496 mono_image_get_methodspec_token_for_generic_method_definition (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb)
2498 MonoDynamicTable *table;
2499 guint32 *values;
2500 guint32 token, mtoken = 0;
2502 token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->methodspec, mb));
2503 if (token)
2504 return token;
2506 table = &assembly->tables [MONO_TABLE_METHODSPEC];
2508 mtoken = mono_image_get_methodref_token_for_methodbuilder (assembly, mb);
2509 switch (mono_metadata_token_table (mtoken)) {
2510 case MONO_TABLE_MEMBERREF:
2511 mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODREF;
2512 break;
2513 case MONO_TABLE_METHOD:
2514 mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODDEF;
2515 break;
2516 default:
2517 g_assert_not_reached ();
2520 if (assembly->save) {
2521 alloc_table (table, table->rows + 1);
2522 values = table->values + table->next_idx * MONO_METHODSPEC_SIZE;
2523 values [MONO_METHODSPEC_METHOD] = mtoken;
2524 values [MONO_METHODSPEC_SIGNATURE] = encode_generic_method_definition_sig (assembly, mb);
2527 token = MONO_TOKEN_METHOD_SPEC | table->next_idx;
2528 table->next_idx ++;
2530 mono_g_hash_table_insert (assembly->methodspec, mb, GUINT_TO_POINTER(token));
2531 return token;
2534 static guint32
2535 mono_image_get_methodbuilder_token (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, gboolean create_methodspec)
2537 guint32 token;
2539 if (mb->generic_params && create_methodspec)
2540 return mono_image_get_methodspec_token_for_generic_method_definition (assembly, mb);
2542 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, mb));
2543 if (token)
2544 return token;
2546 token = mono_image_get_methodref_token_for_methodbuilder (assembly, mb);
2547 g_hash_table_insert (assembly->handleref, mb, GUINT_TO_POINTER(token));
2548 return token;
2551 static guint32
2552 mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *mb)
2554 guint32 token;
2555 ReflectionMethodBuilder rmb;
2556 char *name;
2558 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, mb));
2559 if (token)
2560 return token;
2562 reflection_methodbuilder_from_ctor_builder (&rmb, mb);
2564 name = mono_string_to_utf8 (rmb.name);
2565 token = mono_image_get_memberref_token (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)rmb.type),
2566 name, method_builder_encode_signature (assembly, &rmb));
2568 g_free (name);
2569 g_hash_table_insert (assembly->handleref, mb, GUINT_TO_POINTER(token));
2570 return token;
2572 #endif
2574 static gboolean
2575 is_field_on_inst (MonoClassField *field)
2577 return (field->parent->generic_class && field->parent->generic_class->is_dynamic && ((MonoDynamicGenericClass*)field->parent->generic_class)->fields);
2581 * If FIELD is a field of a MonoDynamicGenericClass, return its non-inflated type.
2583 static MonoType*
2584 get_field_on_inst_generic_type (MonoClassField *field)
2586 MonoDynamicGenericClass *dgclass;
2587 int field_index;
2589 g_assert (is_field_on_inst (field));
2591 dgclass = (MonoDynamicGenericClass*)field->parent->generic_class;
2592 field_index = field - dgclass->fields;
2594 g_assert (field_index >= 0 && field_index < dgclass->count_fields);
2595 return dgclass->field_generic_types [field_index];
2598 #ifndef DISABLE_REFLECTION_EMIT
2599 static guint32
2600 mono_image_get_fieldref_token (MonoDynamicImage *assembly, MonoReflectionField *f)
2602 MonoType *type;
2603 guint32 token;
2604 MonoClassField *field;
2606 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, f));
2607 if (token)
2608 return token;
2609 g_assert (f->field->parent);
2611 field = f->field;
2612 if (field->parent->generic_class && field->parent->generic_class->container_class && field->parent->generic_class->container_class->fields) {
2613 int index = field - field->parent->fields;
2614 type = field->parent->generic_class->container_class->fields [index].type;
2615 } else {
2616 if (is_field_on_inst (f->field))
2617 type = get_field_on_inst_generic_type (f->field);
2618 else
2619 type = f->field->type;
2621 token = mono_image_get_memberref_token (assembly, &f->field->parent->byval_arg,
2622 mono_field_get_name (f->field),
2623 fieldref_encode_signature (assembly, type));
2624 g_hash_table_insert (assembly->handleref, f, GUINT_TO_POINTER(token));
2625 return token;
2628 static guint32
2629 mono_image_get_field_on_inst_token (MonoDynamicImage *assembly, MonoReflectionFieldOnTypeBuilderInst *f)
2631 guint32 token;
2632 MonoClass *klass;
2633 MonoGenericClass *gclass;
2634 MonoDynamicGenericClass *dgclass;
2635 MonoReflectionFieldBuilder *fb = f->fb;
2636 MonoType *type;
2637 char *name;
2639 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, f));
2640 if (token)
2641 return token;
2642 type = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst);
2643 klass = mono_class_from_mono_type (type);
2644 gclass = type->data.generic_class;
2645 g_assert (gclass->is_dynamic);
2646 dgclass = (MonoDynamicGenericClass *) gclass;
2648 name = mono_string_to_utf8 (fb->name);
2649 token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name,
2650 field_encode_signature (assembly, fb));
2651 g_free (name);
2652 g_hash_table_insert (assembly->handleref, f, GUINT_TO_POINTER (token));
2653 return token;
2656 static guint32
2657 mono_image_get_ctor_on_inst_token (MonoDynamicImage *assembly, MonoReflectionCtorOnTypeBuilderInst *c, gboolean create_methodspec)
2659 guint32 sig, token;
2660 MonoClass *klass;
2661 MonoGenericClass *gclass;
2662 MonoDynamicGenericClass *dgclass;
2663 MonoReflectionCtorBuilder *cb = c->cb;
2664 ReflectionMethodBuilder rmb;
2665 MonoType *type;
2666 char *name;
2668 /* A ctor cannot be a generic method, so we can ignore create_methodspec */
2670 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, c));
2671 if (token)
2672 return token;
2673 type = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst);
2674 klass = mono_class_from_mono_type (type);
2675 gclass = type->data.generic_class;
2676 g_assert (gclass->is_dynamic);
2677 dgclass = (MonoDynamicGenericClass *) gclass;
2679 reflection_methodbuilder_from_ctor_builder (&rmb, cb);
2681 name = mono_string_to_utf8 (rmb.name);
2683 sig = method_builder_encode_signature (assembly, &rmb);
2685 token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name, sig);
2686 g_free (name);
2688 g_hash_table_insert (assembly->handleref, c, GUINT_TO_POINTER (token));
2689 return token;
2692 static guint32
2693 mono_image_get_method_on_inst_token (MonoDynamicImage *assembly, MonoReflectionMethodOnTypeBuilderInst *m, gboolean create_methodspec)
2695 guint32 sig, token;
2696 MonoClass *klass;
2697 MonoGenericClass *gclass;
2698 MonoReflectionMethodBuilder *mb = m->mb;
2699 ReflectionMethodBuilder rmb;
2700 MonoType *type;
2701 char *name;
2703 if (create_methodspec && mb->generic_params)
2704 // FIXME:
2705 g_assert_not_reached ();
2707 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, m));
2708 if (token)
2709 return token;
2710 type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst);
2711 klass = mono_class_from_mono_type (type);
2712 gclass = type->data.generic_class;
2713 g_assert (gclass->is_dynamic);
2715 reflection_methodbuilder_from_method_builder (&rmb, mb);
2717 name = mono_string_to_utf8 (rmb.name);
2719 sig = method_builder_encode_signature (assembly, &rmb);
2721 token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name, sig);
2722 g_free (name);
2724 g_hash_table_insert (assembly->handleref, m, GUINT_TO_POINTER (token));
2725 return token;
2728 static guint32
2729 encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context)
2731 SigBuffer buf;
2732 int i;
2733 guint32 nparams = context->method_inst->type_argc;
2734 guint32 idx;
2736 if (!assembly->save)
2737 return 0;
2739 sigbuffer_init (&buf, 32);
2741 * FIXME: vararg, explicit_this, differenc call_conv values...
2743 sigbuffer_add_value (&buf, 0xa); /* FIXME FIXME FIXME */
2744 sigbuffer_add_value (&buf, nparams);
2746 for (i = 0; i < nparams; i++)
2747 encode_type (assembly, context->method_inst->type_argv [i], &buf);
2749 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
2750 sigbuffer_free (&buf);
2751 return idx;
2754 static guint32
2755 method_encode_methodspec (MonoDynamicImage *assembly, MonoMethod *method)
2757 MonoDynamicTable *table;
2758 guint32 *values;
2759 guint32 token, mtoken = 0, sig;
2760 MonoMethodInflated *imethod;
2761 MonoMethod *declaring;
2763 table = &assembly->tables [MONO_TABLE_METHODSPEC];
2765 g_assert (method->is_inflated);
2766 imethod = (MonoMethodInflated *) method;
2767 declaring = imethod->declaring;
2769 sig = method_encode_signature (assembly, mono_method_signature (declaring));
2770 mtoken = mono_image_get_memberref_token (assembly, &method->klass->byval_arg, declaring->name, sig);
2772 if (!mono_method_signature (declaring)->generic_param_count)
2773 return mtoken;
2775 switch (mono_metadata_token_table (mtoken)) {
2776 case MONO_TABLE_MEMBERREF:
2777 mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODREF;
2778 break;
2779 case MONO_TABLE_METHOD:
2780 mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODDEF;
2781 break;
2782 default:
2783 g_assert_not_reached ();
2786 sig = encode_generic_method_sig (assembly, mono_method_get_context (method));
2788 if (assembly->save) {
2789 alloc_table (table, table->rows + 1);
2790 values = table->values + table->next_idx * MONO_METHODSPEC_SIZE;
2791 values [MONO_METHODSPEC_METHOD] = mtoken;
2792 values [MONO_METHODSPEC_SIGNATURE] = sig;
2795 token = MONO_TOKEN_METHOD_SPEC | table->next_idx;
2796 table->next_idx ++;
2798 return token;
2801 static guint32
2802 mono_image_get_methodspec_token (MonoDynamicImage *assembly, MonoMethod *method)
2804 MonoMethodInflated *imethod;
2805 guint32 token;
2807 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
2808 if (token)
2809 return token;
2811 g_assert (method->is_inflated);
2812 imethod = (MonoMethodInflated *) method;
2814 if (mono_method_signature (imethod->declaring)->generic_param_count) {
2815 token = method_encode_methodspec (assembly, method);
2816 } else {
2817 guint32 sig = method_encode_signature (
2818 assembly, mono_method_signature (imethod->declaring));
2819 token = mono_image_get_memberref_token (
2820 assembly, &method->klass->byval_arg, method->name, sig);
2823 g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
2824 return token;
2827 static guint32
2828 mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m)
2830 MonoMethodInflated *imethod = (MonoMethodInflated *) m;
2831 guint32 sig, token;
2833 sig = method_encode_signature (assembly, mono_method_signature (imethod->declaring));
2834 token = mono_image_get_memberref_token (
2835 assembly, &m->klass->byval_arg, m->name, sig);
2837 return token;
2840 static guint32
2841 create_generic_typespec (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb)
2843 MonoDynamicTable *table;
2844 MonoClass *klass;
2845 MonoType *type;
2846 guint32 *values;
2847 guint32 token;
2848 SigBuffer buf;
2849 int count, i;
2852 * We're creating a TypeSpec for the TypeBuilder of a generic type declaration,
2853 * ie. what we'd normally use as the generic type in a TypeSpec signature.
2854 * Because of this, we must not insert it into the `typeref' hash table.
2856 type = mono_reflection_type_get_handle ((MonoReflectionType*)tb);
2857 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typespec, type));
2858 if (token)
2859 return token;
2861 sigbuffer_init (&buf, 32);
2863 g_assert (tb->generic_params);
2864 klass = mono_class_from_mono_type (type);
2866 if (tb->generic_container)
2867 mono_reflection_create_generic_class (tb);
2869 sigbuffer_add_value (&buf, MONO_TYPE_GENERICINST);
2870 g_assert (klass->generic_container);
2871 sigbuffer_add_value (&buf, klass->byval_arg.type);
2872 sigbuffer_add_value (&buf, mono_image_typedef_or_ref_full (assembly, &klass->byval_arg, FALSE));
2874 count = mono_array_length (tb->generic_params);
2875 sigbuffer_add_value (&buf, count);
2876 for (i = 0; i < count; i++) {
2877 MonoReflectionGenericParam *gparam;
2879 gparam = mono_array_get (tb->generic_params, MonoReflectionGenericParam *, i);
2881 encode_type (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)gparam), &buf);
2884 table = &assembly->tables [MONO_TABLE_TYPESPEC];
2886 if (assembly->save) {
2887 token = sigbuffer_add_to_blob_cached (assembly, &buf);
2888 alloc_table (table, table->rows + 1);
2889 values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
2890 values [MONO_TYPESPEC_SIGNATURE] = token;
2892 sigbuffer_free (&buf);
2894 token = MONO_TYPEDEFORREF_TYPESPEC | (table->next_idx << MONO_TYPEDEFORREF_BITS);
2895 g_hash_table_insert (assembly->typespec, type, GUINT_TO_POINTER(token));
2896 table->next_idx ++;
2897 return token;
2901 * Return a copy of TYPE, adding the custom modifiers in MODREQ and MODOPT.
2903 static MonoType*
2904 add_custom_modifiers (MonoDynamicImage *assembly, MonoType *type, MonoArray *modreq, MonoArray *modopt)
2906 int i, count, len, pos;
2907 MonoType *t;
2909 count = 0;
2910 if (modreq)
2911 count += mono_array_length (modreq);
2912 if (modopt)
2913 count += mono_array_length (modopt);
2915 if (count == 0)
2916 return mono_metadata_type_dup (NULL, type);
2918 len = sizeof (MonoType) + ((gint32)count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod);
2919 t = g_malloc (len);
2920 memcpy (t, type, sizeof (MonoType));
2922 t->num_mods = count;
2923 pos = 0;
2924 if (modreq) {
2925 for (i = 0; i < mono_array_length (modreq); ++i) {
2926 MonoType *mod = mono_type_array_get_and_resolve (modreq, i);
2927 t->modifiers [pos].required = 1;
2928 t->modifiers [pos].token = mono_image_typedef_or_ref (assembly, mod);
2929 pos ++;
2932 if (modopt) {
2933 for (i = 0; i < mono_array_length (modopt); ++i) {
2934 MonoType *mod = mono_type_array_get_and_resolve (modopt, i);
2935 t->modifiers [pos].required = 0;
2936 t->modifiers [pos].token = mono_image_typedef_or_ref (assembly, mod);
2937 pos ++;
2941 return t;
2944 static guint32
2945 mono_image_get_generic_field_token (MonoDynamicImage *assembly, MonoReflectionFieldBuilder *fb)
2947 MonoDynamicTable *table;
2948 MonoClass *klass;
2949 MonoType *custom = NULL;
2950 guint32 *values;
2951 guint32 token, pclass, parent, sig;
2952 gchar *name;
2954 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, fb));
2955 if (token)
2956 return token;
2958 klass = mono_class_from_mono_type (mono_reflection_type_get_handle (fb->typeb));
2959 name = mono_string_to_utf8 (fb->name);
2961 /* fb->type does not include the custom modifiers */
2962 /* FIXME: We should do this in one place when a fieldbuilder is created */
2963 if (fb->modreq || fb->modopt) {
2964 custom = add_custom_modifiers (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)fb->type), fb->modreq, fb->modopt);
2965 sig = fieldref_encode_signature (assembly, custom);
2966 g_free (custom);
2967 } else {
2968 sig = fieldref_encode_signature (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)fb->type));
2971 parent = create_generic_typespec (assembly, (MonoReflectionTypeBuilder *) fb->typeb);
2972 g_assert ((parent & MONO_TYPEDEFORREF_MASK) == MONO_TYPEDEFORREF_TYPESPEC);
2974 pclass = MONO_MEMBERREF_PARENT_TYPESPEC;
2975 parent >>= MONO_TYPEDEFORREF_BITS;
2977 table = &assembly->tables [MONO_TABLE_MEMBERREF];
2979 if (assembly->save) {
2980 alloc_table (table, table->rows + 1);
2981 values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
2982 values [MONO_MEMBERREF_CLASS] = pclass | (parent << MONO_MEMBERREF_PARENT_BITS);
2983 values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
2984 values [MONO_MEMBERREF_SIGNATURE] = sig;
2987 token = MONO_TOKEN_MEMBER_REF | table->next_idx;
2988 table->next_idx ++;
2989 g_hash_table_insert (assembly->handleref, fb, GUINT_TO_POINTER(token));
2990 g_free (name);
2991 return token;
2994 static guint32
2995 mono_reflection_encode_sighelper (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper)
2997 SigBuffer buf;
2998 guint32 nargs;
2999 guint32 size;
3000 guint32 i, idx;
3002 if (!assembly->save)
3003 return 0;
3005 /* FIXME: this means SignatureHelper.SignatureHelpType.HELPER_METHOD */
3006 g_assert (helper->type == 2);
3008 if (helper->arguments)
3009 nargs = mono_array_length (helper->arguments);
3010 else
3011 nargs = 0;
3013 size = 10 + (nargs * 10);
3015 sigbuffer_init (&buf, 32);
3017 /* Encode calling convention */
3018 /* Change Any to Standard */
3019 if ((helper->call_conv & 0x03) == 0x03)
3020 helper->call_conv = 0x01;
3021 /* explicit_this implies has_this */
3022 if (helper->call_conv & 0x40)
3023 helper->call_conv &= 0x20;
3025 if (helper->call_conv == 0) { /* Unmanaged */
3026 idx = helper->unmanaged_call_conv - 1;
3027 } else {
3028 /* Managed */
3029 idx = helper->call_conv & 0x60; /* has_this + explicit_this */
3030 if (helper->call_conv & 0x02) /* varargs */
3031 idx += 0x05;
3034 sigbuffer_add_byte (&buf, idx);
3035 sigbuffer_add_value (&buf, nargs);
3036 encode_reflection_type (assembly, helper->return_type, &buf);
3037 for (i = 0; i < nargs; ++i) {
3038 MonoArray *modreqs = NULL;
3039 MonoArray *modopts = NULL;
3040 MonoReflectionType *pt;
3042 if (helper->modreqs && (i < mono_array_length (helper->modreqs)))
3043 modreqs = mono_array_get (helper->modreqs, MonoArray*, i);
3044 if (helper->modopts && (i < mono_array_length (helper->modopts)))
3045 modopts = mono_array_get (helper->modopts, MonoArray*, i);
3047 encode_custom_modifiers (assembly, modreqs, modopts, &buf);
3048 pt = mono_array_get (helper->arguments, MonoReflectionType*, i);
3049 encode_reflection_type (assembly, pt, &buf);
3051 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
3052 sigbuffer_free (&buf);
3054 return idx;
3057 static guint32
3058 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper)
3060 guint32 idx;
3061 MonoDynamicTable *table;
3062 guint32 *values;
3064 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
3065 idx = table->next_idx ++;
3066 table->rows ++;
3067 alloc_table (table, table->rows);
3068 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
3070 values [MONO_STAND_ALONE_SIGNATURE] =
3071 mono_reflection_encode_sighelper (assembly, helper);
3073 return idx;
3076 static int
3077 reflection_cc_to_file (int call_conv) {
3078 switch (call_conv & 0x3) {
3079 case 0:
3080 case 1: return MONO_CALL_DEFAULT;
3081 case 2: return MONO_CALL_VARARG;
3082 default:
3083 g_assert_not_reached ();
3085 return 0;
3087 #endif /* !DISABLE_REFLECTION_EMIT */
3089 typedef struct {
3090 MonoType *parent;
3091 MonoMethodSignature *sig;
3092 char *name;
3093 guint32 token;
3094 } ArrayMethod;
3096 #ifndef DISABLE_REFLECTION_EMIT
3097 static guint32
3098 mono_image_get_array_token (MonoDynamicImage *assembly, MonoReflectionArrayMethod *m)
3100 guint32 nparams, i;
3101 GList *tmp;
3102 char *name;
3103 MonoMethodSignature *sig;
3104 ArrayMethod *am;
3105 MonoType *mtype;
3107 name = mono_string_to_utf8 (m->name);
3108 nparams = mono_array_length (m->parameters);
3109 sig = g_malloc0 (sizeof (MonoMethodSignature) + sizeof (MonoType*) * nparams);
3110 sig->hasthis = 1;
3111 sig->sentinelpos = -1;
3112 sig->call_convention = reflection_cc_to_file (m->call_conv);
3113 sig->param_count = nparams;
3114 sig->ret = m->ret ? mono_reflection_type_get_handle (m->ret): &mono_defaults.void_class->byval_arg;
3115 mtype = mono_reflection_type_get_handle (m->parent);
3116 for (i = 0; i < nparams; ++i)
3117 sig->params [i] = mono_type_array_get_and_resolve (m->parameters, i);
3119 for (tmp = assembly->array_methods; tmp; tmp = tmp->next) {
3120 am = tmp->data;
3121 if (strcmp (name, am->name) == 0 &&
3122 mono_metadata_type_equal (am->parent, mtype) &&
3123 mono_metadata_signature_equal (am->sig, sig)) {
3124 g_free (name);
3125 g_free (sig);
3126 m->table_idx = am->token & 0xffffff;
3127 return am->token;
3130 am = g_new0 (ArrayMethod, 1);
3131 am->name = name;
3132 am->sig = sig;
3133 am->parent = mtype;
3134 am->token = mono_image_get_memberref_token (assembly, am->parent, name,
3135 method_encode_signature (assembly, sig));
3136 assembly->array_methods = g_list_prepend (assembly->array_methods, am);
3137 m->table_idx = am->token & 0xffffff;
3138 return am->token;
3140 #endif
3143 * Insert into the metadata tables all the info about the TypeBuilder tb.
3144 * Data in the tables is inserted in a predefined order, since some tables need to be sorted.
3146 static void
3147 mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicImage *assembly)
3149 MonoDynamicTable *table;
3150 guint *values;
3151 int i, is_object = 0, is_system = 0;
3152 char *n;
3154 table = &assembly->tables [MONO_TABLE_TYPEDEF];
3155 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
3156 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
3157 n = mono_string_to_utf8 (tb->name);
3158 if (strcmp (n, "Object") == 0)
3159 is_object++;
3160 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
3161 g_free (n);
3162 n = mono_string_to_utf8 (tb->nspace);
3163 if (strcmp (n, "System") == 0)
3164 is_system++;
3165 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
3166 g_free (n);
3167 if (tb->parent && !(is_system && is_object) &&
3168 !(tb->attrs & TYPE_ATTRIBUTE_INTERFACE)) { /* interfaces don't have a parent */
3169 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent));
3170 } else {
3171 values [MONO_TYPEDEF_EXTENDS] = 0;
3173 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
3174 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
3177 * if we have explicitlayout or sequentiallayouts, output data in the
3178 * ClassLayout table.
3180 if (((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) &&
3181 ((tb->class_size > 0) || (tb->packing_size > 0))) {
3182 table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
3183 table->rows++;
3184 alloc_table (table, table->rows);
3185 values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
3186 values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
3187 values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
3188 values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
3191 /* handle interfaces */
3192 if (tb->interfaces) {
3193 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
3194 i = table->rows;
3195 table->rows += mono_array_length (tb->interfaces);
3196 alloc_table (table, table->rows);
3197 values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE;
3198 for (i = 0; i < mono_array_length (tb->interfaces); ++i) {
3199 MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i);
3200 values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx;
3201 values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, mono_reflection_type_get_handle (iface));
3202 values += MONO_INTERFACEIMPL_SIZE;
3206 /* handle fields */
3207 if (tb->fields) {
3208 table = &assembly->tables [MONO_TABLE_FIELD];
3209 table->rows += tb->num_fields;
3210 alloc_table (table, table->rows);
3211 for (i = 0; i < tb->num_fields; ++i)
3212 mono_image_get_field_info (
3213 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
3216 /* handle constructors */
3217 if (tb->ctors) {
3218 table = &assembly->tables [MONO_TABLE_METHOD];
3219 table->rows += mono_array_length (tb->ctors);
3220 alloc_table (table, table->rows);
3221 for (i = 0; i < mono_array_length (tb->ctors); ++i)
3222 mono_image_get_ctor_info (domain,
3223 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
3226 /* handle methods */
3227 if (tb->methods) {
3228 table = &assembly->tables [MONO_TABLE_METHOD];
3229 table->rows += tb->num_methods;
3230 alloc_table (table, table->rows);
3231 for (i = 0; i < tb->num_methods; ++i)
3232 mono_image_get_method_info (
3233 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
3236 /* Do the same with properties etc.. */
3237 if (tb->events && mono_array_length (tb->events)) {
3238 table = &assembly->tables [MONO_TABLE_EVENT];
3239 table->rows += mono_array_length (tb->events);
3240 alloc_table (table, table->rows);
3241 table = &assembly->tables [MONO_TABLE_EVENTMAP];
3242 table->rows ++;
3243 alloc_table (table, table->rows);
3244 values = table->values + table->rows * MONO_EVENT_MAP_SIZE;
3245 values [MONO_EVENT_MAP_PARENT] = tb->table_idx;
3246 values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx;
3247 for (i = 0; i < mono_array_length (tb->events); ++i)
3248 mono_image_get_event_info (
3249 mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly);
3251 if (tb->properties && mono_array_length (tb->properties)) {
3252 table = &assembly->tables [MONO_TABLE_PROPERTY];
3253 table->rows += mono_array_length (tb->properties);
3254 alloc_table (table, table->rows);
3255 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
3256 table->rows ++;
3257 alloc_table (table, table->rows);
3258 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
3259 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
3260 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
3261 for (i = 0; i < mono_array_length (tb->properties); ++i)
3262 mono_image_get_property_info (
3263 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
3266 /* handle generic parameters */
3267 if (tb->generic_params) {
3268 table = &assembly->tables [MONO_TABLE_GENERICPARAM];
3269 table->rows += mono_array_length (tb->generic_params);
3270 alloc_table (table, table->rows);
3271 for (i = 0; i < mono_array_length (tb->generic_params); ++i) {
3272 guint32 owner = MONO_TYPEORMETHOD_TYPE | (tb->table_idx << MONO_TYPEORMETHOD_BITS);
3274 mono_image_get_generic_param_info (
3275 mono_array_get (tb->generic_params, MonoReflectionGenericParam*, i), owner, assembly);
3279 mono_image_add_decl_security (assembly,
3280 mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx), tb->permissions);
3282 if (tb->subtypes) {
3283 MonoDynamicTable *ntable;
3285 ntable = &assembly->tables [MONO_TABLE_NESTEDCLASS];
3286 ntable->rows += mono_array_length (tb->subtypes);
3287 alloc_table (ntable, ntable->rows);
3288 values = ntable->values + ntable->next_idx * MONO_NESTED_CLASS_SIZE;
3290 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
3291 MonoReflectionTypeBuilder *subtype = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
3293 values [MONO_NESTED_CLASS_NESTED] = subtype->table_idx;
3294 values [MONO_NESTED_CLASS_ENCLOSING] = tb->table_idx;
3295 /*g_print ("nesting %s (%d) in %s (%d) (rows %d/%d)\n",
3296 mono_string_to_utf8 (subtype->name), subtype->table_idx,
3297 mono_string_to_utf8 (tb->name), tb->table_idx,
3298 ntable->next_idx, ntable->rows);*/
3299 values += MONO_NESTED_CLASS_SIZE;
3300 ntable->next_idx++;
3305 static void
3306 collect_types (GPtrArray *types, MonoReflectionTypeBuilder *type)
3308 int i;
3310 g_ptr_array_add (types, type); /* FIXME: GC object added to unmanaged memory */
3312 if (!type->subtypes)
3313 return;
3315 for (i = 0; i < mono_array_length (type->subtypes); ++i) {
3316 MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
3317 collect_types (types, subtype);
3321 static gint
3322 compare_types_by_table_idx (MonoReflectionTypeBuilder **type1, MonoReflectionTypeBuilder **type2)
3324 if ((*type1)->table_idx < (*type2)->table_idx)
3325 return -1;
3326 else
3327 if ((*type1)->table_idx > (*type2)->table_idx)
3328 return 1;
3329 else
3330 return 0;
3333 static void
3334 params_add_cattrs (MonoDynamicImage *assembly, MonoArray *pinfo) {
3335 int i;
3337 if (!pinfo)
3338 return;
3339 for (i = 0; i < mono_array_length (pinfo); ++i) {
3340 MonoReflectionParamBuilder *pb;
3341 pb = mono_array_get (pinfo, MonoReflectionParamBuilder *, i);
3342 if (!pb)
3343 continue;
3344 mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PARAMDEF, pb->cattrs);
3348 static void
3349 type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb) {
3350 int i;
3352 mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs);
3353 if (tb->fields) {
3354 for (i = 0; i < tb->num_fields; ++i) {
3355 MonoReflectionFieldBuilder* fb;
3356 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
3357 mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs);
3360 if (tb->events) {
3361 for (i = 0; i < mono_array_length (tb->events); ++i) {
3362 MonoReflectionEventBuilder* eb;
3363 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
3364 mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs);
3367 if (tb->properties) {
3368 for (i = 0; i < mono_array_length (tb->properties); ++i) {
3369 MonoReflectionPropertyBuilder* pb;
3370 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
3371 mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs);
3374 if (tb->ctors) {
3375 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
3376 MonoReflectionCtorBuilder* cb;
3377 cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
3378 mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs);
3379 params_add_cattrs (assembly, cb->pinfo);
3383 if (tb->methods) {
3384 for (i = 0; i < tb->num_methods; ++i) {
3385 MonoReflectionMethodBuilder* mb;
3386 mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
3387 mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs);
3388 params_add_cattrs (assembly, mb->pinfo);
3392 if (tb->subtypes) {
3393 for (i = 0; i < mono_array_length (tb->subtypes); ++i)
3394 type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i));
3398 static void
3399 module_add_cattrs (MonoDynamicImage *assembly, MonoReflectionModuleBuilder *moduleb)
3401 int i;
3403 mono_image_add_cattrs (assembly, moduleb->table_idx, MONO_CUSTOM_ATTR_MODULE, moduleb->cattrs);
3405 if (moduleb->global_methods) {
3406 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
3407 MonoReflectionMethodBuilder* mb = mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i);
3408 mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs);
3409 params_add_cattrs (assembly, mb->pinfo);
3413 if (moduleb->global_fields) {
3414 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i) {
3415 MonoReflectionFieldBuilder *fb = mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i);
3416 mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs);
3420 if (moduleb->types) {
3421 for (i = 0; i < moduleb->num_types; ++i)
3422 type_add_cattrs (assembly, mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i));
3426 static void
3427 mono_image_fill_file_table (MonoDomain *domain, MonoReflectionModule *module, MonoDynamicImage *assembly)
3429 MonoDynamicTable *table;
3430 guint32 *values;
3431 char blob_size [6];
3432 guchar hash [20];
3433 char *b = blob_size;
3434 char *dir, *path;
3436 table = &assembly->tables [MONO_TABLE_FILE];
3437 table->rows++;
3438 alloc_table (table, table->rows);
3439 values = table->values + table->next_idx * MONO_FILE_SIZE;
3440 values [MONO_FILE_FLAGS] = FILE_CONTAINS_METADATA;
3441 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, module->image->module_name);
3442 if (module->image->dynamic) {
3443 /* This depends on the fact that the main module is emitted last */
3444 dir = mono_string_to_utf8 (((MonoReflectionModuleBuilder*)module)->assemblyb->dir);
3445 path = g_strdup_printf ("%s%c%s", dir, G_DIR_SEPARATOR, module->image->module_name);
3446 } else {
3447 dir = NULL;
3448 path = g_strdup (module->image->name);
3450 mono_sha1_get_digest_from_file (path, hash);
3451 g_free (dir);
3452 g_free (path);
3453 mono_metadata_encode_value (20, b, &b);
3454 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
3455 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
3456 table->next_idx ++;
3459 static void
3460 mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly)
3462 MonoDynamicTable *table;
3463 int i;
3465 table = &assembly->tables [MONO_TABLE_MODULE];
3466 mb->table_idx = table->next_idx ++;
3467 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert_mstring (&assembly->sheap, mb->module.name);
3468 i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16);
3469 i /= 16;
3470 ++i;
3471 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_GENERATION] = 0;
3472 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i;
3473 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0;
3474 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0;
3477 static guint32
3478 mono_image_fill_export_table_from_class (MonoDomain *domain, MonoClass *klass,
3479 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
3481 MonoDynamicTable *table;
3482 guint32 *values;
3483 guint32 visib, res;
3485 visib = klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3486 if (! ((visib & TYPE_ATTRIBUTE_PUBLIC) || (visib & TYPE_ATTRIBUTE_NESTED_PUBLIC)))
3487 return 0;
3489 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
3490 table->rows++;
3491 alloc_table (table, table->rows);
3492 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
3494 values [MONO_EXP_TYPE_FLAGS] = klass->flags;
3495 values [MONO_EXP_TYPE_TYPEDEF] = klass->type_token;
3496 if (klass->nested_in)
3497 values [MONO_EXP_TYPE_IMPLEMENTATION] = (parent_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
3498 else
3499 values [MONO_EXP_TYPE_IMPLEMENTATION] = (module_index << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_FILE;
3500 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
3501 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
3503 res = table->next_idx;
3505 table->next_idx ++;
3507 /* Emit nested types */
3508 if (klass->ext && klass->ext->nested_classes) {
3509 GList *tmp;
3511 for (tmp = klass->ext->nested_classes; tmp; tmp = tmp->next)
3512 mono_image_fill_export_table_from_class (domain, tmp->data, module_index, table->next_idx - 1, assembly);
3515 return res;
3518 static void
3519 mono_image_fill_export_table (MonoDomain *domain, MonoReflectionTypeBuilder *tb,
3520 guint32 module_index, guint32 parent_index, MonoDynamicImage *assembly)
3522 MonoClass *klass;
3523 guint32 idx, i;
3525 klass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)tb));
3527 klass->type_token = mono_metadata_make_token (MONO_TABLE_TYPEDEF, tb->table_idx);
3529 idx = mono_image_fill_export_table_from_class (domain, klass, module_index,
3530 parent_index, assembly);
3533 * Emit nested types
3534 * We need to do this ourselves since klass->nested_classes is not set up.
3536 if (tb->subtypes) {
3537 for (i = 0; i < mono_array_length (tb->subtypes); ++i)
3538 mono_image_fill_export_table (domain, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i), module_index, idx, assembly);
3542 static void
3543 mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModule *module,
3544 guint32 module_index, MonoDynamicImage *assembly)
3546 MonoImage *image = module->image;
3547 MonoTableInfo *t;
3548 guint32 i;
3550 t = &image->tables [MONO_TABLE_TYPEDEF];
3552 for (i = 0; i < t->rows; ++i) {
3553 MonoClass *klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1));
3555 if (klass->flags & TYPE_ATTRIBUTE_PUBLIC)
3556 mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
3560 static guint32
3561 add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly, MonoClass *klass)
3563 MonoDynamicTable *table;
3564 guint32 *values;
3565 guint32 scope, idx, res, impl;
3566 gboolean forwarder = TRUE;
3568 if (klass->nested_in) {
3569 impl = add_exported_type (assemblyb, assembly, klass->nested_in);
3570 forwarder = FALSE;
3571 } else {
3572 scope = resolution_scope_from_image (assembly, klass->image);
3573 g_assert ((scope & MONO_RESOLTION_SCOPE_MASK) == MONO_RESOLTION_SCOPE_ASSEMBLYREF);
3574 idx = scope >> MONO_RESOLTION_SCOPE_BITS;
3575 impl = (idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
3578 table = &assembly->tables [MONO_TABLE_EXPORTEDTYPE];
3580 table->rows++;
3581 alloc_table (table, table->rows);
3582 values = table->values + table->next_idx * MONO_EXP_TYPE_SIZE;
3584 values [MONO_EXP_TYPE_FLAGS] = forwarder ? TYPE_ATTRIBUTE_FORWARDER : 0;
3585 values [MONO_EXP_TYPE_TYPEDEF] = 0;
3586 values [MONO_EXP_TYPE_IMPLEMENTATION] = impl;
3587 values [MONO_EXP_TYPE_NAME] = string_heap_insert (&assembly->sheap, klass->name);
3588 values [MONO_EXP_TYPE_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
3590 res = (table->next_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_EXP_TYPE;
3592 table->next_idx++;
3594 return res;
3597 static void
3598 mono_image_fill_export_table_from_type_forwarders (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *assembly)
3600 MonoClass *klass;
3601 int i;
3603 if (!assemblyb->type_forwarders)
3604 return;
3606 for (i = 0; i < mono_array_length (assemblyb->type_forwarders); ++i) {
3607 MonoReflectionType *t = mono_array_get (assemblyb->type_forwarders, MonoReflectionType *, i);
3608 MonoType *type;
3609 if (!t)
3610 continue;
3612 type = mono_reflection_type_get_handle (t);
3613 g_assert (type);
3615 klass = mono_class_from_mono_type (type);
3617 add_exported_type (assemblyb, assembly, klass);
3621 #define align_pointer(base,p)\
3622 do {\
3623 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
3624 if (__diff & 3)\
3625 (p) += 4 - (__diff & 3);\
3626 } while (0)
3628 static int
3629 compare_constants (const void *a, const void *b)
3631 const guint32 *a_values = a;
3632 const guint32 *b_values = b;
3633 return a_values [MONO_CONSTANT_PARENT] - b_values [MONO_CONSTANT_PARENT];
3636 static int
3637 compare_semantics (const void *a, const void *b)
3639 const guint32 *a_values = a;
3640 const guint32 *b_values = b;
3641 int assoc = a_values [MONO_METHOD_SEMA_ASSOCIATION] - b_values [MONO_METHOD_SEMA_ASSOCIATION];
3642 if (assoc)
3643 return assoc;
3644 return a_values [MONO_METHOD_SEMA_SEMANTICS] - b_values [MONO_METHOD_SEMA_SEMANTICS];
3647 static int
3648 compare_custom_attrs (const void *a, const void *b)
3650 const guint32 *a_values = a;
3651 const guint32 *b_values = b;
3653 return a_values [MONO_CUSTOM_ATTR_PARENT] - b_values [MONO_CUSTOM_ATTR_PARENT];
3656 static int
3657 compare_field_marshal (const void *a, const void *b)
3659 const guint32 *a_values = a;
3660 const guint32 *b_values = b;
3662 return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
3665 static int
3666 compare_nested (const void *a, const void *b)
3668 const guint32 *a_values = a;
3669 const guint32 *b_values = b;
3671 return a_values [MONO_NESTED_CLASS_NESTED] - b_values [MONO_NESTED_CLASS_NESTED];
3674 static int
3675 compare_genericparam (const void *a, const void *b)
3677 const GenericParamTableEntry **a_entry = (const GenericParamTableEntry **) a;
3678 const GenericParamTableEntry **b_entry = (const GenericParamTableEntry **) b;
3680 if ((*b_entry)->owner == (*a_entry)->owner)
3681 return
3682 mono_type_get_generic_param_num (mono_reflection_type_get_handle ((MonoReflectionType*)(*a_entry)->gparam)) -
3683 mono_type_get_generic_param_num (mono_reflection_type_get_handle ((MonoReflectionType*)(*b_entry)->gparam));
3684 else
3685 return (*a_entry)->owner - (*b_entry)->owner;
3688 static int
3689 compare_declsecurity_attrs (const void *a, const void *b)
3691 const guint32 *a_values = a;
3692 const guint32 *b_values = b;
3694 return a_values [MONO_DECL_SECURITY_PARENT] - b_values [MONO_DECL_SECURITY_PARENT];
3697 static int
3698 compare_interface_impl (const void *a, const void *b)
3700 const guint32 *a_values = a;
3701 const guint32 *b_values = b;
3703 int klass = a_values [MONO_INTERFACEIMPL_CLASS] - b_values [MONO_INTERFACEIMPL_CLASS];
3704 if (klass)
3705 return klass;
3707 return a_values [MONO_INTERFACEIMPL_INTERFACE] - b_values [MONO_INTERFACEIMPL_INTERFACE];
3710 static void
3711 pad_heap (MonoDynamicStream *sh)
3713 if (sh->index & 3) {
3714 int sz = 4 - (sh->index & 3);
3715 memset (sh->data + sh->index, 0, sz);
3716 sh->index += sz;
3720 struct StreamDesc {
3721 const char *name;
3722 MonoDynamicStream *stream;
3726 * build_compressed_metadata() fills in the blob of data that represents the
3727 * raw metadata as it will be saved in the PE file. The five streams are output
3728 * and the metadata tables are comnpressed from the guint32 array representation,
3729 * to the compressed on-disk format.
3731 static void
3732 build_compressed_metadata (MonoDynamicImage *assembly)
3734 MonoDynamicTable *table;
3735 int i;
3736 guint64 valid_mask = 0;
3737 guint64 sorted_mask;
3738 guint32 heapt_size = 0;
3739 guint32 meta_size = 256; /* allow for header and other stuff */
3740 guint32 table_offset;
3741 guint32 ntables = 0;
3742 guint64 *int64val;
3743 guint32 *int32val;
3744 guint16 *int16val;
3745 MonoImage *meta;
3746 unsigned char *p;
3747 struct StreamDesc stream_desc [5];
3749 qsort (assembly->gen_params->pdata, assembly->gen_params->len, sizeof (gpointer), compare_genericparam);
3750 for (i = 0; i < assembly->gen_params->len; i++){
3751 GenericParamTableEntry *entry = g_ptr_array_index (assembly->gen_params, i);
3752 write_generic_param_entry (assembly, entry);
3755 stream_desc [0].name = "#~";
3756 stream_desc [0].stream = &assembly->tstream;
3757 stream_desc [1].name = "#Strings";
3758 stream_desc [1].stream = &assembly->sheap;
3759 stream_desc [2].name = "#US";
3760 stream_desc [2].stream = &assembly->us;
3761 stream_desc [3].name = "#Blob";
3762 stream_desc [3].stream = &assembly->blob;
3763 stream_desc [4].name = "#GUID";
3764 stream_desc [4].stream = &assembly->guid;
3766 /* tables that are sorted */
3767 sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL)
3768 | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT)
3769 | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA)
3770 | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS)
3771 | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE)
3772 | ((guint64)1 << MONO_TABLE_DECLSECURITY) | ((guint64)1 << MONO_TABLE_GENERICPARAM)
3773 | ((guint64)1 << MONO_TABLE_INTERFACEIMPL);
3775 /* Compute table sizes */
3776 /* the MonoImage has already been created in mono_image_basic_init() */
3777 meta = &assembly->image;
3779 /* sizes should be multiple of 4 */
3780 pad_heap (&assembly->blob);
3781 pad_heap (&assembly->guid);
3782 pad_heap (&assembly->sheap);
3783 pad_heap (&assembly->us);
3785 /* Setup the info used by compute_sizes () */
3786 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
3787 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
3788 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
3790 meta_size += assembly->blob.index;
3791 meta_size += assembly->guid.index;
3792 meta_size += assembly->sheap.index;
3793 meta_size += assembly->us.index;
3795 for (i=0; i < MONO_TABLE_NUM; ++i)
3796 meta->tables [i].rows = assembly->tables [i].rows;
3798 for (i = 0; i < MONO_TABLE_NUM; i++){
3799 if (meta->tables [i].rows == 0)
3800 continue;
3801 valid_mask |= (guint64)1 << i;
3802 ntables ++;
3803 meta->tables [i].row_size = mono_metadata_compute_size (
3804 meta, i, &meta->tables [i].size_bitfield);
3805 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
3807 heapt_size += 24; /* #~ header size */
3808 heapt_size += ntables * 4;
3809 /* make multiple of 4 */
3810 heapt_size += 3;
3811 heapt_size &= ~3;
3812 meta_size += heapt_size;
3813 meta->raw_metadata = g_malloc0 (meta_size);
3814 p = (unsigned char*)meta->raw_metadata;
3815 /* the metadata signature */
3816 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
3817 /* version numbers and 4 bytes reserved */
3818 int16val = (guint16*)p;
3819 *int16val++ = GUINT16_TO_LE (meta->md_version_major);
3820 *int16val = GUINT16_TO_LE (meta->md_version_minor);
3821 p += 8;
3822 /* version string */
3823 int32val = (guint32*)p;
3824 *int32val = GUINT32_TO_LE ((strlen (meta->version) + 3) & (~3)); /* needs to be multiple of 4 */
3825 p += 4;
3826 memcpy (p, meta->version, strlen (meta->version));
3827 p += GUINT32_FROM_LE (*int32val);
3828 align_pointer (meta->raw_metadata, p);
3829 int16val = (guint16*)p;
3830 *int16val++ = GUINT16_TO_LE (0); /* flags must be 0 */
3831 *int16val = GUINT16_TO_LE (5); /* number of streams */
3832 p += 4;
3835 * write the stream info.
3837 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
3838 table_offset += 3; table_offset &= ~3;
3840 assembly->tstream.index = heapt_size;
3841 for (i = 0; i < 5; ++i) {
3842 int32val = (guint32*)p;
3843 stream_desc [i].stream->offset = table_offset;
3844 *int32val++ = GUINT32_TO_LE (table_offset);
3845 *int32val = GUINT32_TO_LE (stream_desc [i].stream->index);
3846 table_offset += GUINT32_FROM_LE (*int32val);
3847 table_offset += 3; table_offset &= ~3;
3848 p += 8;
3849 strcpy ((char*)p, stream_desc [i].name);
3850 p += strlen (stream_desc [i].name) + 1;
3851 align_pointer (meta->raw_metadata, p);
3854 * now copy the data, the table stream header and contents goes first.
3856 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
3857 p = (guchar*)meta->raw_metadata + assembly->tstream.offset;
3858 int32val = (guint32*)p;
3859 *int32val = GUINT32_TO_LE (0); /* reserved */
3860 p += 4;
3862 if (mono_framework_version () > 1) {
3863 *p++ = 2; /* version */
3864 *p++ = 0;
3865 } else {
3866 *p++ = 1; /* version */
3867 *p++ = 0;
3870 if (meta->idx_string_wide)
3871 *p |= 0x01;
3872 if (meta->idx_guid_wide)
3873 *p |= 0x02;
3874 if (meta->idx_blob_wide)
3875 *p |= 0x04;
3876 ++p;
3877 *p++ = 1; /* reserved */
3878 int64val = (guint64*)p;
3879 *int64val++ = GUINT64_TO_LE (valid_mask);
3880 *int64val++ = GUINT64_TO_LE (valid_mask & sorted_mask); /* bitvector of sorted tables */
3881 p += 16;
3882 int32val = (guint32*)p;
3883 for (i = 0; i < MONO_TABLE_NUM; i++){
3884 if (meta->tables [i].rows == 0)
3885 continue;
3886 *int32val++ = GUINT32_TO_LE (meta->tables [i].rows);
3888 p = (unsigned char*)int32val;
3890 /* sort the tables that still need sorting */
3891 table = &assembly->tables [MONO_TABLE_CONSTANT];
3892 if (table->rows)
3893 qsort (table->values + MONO_CONSTANT_SIZE, table->rows, sizeof (guint32) * MONO_CONSTANT_SIZE, compare_constants);
3894 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
3895 if (table->rows)
3896 qsort (table->values + MONO_METHOD_SEMA_SIZE, table->rows, sizeof (guint32) * MONO_METHOD_SEMA_SIZE, compare_semantics);
3897 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
3898 if (table->rows)
3899 qsort (table->values + MONO_CUSTOM_ATTR_SIZE, table->rows, sizeof (guint32) * MONO_CUSTOM_ATTR_SIZE, compare_custom_attrs);
3900 table = &assembly->tables [MONO_TABLE_FIELDMARSHAL];
3901 if (table->rows)
3902 qsort (table->values + MONO_FIELD_MARSHAL_SIZE, table->rows, sizeof (guint32) * MONO_FIELD_MARSHAL_SIZE, compare_field_marshal);
3903 table = &assembly->tables [MONO_TABLE_NESTEDCLASS];
3904 if (table->rows)
3905 qsort (table->values + MONO_NESTED_CLASS_SIZE, table->rows, sizeof (guint32) * MONO_NESTED_CLASS_SIZE, compare_nested);
3906 /* Section 21.11 DeclSecurity in Partition II doesn't specify this to be sorted by MS implementation requires it */
3907 table = &assembly->tables [MONO_TABLE_DECLSECURITY];
3908 if (table->rows)
3909 qsort (table->values + MONO_DECL_SECURITY_SIZE, table->rows, sizeof (guint32) * MONO_DECL_SECURITY_SIZE, compare_declsecurity_attrs);
3910 table = &assembly->tables [MONO_TABLE_INTERFACEIMPL];
3911 if (table->rows)
3912 qsort (table->values + MONO_INTERFACEIMPL_SIZE, table->rows, sizeof (guint32) * MONO_INTERFACEIMPL_SIZE, compare_interface_impl);
3914 /* compress the tables */
3915 for (i = 0; i < MONO_TABLE_NUM; i++){
3916 int row, col;
3917 guint32 *values;
3918 guint32 bitfield = meta->tables [i].size_bitfield;
3919 if (!meta->tables [i].rows)
3920 continue;
3921 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
3922 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
3923 meta->tables [i].base = (char*)p;
3924 for (row = 1; row <= meta->tables [i].rows; ++row) {
3925 values = assembly->tables [i].values + row * assembly->tables [i].columns;
3926 for (col = 0; col < assembly->tables [i].columns; ++col) {
3927 switch (mono_metadata_table_size (bitfield, col)) {
3928 case 1:
3929 *p++ = values [col];
3930 break;
3931 case 2:
3932 *p++ = values [col] & 0xff;
3933 *p++ = (values [col] >> 8) & 0xff;
3934 break;
3935 case 4:
3936 *p++ = values [col] & 0xff;
3937 *p++ = (values [col] >> 8) & 0xff;
3938 *p++ = (values [col] >> 16) & 0xff;
3939 *p++ = (values [col] >> 24) & 0xff;
3940 break;
3941 default:
3942 g_assert_not_reached ();
3946 g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
3949 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
3950 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
3951 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
3952 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
3953 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
3955 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
3959 * Some tables in metadata need to be sorted according to some criteria, but
3960 * when methods and fields are first created with reflection, they may be assigned a token
3961 * that doesn't correspond to the final token they will get assigned after the sorting.
3962 * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream
3963 * with the reflection objects that represent them. Once all the tables are set up, the
3964 * reflection objects will contains the correct table index. fixup_method() will fixup the
3965 * tokens for the method with ILGenerator @ilgen.
3967 static void
3968 fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *assembly)
3970 guint32 code_idx = GPOINTER_TO_UINT (value);
3971 MonoReflectionILTokenInfo *iltoken;
3972 MonoReflectionFieldBuilder *field;
3973 MonoReflectionCtorBuilder *ctor;
3974 MonoReflectionMethodBuilder *method;
3975 MonoReflectionTypeBuilder *tb;
3976 MonoReflectionArrayMethod *am;
3977 guint32 i, idx = 0;
3978 unsigned char *target;
3980 for (i = 0; i < ilgen->num_token_fixups; ++i) {
3981 iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i);
3982 target = (guchar*)assembly->code.data + code_idx + iltoken->code_pos;
3983 switch (target [3]) {
3984 case MONO_TABLE_FIELD:
3985 if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
3986 field = (MonoReflectionFieldBuilder *)iltoken->member;
3987 idx = field->table_idx;
3988 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
3989 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
3990 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
3991 } else {
3992 g_assert_not_reached ();
3994 break;
3995 case MONO_TABLE_METHOD:
3996 if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
3997 method = (MonoReflectionMethodBuilder *)iltoken->member;
3998 idx = method->table_idx;
3999 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
4000 ctor = (MonoReflectionCtorBuilder *)iltoken->member;
4001 idx = ctor->table_idx;
4002 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
4003 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
4004 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
4005 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
4006 } else {
4007 g_assert_not_reached ();
4009 break;
4010 case MONO_TABLE_TYPEDEF:
4011 if (strcmp (iltoken->member->vtable->klass->name, "TypeBuilder"))
4012 g_assert_not_reached ();
4013 tb = (MonoReflectionTypeBuilder *)iltoken->member;
4014 idx = tb->table_idx;
4015 break;
4016 case MONO_TABLE_MEMBERREF:
4017 if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
4018 am = (MonoReflectionArrayMethod*)iltoken->member;
4019 idx = am->table_idx;
4020 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
4021 !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod") ||
4022 !strcmp (iltoken->member->vtable->klass->name, "MonoGenericMethod") ||
4023 !strcmp (iltoken->member->vtable->klass->name, "MonoGenericCMethod")) {
4024 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
4025 g_assert (m->klass->generic_class || m->klass->generic_container);
4026 continue;
4027 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
4028 continue;
4029 } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
4030 MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
4031 g_assert (is_field_on_inst (f));
4032 continue;
4033 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
4034 !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
4035 continue;
4036 } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
4037 continue;
4038 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
4039 continue;
4040 } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
4041 continue;
4042 } else {
4043 g_assert_not_reached ();
4045 break;
4046 case MONO_TABLE_METHODSPEC:
4047 if (!strcmp (iltoken->member->vtable->klass->name, "MonoGenericMethod")) {
4048 MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
4049 g_assert (mono_method_signature (m)->generic_param_count);
4050 continue;
4051 } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
4052 continue;
4053 } else {
4054 g_assert_not_reached ();
4056 break;
4057 default:
4058 g_error ("got unexpected table 0x%02x in fixup", target [3]);
4060 target [0] = idx & 0xff;
4061 target [1] = (idx >> 8) & 0xff;
4062 target [2] = (idx >> 16) & 0xff;
4067 * fixup_cattrs:
4069 * The CUSTOM_ATTRIBUTE table might contain METHODDEF tokens whose final
4070 * value is not known when the table is emitted.
4072 static void
4073 fixup_cattrs (MonoDynamicImage *assembly)
4075 MonoDynamicTable *table;
4076 guint32 *values;
4077 guint32 type, i, idx, token;
4078 MonoObject *ctor;
4080 table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE];
4082 for (i = 0; i < table->rows; ++i) {
4083 values = table->values + ((i + 1) * MONO_CUSTOM_ATTR_SIZE);
4085 type = values [MONO_CUSTOM_ATTR_TYPE];
4086 if ((type & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
4087 idx = type >> MONO_CUSTOM_ATTR_TYPE_BITS;
4088 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
4089 ctor = mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
4090 g_assert (ctor);
4092 if (!strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
4093 MonoMethod *m = ((MonoReflectionMethod*)ctor)->method;
4094 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, m));
4095 values [MONO_CUSTOM_ATTR_TYPE] = (idx << MONO_CUSTOM_ATTR_TYPE_BITS) | MONO_CUSTOM_ATTR_TYPE_METHODDEF;
4101 static void
4102 assembly_add_resource_manifest (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc, guint32 implementation)
4104 MonoDynamicTable *table;
4105 guint32 *values;
4107 table = &assembly->tables [MONO_TABLE_MANIFESTRESOURCE];
4108 table->rows++;
4109 alloc_table (table, table->rows);
4110 values = table->values + table->next_idx * MONO_MANIFEST_SIZE;
4111 values [MONO_MANIFEST_OFFSET] = rsrc->offset;
4112 values [MONO_MANIFEST_FLAGS] = rsrc->attrs;
4113 values [MONO_MANIFEST_NAME] = string_heap_insert_mstring (&assembly->sheap, rsrc->name);
4114 values [MONO_MANIFEST_IMPLEMENTATION] = implementation;
4115 table->next_idx++;
4118 static void
4119 assembly_add_resource (MonoReflectionModuleBuilder *mb, MonoDynamicImage *assembly, MonoReflectionResource *rsrc)
4121 MonoDynamicTable *table;
4122 guint32 *values;
4123 char blob_size [6];
4124 guchar hash [20];
4125 char *b = blob_size;
4126 char *name, *sname;
4127 guint32 idx, offset;
4129 if (rsrc->filename) {
4130 name = mono_string_to_utf8 (rsrc->filename);
4131 sname = g_path_get_basename (name);
4133 table = &assembly->tables [MONO_TABLE_FILE];
4134 table->rows++;
4135 alloc_table (table, table->rows);
4136 values = table->values + table->next_idx * MONO_FILE_SIZE;
4137 values [MONO_FILE_FLAGS] = FILE_CONTAINS_NO_METADATA;
4138 values [MONO_FILE_NAME] = string_heap_insert (&assembly->sheap, sname);
4139 g_free (sname);
4141 mono_sha1_get_digest_from_file (name, hash);
4142 mono_metadata_encode_value (20, b, &b);
4143 values [MONO_FILE_HASH_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
4144 mono_image_add_stream_data (&assembly->blob, (char*)hash, 20);
4145 g_free (name);
4146 idx = table->next_idx++;
4147 rsrc->offset = 0;
4148 idx = MONO_IMPLEMENTATION_FILE | (idx << MONO_IMPLEMENTATION_BITS);
4149 } else {
4150 char sizebuf [4];
4151 char *data;
4152 guint len;
4153 if (rsrc->data) {
4154 data = mono_array_addr (rsrc->data, char, 0);
4155 len = mono_array_length (rsrc->data);
4156 } else {
4157 data = NULL;
4158 len = 0;
4160 offset = len;
4161 sizebuf [0] = offset; sizebuf [1] = offset >> 8;
4162 sizebuf [2] = offset >> 16; sizebuf [3] = offset >> 24;
4163 rsrc->offset = mono_image_add_stream_data (&assembly->resources, sizebuf, 4);
4164 mono_image_add_stream_data (&assembly->resources, data, len);
4166 if (!mb->is_main)
4168 * The entry should be emitted into the MANIFESTRESOURCE table of
4169 * the main module, but that needs to reference the FILE table
4170 * which isn't emitted yet.
4172 return;
4173 else
4174 idx = 0;
4177 assembly_add_resource_manifest (mb, assembly, rsrc, idx);
4180 static void
4181 set_version_from_string (MonoString *version, guint32 *values)
4183 gchar *ver, *p, *str;
4184 guint32 i;
4186 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
4187 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
4188 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
4189 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
4190 if (!version)
4191 return;
4192 ver = str = mono_string_to_utf8 (version);
4193 for (i = 0; i < 4; ++i) {
4194 values [MONO_ASSEMBLY_MAJOR_VERSION + i] = strtol (ver, &p, 10);
4195 switch (*p) {
4196 case '.':
4197 p++;
4198 break;
4199 case '*':
4200 /* handle Revision and Build */
4201 p++;
4202 break;
4204 ver = p;
4206 g_free (str);
4209 static guint32
4210 load_public_key (MonoArray *pkey, MonoDynamicImage *assembly) {
4211 gsize len;
4212 guint32 token = 0;
4213 char blob_size [6];
4214 char *b = blob_size;
4216 if (!pkey)
4217 return token;
4219 len = mono_array_length (pkey);
4220 mono_metadata_encode_value (len, b, &b);
4221 token = mono_image_add_stream_data (&assembly->blob, blob_size, b - blob_size);
4222 mono_image_add_stream_data (&assembly->blob, mono_array_addr (pkey, char, 0), len);
4224 assembly->public_key = g_malloc (len);
4225 memcpy (assembly->public_key, mono_array_addr (pkey, char, 0), len);
4226 assembly->public_key_len = len;
4228 /* Special case: check for ECMA key (16 bytes) */
4229 if ((len == MONO_ECMA_KEY_LENGTH) && mono_is_ecma_key (mono_array_addr (pkey, char, 0), len)) {
4230 /* In this case we must reserve 128 bytes (1024 bits) for the signature */
4231 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH;
4232 } else if (len >= MONO_PUBLIC_KEY_HEADER_LENGTH + MONO_MINIMUM_PUBLIC_KEY_LENGTH) {
4233 /* minimum key size (in 2.0) is 384 bits */
4234 assembly->strong_name_size = len - MONO_PUBLIC_KEY_HEADER_LENGTH;
4235 } else {
4236 /* FIXME - verifier */
4237 g_warning ("Invalid public key length: %d bits (total: %d)", (int)MONO_PUBLIC_KEY_BIT_SIZE (len), (int)len);
4238 assembly->strong_name_size = MONO_DEFAULT_PUBLIC_KEY_LENGTH; /* to be safe */
4240 assembly->strong_name = g_malloc0 (assembly->strong_name_size);
4242 return token;
4245 static void
4246 mono_image_emit_manifest (MonoReflectionModuleBuilder *moduleb)
4248 MonoDynamicTable *table;
4249 MonoDynamicImage *assembly;
4250 MonoReflectionAssemblyBuilder *assemblyb;
4251 MonoDomain *domain;
4252 guint32 *values;
4253 int i;
4254 guint32 module_index;
4256 assemblyb = moduleb->assemblyb;
4257 assembly = moduleb->dynamic_image;
4258 domain = mono_object_domain (assemblyb);
4260 /* Emit ASSEMBLY table */
4261 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
4262 alloc_table (table, 1);
4263 values = table->values + MONO_ASSEMBLY_SIZE;
4264 values [MONO_ASSEMBLY_HASH_ALG] = assemblyb->algid? assemblyb->algid: ASSEMBLY_HASH_SHA1;
4265 values [MONO_ASSEMBLY_NAME] = string_heap_insert_mstring (&assembly->sheap, assemblyb->name);
4266 if (assemblyb->culture) {
4267 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert_mstring (&assembly->sheap, assemblyb->culture);
4268 } else {
4269 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
4271 values [MONO_ASSEMBLY_PUBLIC_KEY] = load_public_key (assemblyb->public_key, assembly);
4272 values [MONO_ASSEMBLY_FLAGS] = assemblyb->flags;
4273 set_version_from_string (assemblyb->version, values);
4275 /* Emit FILE + EXPORTED_TYPE table */
4276 module_index = 0;
4277 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
4278 int j;
4279 MonoReflectionModuleBuilder *file_module =
4280 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
4281 if (file_module != moduleb) {
4282 mono_image_fill_file_table (domain, (MonoReflectionModule*)file_module, assembly);
4283 module_index ++;
4284 if (file_module->types) {
4285 for (j = 0; j < file_module->num_types; ++j) {
4286 MonoReflectionTypeBuilder *tb = mono_array_get (file_module->types, MonoReflectionTypeBuilder*, j);
4287 mono_image_fill_export_table (domain, tb, module_index, 0, assembly);
4292 if (assemblyb->loaded_modules) {
4293 for (i = 0; i < mono_array_length (assemblyb->loaded_modules); ++i) {
4294 MonoReflectionModule *file_module =
4295 mono_array_get (assemblyb->loaded_modules, MonoReflectionModule*, i);
4296 mono_image_fill_file_table (domain, file_module, assembly);
4297 module_index ++;
4298 mono_image_fill_export_table_from_module (domain, file_module, module_index, assembly);
4301 if (assemblyb->type_forwarders)
4302 mono_image_fill_export_table_from_type_forwarders (assemblyb, assembly);
4304 /* Emit MANIFESTRESOURCE table */
4305 module_index = 0;
4306 for (i = 0; i < mono_array_length (assemblyb->modules); ++i) {
4307 int j;
4308 MonoReflectionModuleBuilder *file_module =
4309 mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i);
4310 /* The table for the main module is emitted later */
4311 if (file_module != moduleb) {
4312 module_index ++;
4313 if (file_module->resources) {
4314 int len = mono_array_length (file_module->resources);
4315 for (j = 0; j < len; ++j) {
4316 MonoReflectionResource* res = (MonoReflectionResource*)mono_array_addr (file_module->resources, MonoReflectionResource, j);
4317 assembly_add_resource_manifest (file_module, assembly, res, MONO_IMPLEMENTATION_FILE | (module_index << MONO_IMPLEMENTATION_BITS));
4324 #ifndef DISABLE_REFLECTION_EMIT_SAVE
4327 * mono_image_build_metadata() will fill the info in all the needed metadata tables
4328 * for the modulebuilder @moduleb.
4329 * At the end of the process, method and field tokens are fixed up and the
4330 * on-disk compressed metadata representation is created.
4332 void
4333 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb)
4335 MonoDynamicTable *table;
4336 MonoDynamicImage *assembly;
4337 MonoReflectionAssemblyBuilder *assemblyb;
4338 MonoDomain *domain;
4339 GPtrArray *types;
4340 guint32 *values;
4341 int i, j;
4343 assemblyb = moduleb->assemblyb;
4344 assembly = moduleb->dynamic_image;
4345 domain = mono_object_domain (assemblyb);
4347 if (assembly->text_rva)
4348 return;
4350 assembly->text_rva = START_TEXT_RVA;
4352 if (moduleb->is_main) {
4353 mono_image_emit_manifest (moduleb);
4356 table = &assembly->tables [MONO_TABLE_TYPEDEF];
4357 table->rows = 1; /* .<Module> */
4358 table->next_idx++;
4359 alloc_table (table, table->rows);
4361 * Set the first entry.
4363 values = table->values + table->columns;
4364 values [MONO_TYPEDEF_FLAGS] = 0;
4365 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
4366 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
4367 values [MONO_TYPEDEF_EXTENDS] = 0;
4368 values [MONO_TYPEDEF_FIELD_LIST] = 1;
4369 values [MONO_TYPEDEF_METHOD_LIST] = 1;
4372 * handle global methods
4373 * FIXME: test what to do when global methods are defined in multiple modules.
4375 if (moduleb->global_methods) {
4376 table = &assembly->tables [MONO_TABLE_METHOD];
4377 table->rows += mono_array_length (moduleb->global_methods);
4378 alloc_table (table, table->rows);
4379 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i)
4380 mono_image_get_method_info (
4381 mono_array_get (moduleb->global_methods, MonoReflectionMethodBuilder*, i), assembly);
4383 if (moduleb->global_fields) {
4384 table = &assembly->tables [MONO_TABLE_FIELD];
4385 table->rows += mono_array_length (moduleb->global_fields);
4386 alloc_table (table, table->rows);
4387 for (i = 0; i < mono_array_length (moduleb->global_fields); ++i)
4388 mono_image_get_field_info (
4389 mono_array_get (moduleb->global_fields, MonoReflectionFieldBuilder*, i), assembly);
4392 table = &assembly->tables [MONO_TABLE_MODULE];
4393 alloc_table (table, 1);
4394 mono_image_fill_module_table (domain, moduleb, assembly);
4396 /* Collect all types into a list sorted by their table_idx */
4397 types = g_ptr_array_new ();
4399 if (moduleb->types)
4400 for (i = 0; i < moduleb->num_types; ++i) {
4401 MonoReflectionTypeBuilder *type = mono_array_get (moduleb->types, MonoReflectionTypeBuilder*, i);
4402 collect_types (types, type);
4405 g_ptr_array_sort (types, (GCompareFunc)compare_types_by_table_idx);
4406 table = &assembly->tables [MONO_TABLE_TYPEDEF];
4407 table->rows += types->len;
4408 alloc_table (table, table->rows);
4411 * Emit type names + namespaces at one place inside the string heap,
4412 * so load_class_names () needs to touch fewer pages.
4414 for (i = 0; i < types->len; ++i) {
4415 MonoReflectionTypeBuilder *tb = g_ptr_array_index (types, i);
4416 string_heap_insert_mstring (&assembly->sheap, tb->nspace);
4418 for (i = 0; i < types->len; ++i) {
4419 MonoReflectionTypeBuilder *tb = g_ptr_array_index (types, i);
4420 string_heap_insert_mstring (&assembly->sheap, tb->name);
4423 for (i = 0; i < types->len; ++i) {
4424 MonoReflectionTypeBuilder *type = g_ptr_array_index (types, i);
4425 mono_image_get_type_info (domain, type, assembly);
4429 * table->rows is already set above and in mono_image_fill_module_table.
4431 /* add all the custom attributes at the end, once all the indexes are stable */
4432 mono_image_add_cattrs (assembly, 1, MONO_CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs);
4434 /* CAS assembly permissions */
4435 if (assemblyb->permissions_minimum)
4436 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_minimum);
4437 if (assemblyb->permissions_optional)
4438 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_optional);
4439 if (assemblyb->permissions_refused)
4440 mono_image_add_decl_security (assembly, mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1), assemblyb->permissions_refused);
4442 module_add_cattrs (assembly, moduleb);
4444 /* fixup tokens */
4445 mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly);
4447 /* Create the MethodImpl table. We do this after emitting all methods so we already know
4448 * the final tokens and don't need another fixup pass. */
4450 if (moduleb->global_methods) {
4451 for (i = 0; i < mono_array_length (moduleb->global_methods); ++i) {
4452 MonoReflectionMethodBuilder *mb = mono_array_get (
4453 moduleb->global_methods, MonoReflectionMethodBuilder*, i);
4454 mono_image_add_methodimpl (assembly, mb);
4458 for (i = 0; i < types->len; ++i) {
4459 MonoReflectionTypeBuilder *type = g_ptr_array_index (types, i);
4460 if (type->methods) {
4461 for (j = 0; j < type->num_methods; ++j) {
4462 MonoReflectionMethodBuilder *mb = mono_array_get (
4463 type->methods, MonoReflectionMethodBuilder*, j);
4465 mono_image_add_methodimpl (assembly, mb);
4470 g_ptr_array_free (types, TRUE);
4472 fixup_cattrs (assembly);
4475 #else /* DISABLE_REFLECTION_EMIT_SAVE */
4477 void
4478 mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb)
4480 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit_save, so saving of dynamic assemblies is not supported.");
4483 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
4486 typedef struct {
4487 guint32 import_lookup_table;
4488 guint32 timestamp;
4489 guint32 forwarder;
4490 guint32 name_rva;
4491 guint32 import_address_table_rva;
4492 } MonoIDT;
4494 typedef struct {
4495 guint32 name_rva;
4496 guint32 flags;
4497 } MonoILT;
4499 #ifndef DISABLE_REFLECTION_EMIT
4502 * mono_image_insert_string:
4503 * @module: module builder object
4504 * @str: a string
4506 * Insert @str into the user string stream of @module.
4508 guint32
4509 mono_image_insert_string (MonoReflectionModuleBuilder *module, MonoString *str)
4511 MonoDynamicImage *assembly;
4512 guint32 idx;
4513 char buf [16];
4514 char *b = buf;
4516 MONO_ARCH_SAVE_REGS;
4518 if (!module->dynamic_image)
4519 mono_image_module_basic_init (module);
4521 assembly = module->dynamic_image;
4523 if (assembly->save) {
4524 mono_metadata_encode_value (1 | (str->length * 2), b, &b);
4525 idx = mono_image_add_stream_data (&assembly->us, buf, b-buf);
4526 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4528 char *swapped = g_malloc (2 * mono_string_length (str));
4529 const char *p = (const char*)mono_string_chars (str);
4531 swap_with_size (swapped, p, 2, mono_string_length (str));
4532 mono_image_add_stream_data (&assembly->us, swapped, str->length * 2);
4533 g_free (swapped);
4535 #else
4536 mono_image_add_stream_data (&assembly->us, (const char*)mono_string_chars (str), str->length * 2);
4537 #endif
4538 mono_image_add_stream_data (&assembly->us, "", 1);
4539 } else {
4540 idx = assembly->us.index ++;
4543 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (MONO_TOKEN_STRING | idx), str);
4545 return MONO_TOKEN_STRING | idx;
4548 guint32
4549 mono_image_create_method_token (MonoDynamicImage *assembly, MonoObject *obj, MonoArray *opt_param_types)
4551 MonoClass *klass;
4552 guint32 token = 0;
4554 klass = obj->vtable->klass;
4555 if (strcmp (klass->name, "MonoMethod") == 0) {
4556 MonoMethod *method = ((MonoReflectionMethod *)obj)->method;
4557 MonoMethodSignature *sig, *old;
4558 guint32 sig_token, parent;
4559 int nargs, i;
4561 g_assert (opt_param_types && (mono_method_signature (method)->sentinelpos >= 0));
4563 nargs = mono_array_length (opt_param_types);
4564 old = mono_method_signature (method);
4565 sig = mono_metadata_signature_alloc ( &assembly->image, old->param_count + nargs);
4567 sig->hasthis = old->hasthis;
4568 sig->explicit_this = old->explicit_this;
4569 sig->call_convention = old->call_convention;
4570 sig->generic_param_count = old->generic_param_count;
4571 sig->param_count = old->param_count + nargs;
4572 sig->sentinelpos = old->param_count;
4573 sig->ret = old->ret;
4575 for (i = 0; i < old->param_count; i++)
4576 sig->params [i] = old->params [i];
4578 for (i = 0; i < nargs; i++) {
4579 MonoReflectionType *rt = mono_array_get (opt_param_types, MonoReflectionType *, i);
4580 sig->params [old->param_count + i] = mono_reflection_type_get_handle (rt);
4583 parent = mono_image_typedef_or_ref (assembly, &method->klass->byval_arg);
4584 g_assert ((parent & MONO_TYPEDEFORREF_MASK) == MONO_MEMBERREF_PARENT_TYPEREF);
4585 parent >>= MONO_TYPEDEFORREF_BITS;
4587 parent <<= MONO_MEMBERREF_PARENT_BITS;
4588 parent |= MONO_MEMBERREF_PARENT_TYPEREF;
4590 sig_token = method_encode_signature (assembly, sig);
4591 token = mono_image_get_varargs_method_token (assembly, parent, method->name, sig_token);
4592 } else if (strcmp (klass->name, "MethodBuilder") == 0) {
4593 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
4594 ReflectionMethodBuilder rmb;
4595 guint32 parent, sig;
4596 char *name;
4598 reflection_methodbuilder_from_method_builder (&rmb, mb);
4599 rmb.opt_types = opt_param_types;
4601 sig = method_builder_encode_signature (assembly, &rmb);
4603 parent = mono_image_create_token (assembly, obj, TRUE, TRUE);
4604 g_assert (mono_metadata_token_table (parent) == MONO_TABLE_METHOD);
4606 parent = mono_metadata_token_index (parent) << MONO_MEMBERREF_PARENT_BITS;
4607 parent |= MONO_MEMBERREF_PARENT_METHODDEF;
4609 name = mono_string_to_utf8 (rmb.name);
4610 token = mono_image_get_varargs_method_token (
4611 assembly, parent, name, sig);
4612 g_free (name);
4613 } else {
4614 g_error ("requested method token for %s\n", klass->name);
4617 return token;
4621 * mono_image_create_token:
4622 * @assembly: a dynamic assembly
4623 * @obj:
4624 * @register_token: Whenever to register the token in the assembly->tokens hash.
4626 * Get a token to insert in the IL code stream for the given MemberInfo.
4627 * The metadata emission routines need to pass FALSE as REGISTER_TOKEN, since by that time,
4628 * the table_idx-es were recomputed, so registering the token would overwrite an existing
4629 * entry.
4631 guint32
4632 mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
4633 gboolean create_methodspec, gboolean register_token)
4635 MonoClass *klass;
4636 guint32 token = 0;
4638 klass = obj->vtable->klass;
4640 /* Check for user defined reflection objects */
4641 /* TypeDelegator is the only corlib type which doesn't look like a MonoReflectionType */
4642 if (klass->image != mono_defaults.corlib || (strcmp (klass->name, "TypeDelegator") == 0))
4643 mono_raise_exception (mono_get_exception_not_supported ("User defined subclasses of System.Type are not yet supported")); \
4645 if (strcmp (klass->name, "MethodBuilder") == 0) {
4646 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
4647 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
4649 if (tb->module->dynamic_image == assembly && !tb->generic_params && !mb->generic_params)
4650 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
4651 else
4652 token = mono_image_get_methodbuilder_token (assembly, mb, create_methodspec);
4653 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
4654 } else if (strcmp (klass->name, "ConstructorBuilder") == 0) {
4655 MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
4656 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
4658 if (tb->module->dynamic_image == assembly && !tb->generic_params)
4659 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
4660 else
4661 token = mono_image_get_ctorbuilder_token (assembly, mb);
4662 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
4663 } else if (strcmp (klass->name, "FieldBuilder") == 0) {
4664 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)obj;
4665 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)fb->typeb;
4666 if (tb->generic_params) {
4667 token = mono_image_get_generic_field_token (assembly, fb);
4668 } else {
4669 token = fb->table_idx | MONO_TOKEN_FIELD_DEF;
4671 } else if (strcmp (klass->name, "TypeBuilder") == 0) {
4672 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
4673 token = tb->table_idx | MONO_TOKEN_TYPE_DEF;
4674 } else if (strcmp (klass->name, "MonoType") == 0) {
4675 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
4676 MonoClass *mc = mono_class_from_mono_type (type);
4677 token = mono_metadata_token_from_dor (
4678 mono_image_typedef_or_ref_full (assembly, type, mc->generic_container == NULL));
4679 } else if (strcmp (klass->name, "GenericTypeParameterBuilder") == 0) {
4680 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
4681 token = mono_metadata_token_from_dor (
4682 mono_image_typedef_or_ref (assembly, type));
4683 } else if (strcmp (klass->name, "MonoGenericClass") == 0) {
4684 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
4685 token = mono_metadata_token_from_dor (
4686 mono_image_typedef_or_ref (assembly, type));
4687 } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
4688 strcmp (klass->name, "MonoMethod") == 0 ||
4689 strcmp (klass->name, "MonoGenericMethod") == 0 ||
4690 strcmp (klass->name, "MonoGenericCMethod") == 0) {
4691 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
4692 if (m->method->is_inflated) {
4693 if (create_methodspec)
4694 token = mono_image_get_methodspec_token (assembly, m->method);
4695 else
4696 token = mono_image_get_inflated_method_token (assembly, m->method);
4697 } else if ((m->method->klass->image == &assembly->image) &&
4698 !m->method->klass->generic_class) {
4699 static guint32 method_table_idx = 0xffffff;
4700 if (m->method->klass->wastypebuilder) {
4701 /* we use the same token as the one that was assigned
4702 * to the Methodbuilder.
4703 * FIXME: do the equivalent for Fields.
4705 token = m->method->token;
4706 } else {
4708 * Each token should have a unique index, but the indexes are
4709 * assigned by managed code, so we don't know about them. An
4710 * easy solution is to count backwards...
4712 method_table_idx --;
4713 token = MONO_TOKEN_METHOD_DEF | method_table_idx;
4715 } else {
4716 token = mono_image_get_methodref_token (assembly, m->method, create_methodspec);
4718 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
4719 } else if (strcmp (klass->name, "MonoField") == 0) {
4720 MonoReflectionField *f = (MonoReflectionField *)obj;
4721 if ((f->field->parent->image == &assembly->image) && !is_field_on_inst (f->field)) {
4722 static guint32 field_table_idx = 0xffffff;
4723 field_table_idx --;
4724 token = MONO_TOKEN_FIELD_DEF | field_table_idx;
4725 } else {
4726 token = mono_image_get_fieldref_token (assembly, f);
4728 /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/
4729 } else if (strcmp (klass->name, "MonoArrayMethod") == 0) {
4730 MonoReflectionArrayMethod *m = (MonoReflectionArrayMethod *)obj;
4731 token = mono_image_get_array_token (assembly, m);
4732 } else if (strcmp (klass->name, "SignatureHelper") == 0) {
4733 MonoReflectionSigHelper *s = (MonoReflectionSigHelper*)obj;
4734 token = MONO_TOKEN_SIGNATURE | mono_image_get_sighelper_token (assembly, s);
4735 } else if (strcmp (klass->name, "EnumBuilder") == 0) {
4736 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
4737 token = mono_metadata_token_from_dor (
4738 mono_image_typedef_or_ref (assembly, type));
4739 } else if (strcmp (klass->name, "FieldOnTypeBuilderInst") == 0) {
4740 MonoReflectionFieldOnTypeBuilderInst *f = (MonoReflectionFieldOnTypeBuilderInst*)obj;
4741 token = mono_image_get_field_on_inst_token (assembly, f);
4742 } else if (strcmp (klass->name, "ConstructorOnTypeBuilderInst") == 0) {
4743 MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
4744 token = mono_image_get_ctor_on_inst_token (assembly, c, create_methodspec);
4745 } else if (strcmp (klass->name, "MethodOnTypeBuilderInst") == 0) {
4746 MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
4747 token = mono_image_get_method_on_inst_token (assembly, m, create_methodspec);
4748 } else if (is_sre_array (klass) || is_sre_byref (klass) || is_sre_pointer (klass)) {
4749 MonoReflectionType *type = (MonoReflectionType *)obj;
4750 token = mono_metadata_token_from_dor (
4751 mono_image_typedef_or_ref (assembly, mono_reflection_type_get_handle (type)));
4752 } else {
4753 g_error ("requested token for %s\n", klass->name);
4756 if (register_token)
4757 mono_image_register_token (assembly, token, obj);
4759 return token;
4763 * mono_image_register_token:
4765 * Register the TOKEN->OBJ mapping in the mapping table in ASSEMBLY. This is required for
4766 * the Module.ResolveXXXToken () methods to work.
4768 void
4769 mono_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObject *obj)
4771 MonoObject *prev = mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
4772 if (prev) {
4773 /* There could be multiple MethodInfo objects with the same token */
4774 //g_assert (prev == obj);
4775 } else {
4776 mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), obj);
4780 static MonoDynamicImage*
4781 create_dynamic_mono_image (MonoDynamicAssembly *assembly, char *assembly_name, char *module_name)
4783 static const guchar entrycode [16] = {0xff, 0x25, 0};
4784 MonoDynamicImage *image;
4785 int i;
4787 const char *version;
4789 if (!strcmp (mono_get_runtime_info ()->framework_version, "2.1"))
4790 version = "v2.0.50727"; /* HACK: SL 2 enforces the .net 2 metadata version */
4791 else
4792 version = mono_get_runtime_info ()->runtime_version;
4794 #if HAVE_BOEHM_GC
4795 image = GC_MALLOC (sizeof (MonoDynamicImage));
4796 #else
4797 image = g_new0 (MonoDynamicImage, 1);
4798 #endif
4800 mono_profiler_module_event (&image->image, MONO_PROFILE_START_LOAD);
4802 /*g_print ("created image %p\n", image);*/
4803 /* keep in sync with image.c */
4804 image->image.name = assembly_name;
4805 image->image.assembly_name = image->image.name; /* they may be different */
4806 image->image.module_name = module_name;
4807 image->image.version = g_strdup (version);
4808 image->image.md_version_major = 1;
4809 image->image.md_version_minor = 1;
4810 image->image.dynamic = TRUE;
4812 image->image.references = g_new0 (MonoAssembly*, 1);
4813 image->image.references [0] = NULL;
4815 mono_image_init (&image->image);
4817 image->token_fixups = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC);
4818 image->method_to_table_idx = g_hash_table_new (NULL, NULL);
4819 image->field_to_table_idx = g_hash_table_new (NULL, NULL);
4820 image->method_aux_hash = g_hash_table_new (NULL, NULL);
4821 image->handleref = g_hash_table_new (NULL, NULL);
4822 image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
4823 image->generic_def_objects = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
4824 image->methodspec = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC);
4825 image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
4826 image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
4827 image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
4828 image->gen_params = g_ptr_array_new ();
4830 /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/
4831 string_heap_init (&image->sheap);
4832 mono_image_add_stream_data (&image->us, "", 1);
4833 add_to_blob_cached (image, (char*) "", 1, NULL, 0);
4834 /* import tables... */
4835 mono_image_add_stream_data (&image->code, (char*)entrycode, sizeof (entrycode));
4836 image->iat_offset = mono_image_add_stream_zero (&image->code, 8); /* two IAT entries */
4837 image->idt_offset = mono_image_add_stream_zero (&image->code, 2 * sizeof (MonoIDT)); /* two IDT entries */
4838 image->imp_names_offset = mono_image_add_stream_zero (&image->code, 2); /* flags for name entry */
4839 mono_image_add_stream_data (&image->code, "_CorExeMain", 12);
4840 mono_image_add_stream_data (&image->code, "mscoree.dll", 12);
4841 image->ilt_offset = mono_image_add_stream_zero (&image->code, 8); /* two ILT entries */
4842 stream_data_align (&image->code);
4844 image->cli_header_offset = mono_image_add_stream_zero (&image->code, sizeof (MonoCLIHeader));
4846 for (i=0; i < MONO_TABLE_NUM; ++i) {
4847 image->tables [i].next_idx = 1;
4848 image->tables [i].columns = table_sizes [i];
4851 image->image.assembly = (MonoAssembly*)assembly;
4852 image->run = assembly->run;
4853 image->save = assembly->save;
4854 image->pe_kind = 0x1; /* ILOnly */
4855 image->machine = 0x14c; /* I386 */
4857 mono_profiler_module_loaded (&image->image, MONO_PROFILE_OK);
4859 return image;
4861 #endif
4863 static void
4864 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
4866 g_free (key);
4869 void
4870 mono_dynamic_image_free (MonoDynamicImage *image)
4872 MonoDynamicImage *di = image;
4873 GList *list;
4874 int i;
4876 if (di->methodspec)
4877 mono_g_hash_table_destroy (di->methodspec);
4878 if (di->typespec)
4879 g_hash_table_destroy (di->typespec);
4880 if (di->typeref)
4881 g_hash_table_destroy (di->typeref);
4882 if (di->handleref)
4883 g_hash_table_destroy (di->handleref);
4884 if (di->tokens)
4885 mono_g_hash_table_destroy (di->tokens);
4886 if (di->generic_def_objects)
4887 mono_g_hash_table_destroy (di->generic_def_objects);
4888 if (di->blob_cache) {
4889 g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
4890 g_hash_table_destroy (di->blob_cache);
4892 if (di->standalonesig_cache)
4893 g_hash_table_destroy (di->standalonesig_cache);
4894 for (list = di->array_methods; list; list = list->next) {
4895 ArrayMethod *am = (ArrayMethod *)list->data;
4896 g_free (am->sig);
4897 g_free (am->name);
4898 g_free (am);
4900 g_list_free (di->array_methods);
4901 if (di->gen_params) {
4902 for (i = 0; i < di->gen_params->len; i++) {
4903 GenericParamTableEntry *entry = g_ptr_array_index (di->gen_params, i);
4904 if (entry->gparam->type.type) {
4905 MonoGenericParam *param = entry->gparam->type.type->data.generic_param;
4906 g_free ((char*)mono_generic_param_info (param)->name);
4907 g_free (param);
4909 g_free (entry);
4911 g_ptr_array_free (di->gen_params, TRUE);
4913 if (di->token_fixups)
4914 mono_g_hash_table_destroy (di->token_fixups);
4915 if (di->method_to_table_idx)
4916 g_hash_table_destroy (di->method_to_table_idx);
4917 if (di->field_to_table_idx)
4918 g_hash_table_destroy (di->field_to_table_idx);
4919 if (di->method_aux_hash)
4920 g_hash_table_destroy (di->method_aux_hash);
4921 g_free (di->strong_name);
4922 g_free (di->win32_res);
4923 if (di->public_key)
4924 g_free (di->public_key);
4926 /*g_print ("string heap destroy for image %p\n", di);*/
4927 mono_dynamic_stream_reset (&di->sheap);
4928 mono_dynamic_stream_reset (&di->code);
4929 mono_dynamic_stream_reset (&di->resources);
4930 mono_dynamic_stream_reset (&di->us);
4931 mono_dynamic_stream_reset (&di->blob);
4932 mono_dynamic_stream_reset (&di->tstream);
4933 mono_dynamic_stream_reset (&di->guid);
4934 for (i = 0; i < MONO_TABLE_NUM; ++i) {
4935 g_free (di->tables [i].values);
4939 #ifndef DISABLE_REFLECTION_EMIT
4942 * mono_image_basic_init:
4943 * @assembly: an assembly builder object
4945 * Create the MonoImage that represents the assembly builder and setup some
4946 * of the helper hash table and the basic metadata streams.
4948 void
4949 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
4951 MonoDynamicAssembly *assembly;
4952 MonoDynamicImage *image;
4953 MonoDomain *domain = mono_object_domain (assemblyb);
4955 MONO_ARCH_SAVE_REGS;
4957 if (assemblyb->dynamic_assembly)
4958 return;
4960 #if HAVE_BOEHM_GC
4961 assembly = assemblyb->dynamic_assembly = GC_MALLOC (sizeof (MonoDynamicAssembly));
4962 #else
4963 assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
4964 #endif
4966 mono_profiler_assembly_event (&assembly->assembly, MONO_PROFILE_START_LOAD);
4968 assembly->assembly.ref_count = 1;
4969 assembly->assembly.dynamic = TRUE;
4970 assembly->assembly.corlib_internal = assemblyb->corlib_internal;
4971 assemblyb->assembly.assembly = (MonoAssembly*)assembly;
4972 assembly->assembly.basedir = mono_string_to_utf8 (assemblyb->dir);
4973 if (assemblyb->culture)
4974 assembly->assembly.aname.culture = mono_string_to_utf8 (assemblyb->culture);
4975 else
4976 assembly->assembly.aname.culture = g_strdup ("");
4978 if (assemblyb->version) {
4979 char *vstr = mono_string_to_utf8 (assemblyb->version);
4980 char **version = g_strsplit (vstr, ".", 4);
4981 char **parts = version;
4982 assembly->assembly.aname.major = atoi (*parts++);
4983 assembly->assembly.aname.minor = atoi (*parts++);
4984 assembly->assembly.aname.build = *parts != NULL ? atoi (*parts++) : 0;
4985 assembly->assembly.aname.revision = *parts != NULL ? atoi (*parts) : 0;
4987 g_strfreev (version);
4988 g_free (vstr);
4989 } else {
4990 assembly->assembly.aname.major = 0;
4991 assembly->assembly.aname.minor = 0;
4992 assembly->assembly.aname.build = 0;
4993 assembly->assembly.aname.revision = 0;
4996 assembly->run = assemblyb->access != 2;
4997 assembly->save = assemblyb->access != 1;
4999 image = create_dynamic_mono_image (assembly, mono_string_to_utf8 (assemblyb->name), g_strdup ("RefEmit_YouForgotToDefineAModule"));
5000 image->initial_image = TRUE;
5001 assembly->assembly.aname.name = image->image.name;
5002 assembly->assembly.image = &image->image;
5003 if (assemblyb->pktoken && assemblyb->pktoken->max_length) {
5004 /* -1 to correct for the trailing NULL byte */
5005 if (assemblyb->pktoken->max_length != MONO_PUBLIC_KEY_TOKEN_LENGTH - 1) {
5006 g_error ("Public key token length invalid for assembly %s: %i", assembly->assembly.aname.name, assemblyb->pktoken->max_length);
5008 memcpy (&assembly->assembly.aname.public_key_token, mono_array_addr (assemblyb->pktoken, guint8, 0), assemblyb->pktoken->max_length);
5011 mono_domain_assemblies_lock (domain);
5012 domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, assembly);
5013 mono_domain_assemblies_unlock (domain);
5015 register_assembly (mono_object_domain (assemblyb), &assemblyb->assembly, &assembly->assembly);
5017 mono_profiler_assembly_loaded (&assembly->assembly, MONO_PROFILE_OK);
5019 mono_assembly_invoke_load_hook ((MonoAssembly*)assembly);
5022 #endif /* !DISABLE_REFLECTION_EMIT */
5024 #ifndef DISABLE_REFLECTION_EMIT_SAVE
5026 static int
5027 calc_section_size (MonoDynamicImage *assembly)
5029 int nsections = 0;
5031 /* alignment constraints */
5032 mono_image_add_stream_zero (&assembly->code, 4 - (assembly->code.index % 4));
5033 g_assert ((assembly->code.index % 4) == 0);
5034 assembly->meta_size += 3;
5035 assembly->meta_size &= ~3;
5036 mono_image_add_stream_zero (&assembly->resources, 4 - (assembly->resources.index % 4));
5037 g_assert ((assembly->resources.index % 4) == 0);
5039 assembly->sections [MONO_SECTION_TEXT].size = assembly->meta_size + assembly->code.index + assembly->resources.index + assembly->strong_name_size;
5040 assembly->sections [MONO_SECTION_TEXT].attrs = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
5041 nsections++;
5043 if (assembly->win32_res) {
5044 guint32 res_size = (assembly->win32_res_size + 3) & ~3;
5046 assembly->sections [MONO_SECTION_RSRC].size = res_size;
5047 assembly->sections [MONO_SECTION_RSRC].attrs = SECT_FLAGS_HAS_INITIALIZED_DATA | SECT_FLAGS_MEM_READ;
5048 nsections++;
5051 assembly->sections [MONO_SECTION_RELOC].size = 12;
5052 assembly->sections [MONO_SECTION_RELOC].attrs = SECT_FLAGS_MEM_READ | SECT_FLAGS_MEM_DISCARDABLE | SECT_FLAGS_HAS_INITIALIZED_DATA;
5053 nsections++;
5055 return nsections;
5058 typedef struct {
5059 guint32 id;
5060 guint32 offset;
5061 GSList *children;
5062 MonoReflectionWin32Resource *win32_res; /* Only for leaf nodes */
5063 } ResTreeNode;
5065 static int
5066 resource_tree_compare_by_id (gconstpointer a, gconstpointer b)
5068 ResTreeNode *t1 = (ResTreeNode*)a;
5069 ResTreeNode *t2 = (ResTreeNode*)b;
5071 return t1->id - t2->id;
5075 * resource_tree_create:
5077 * Organize the resources into a resource tree.
5079 static ResTreeNode *
5080 resource_tree_create (MonoArray *win32_resources)
5082 ResTreeNode *tree, *res_node, *type_node, *lang_node;
5083 GSList *l;
5084 int i;
5086 tree = g_new0 (ResTreeNode, 1);
5088 for (i = 0; i < mono_array_length (win32_resources); ++i) {
5089 MonoReflectionWin32Resource *win32_res =
5090 (MonoReflectionWin32Resource*)mono_array_addr (win32_resources, MonoReflectionWin32Resource, i);
5092 /* Create node */
5094 /* FIXME: BUG: this stores managed references in unmanaged memory */
5095 lang_node = g_new0 (ResTreeNode, 1);
5096 lang_node->id = win32_res->lang_id;
5097 lang_node->win32_res = win32_res;
5099 /* Create type node if neccesary */
5100 type_node = NULL;
5101 for (l = tree->children; l; l = l->next)
5102 if (((ResTreeNode*)(l->data))->id == win32_res->res_type) {
5103 type_node = (ResTreeNode*)l->data;
5104 break;
5107 if (!type_node) {
5108 type_node = g_new0 (ResTreeNode, 1);
5109 type_node->id = win32_res->res_type;
5112 * The resource types have to be sorted otherwise
5113 * Windows Explorer can't display the version information.
5115 tree->children = g_slist_insert_sorted (tree->children,
5116 type_node, resource_tree_compare_by_id);
5119 /* Create res node if neccesary */
5120 res_node = NULL;
5121 for (l = type_node->children; l; l = l->next)
5122 if (((ResTreeNode*)(l->data))->id == win32_res->res_id) {
5123 res_node = (ResTreeNode*)l->data;
5124 break;
5127 if (!res_node) {
5128 res_node = g_new0 (ResTreeNode, 1);
5129 res_node->id = win32_res->res_id;
5130 type_node->children = g_slist_append (type_node->children, res_node);
5133 res_node->children = g_slist_append (res_node->children, lang_node);
5136 return tree;
5140 * resource_tree_encode:
5142 * Encode the resource tree into the format used in the PE file.
5144 static void
5145 resource_tree_encode (ResTreeNode *node, char *begin, char *p, char **endbuf)
5147 char *entries;
5148 MonoPEResourceDir dir;
5149 MonoPEResourceDirEntry dir_entry;
5150 MonoPEResourceDataEntry data_entry;
5151 GSList *l;
5152 guint32 res_id_entries;
5155 * For the format of the resource directory, see the article
5156 * "An In-Depth Look into the Win32 Portable Executable File Format" by
5157 * Matt Pietrek
5160 memset (&dir, 0, sizeof (dir));
5161 memset (&dir_entry, 0, sizeof (dir_entry));
5162 memset (&data_entry, 0, sizeof (data_entry));
5164 g_assert (sizeof (dir) == 16);
5165 g_assert (sizeof (dir_entry) == 8);
5166 g_assert (sizeof (data_entry) == 16);
5168 node->offset = p - begin;
5170 /* IMAGE_RESOURCE_DIRECTORY */
5171 res_id_entries = g_slist_length (node->children);
5172 dir.res_id_entries = GUINT16_TO_LE (res_id_entries);
5174 memcpy (p, &dir, sizeof (dir));
5175 p += sizeof (dir);
5177 /* Reserve space for entries */
5178 entries = p;
5179 p += sizeof (dir_entry) * res_id_entries;
5181 /* Write children */
5182 for (l = node->children; l; l = l->next) {
5183 ResTreeNode *child = (ResTreeNode*)l->data;
5185 if (child->win32_res) {
5186 guint32 size;
5188 child->offset = p - begin;
5190 /* IMAGE_RESOURCE_DATA_ENTRY */
5191 data_entry.rde_data_offset = GUINT32_TO_LE (p - begin + sizeof (data_entry));
5192 size = mono_array_length (child->win32_res->res_data);
5193 data_entry.rde_size = GUINT32_TO_LE (size);
5195 memcpy (p, &data_entry, sizeof (data_entry));
5196 p += sizeof (data_entry);
5198 memcpy (p, mono_array_addr (child->win32_res->res_data, char, 0), size);
5199 p += size;
5200 } else {
5201 resource_tree_encode (child, begin, p, &p);
5205 /* IMAGE_RESOURCE_ENTRY */
5206 for (l = node->children; l; l = l->next) {
5207 ResTreeNode *child = (ResTreeNode*)l->data;
5209 MONO_PE_RES_DIR_ENTRY_SET_NAME (dir_entry, FALSE, child->id);
5210 MONO_PE_RES_DIR_ENTRY_SET_DIR (dir_entry, !child->win32_res, child->offset);
5212 memcpy (entries, &dir_entry, sizeof (dir_entry));
5213 entries += sizeof (dir_entry);
5216 *endbuf = p;
5219 static void
5220 resource_tree_free (ResTreeNode * node)
5222 GSList * list;
5223 for (list = node->children; list; list = list->next)
5224 resource_tree_free ((ResTreeNode*)list->data);
5225 g_slist_free(node->children);
5226 g_free (node);
5229 static void
5230 assembly_add_win32_resources (MonoDynamicImage *assembly, MonoReflectionAssemblyBuilder *assemblyb)
5232 char *buf;
5233 char *p;
5234 guint32 size, i;
5235 MonoReflectionWin32Resource *win32_res;
5236 ResTreeNode *tree;
5238 if (!assemblyb->win32_resources)
5239 return;
5242 * Resources are stored in a three level tree inside the PE file.
5243 * - level one contains a node for each type of resource
5244 * - level two contains a node for each resource
5245 * - level three contains a node for each instance of a resource for a
5246 * specific language.
5249 tree = resource_tree_create (assemblyb->win32_resources);
5251 /* Estimate the size of the encoded tree */
5252 size = 0;
5253 for (i = 0; i < mono_array_length (assemblyb->win32_resources); ++i) {
5254 win32_res = (MonoReflectionWin32Resource*)mono_array_addr (assemblyb->win32_resources, MonoReflectionWin32Resource, i);
5255 size += mono_array_length (win32_res->res_data);
5257 /* Directory structure */
5258 size += mono_array_length (assemblyb->win32_resources) * 256;
5259 p = buf = g_malloc (size);
5261 resource_tree_encode (tree, p, p, &p);
5263 g_assert (p - buf <= size);
5265 assembly->win32_res = g_malloc (p - buf);
5266 assembly->win32_res_size = p - buf;
5267 memcpy (assembly->win32_res, buf, p - buf);
5269 g_free (buf);
5270 resource_tree_free (tree);
5273 static void
5274 fixup_resource_directory (char *res_section, char *p, guint32 rva)
5276 MonoPEResourceDir *dir = (MonoPEResourceDir*)p;
5277 int i;
5279 p += sizeof (MonoPEResourceDir);
5280 for (i = 0; i < GUINT16_FROM_LE (dir->res_named_entries) + GUINT16_FROM_LE (dir->res_id_entries); ++i) {
5281 MonoPEResourceDirEntry *dir_entry = (MonoPEResourceDirEntry*)p;
5282 char *child = res_section + MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*dir_entry);
5283 if (MONO_PE_RES_DIR_ENTRY_IS_DIR (*dir_entry)) {
5284 fixup_resource_directory (res_section, child, rva);
5285 } else {
5286 MonoPEResourceDataEntry *data_entry = (MonoPEResourceDataEntry*)child;
5287 data_entry->rde_data_offset = GUINT32_TO_LE (GUINT32_FROM_LE (data_entry->rde_data_offset) + rva);
5290 p += sizeof (MonoPEResourceDirEntry);
5294 static void
5295 checked_write_file (HANDLE f, gconstpointer buffer, guint32 numbytes)
5297 guint32 dummy;
5298 if (!WriteFile (f, buffer, numbytes, &dummy, NULL))
5299 g_error ("WriteFile returned %d\n", GetLastError ());
5303 * mono_image_create_pefile:
5304 * @mb: a module builder object
5306 * This function creates the PE-COFF header, the image sections, the CLI header * etc. all the data is written in
5307 * assembly->pefile where it can be easily retrieved later in chunks.
5309 void
5310 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file)
5312 MonoMSDOSHeader *msdos;
5313 MonoDotNetHeader *header;
5314 MonoSectionTable *section;
5315 MonoCLIHeader *cli_header;
5316 guint32 size, image_size, virtual_base, text_offset;
5317 guint32 header_start, section_start, file_offset, virtual_offset;
5318 MonoDynamicImage *assembly;
5319 MonoReflectionAssemblyBuilder *assemblyb;
5320 MonoDynamicStream pefile_stream = {0};
5321 MonoDynamicStream *pefile = &pefile_stream;
5322 int i, nsections;
5323 guint32 *rva, value;
5324 guchar *p;
5325 static const unsigned char msheader[] = {
5326 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
5327 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
5330 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
5331 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
5332 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
5333 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5336 assemblyb = mb->assemblyb;
5338 mono_image_basic_init (assemblyb);
5339 assembly = mb->dynamic_image;
5341 assembly->pe_kind = assemblyb->pe_kind;
5342 assembly->machine = assemblyb->machine;
5343 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->pe_kind = assemblyb->pe_kind;
5344 ((MonoDynamicImage*)assemblyb->dynamic_assembly->assembly.image)->machine = assemblyb->machine;
5346 mono_image_build_metadata (mb);
5348 if (mb->is_main && assemblyb->resources) {
5349 int len = mono_array_length (assemblyb->resources);
5350 for (i = 0; i < len; ++i)
5351 assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (assemblyb->resources, MonoReflectionResource, i));
5354 if (mb->resources) {
5355 int len = mono_array_length (mb->resources);
5356 for (i = 0; i < len; ++i)
5357 assembly_add_resource (mb, assembly, (MonoReflectionResource*)mono_array_addr (mb->resources, MonoReflectionResource, i));
5360 build_compressed_metadata (assembly);
5362 if (mb->is_main)
5363 assembly_add_win32_resources (assembly, assemblyb);
5365 nsections = calc_section_size (assembly);
5367 /* The DOS header and stub */
5368 g_assert (sizeof (MonoMSDOSHeader) == sizeof (msheader));
5369 mono_image_add_stream_data (pefile, (char*)msheader, sizeof (msheader));
5371 /* the dotnet header */
5372 header_start = mono_image_add_stream_zero (pefile, sizeof (MonoDotNetHeader));
5374 /* the section tables */
5375 section_start = mono_image_add_stream_zero (pefile, sizeof (MonoSectionTable) * nsections);
5377 file_offset = section_start + sizeof (MonoSectionTable) * nsections;
5378 virtual_offset = VIRT_ALIGN;
5379 image_size = 0;
5381 for (i = 0; i < MONO_SECTION_MAX; ++i) {
5382 if (!assembly->sections [i].size)
5383 continue;
5384 /* align offsets */
5385 file_offset += FILE_ALIGN - 1;
5386 file_offset &= ~(FILE_ALIGN - 1);
5387 virtual_offset += VIRT_ALIGN - 1;
5388 virtual_offset &= ~(VIRT_ALIGN - 1);
5390 assembly->sections [i].offset = file_offset;
5391 assembly->sections [i].rva = virtual_offset;
5393 file_offset += assembly->sections [i].size;
5394 virtual_offset += assembly->sections [i].size;
5395 image_size += (assembly->sections [i].size + VIRT_ALIGN - 1) & ~(VIRT_ALIGN - 1);
5398 file_offset += FILE_ALIGN - 1;
5399 file_offset &= ~(FILE_ALIGN - 1);
5401 image_size += section_start + sizeof (MonoSectionTable) * nsections;
5403 /* back-patch info */
5404 msdos = (MonoMSDOSHeader*)pefile->data;
5405 msdos->pe_offset = GUINT32_FROM_LE (sizeof (MonoMSDOSHeader));
5407 header = (MonoDotNetHeader*)(pefile->data + header_start);
5408 header->pesig [0] = 'P';
5409 header->pesig [1] = 'E';
5411 header->coff.coff_machine = GUINT16_FROM_LE (assemblyb->machine);
5412 header->coff.coff_sections = GUINT16_FROM_LE (nsections);
5413 header->coff.coff_time = GUINT32_FROM_LE (time (NULL));
5414 header->coff.coff_opt_header_size = GUINT16_FROM_LE (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4);
5415 if (assemblyb->pekind == 1) {
5416 /* it's a dll */
5417 header->coff.coff_attributes = GUINT16_FROM_LE (0x210e);
5418 } else {
5419 /* it's an exe */
5420 header->coff.coff_attributes = GUINT16_FROM_LE (0x010e);
5423 virtual_base = 0x400000; /* FIXME: 0x10000000 if a DLL */
5425 header->pe.pe_magic = GUINT16_FROM_LE (0x10B);
5426 header->pe.pe_major = 6;
5427 header->pe.pe_minor = 0;
5428 size = assembly->sections [MONO_SECTION_TEXT].size;
5429 size += FILE_ALIGN - 1;
5430 size &= ~(FILE_ALIGN - 1);
5431 header->pe.pe_code_size = GUINT32_FROM_LE(size);
5432 size = assembly->sections [MONO_SECTION_RSRC].size;
5433 size += FILE_ALIGN - 1;
5434 size &= ~(FILE_ALIGN - 1);
5435 header->pe.pe_data_size = GUINT32_FROM_LE(size);
5436 g_assert (START_TEXT_RVA == assembly->sections [MONO_SECTION_TEXT].rva);
5437 header->pe.pe_rva_code_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
5438 header->pe.pe_rva_data_base = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
5439 /* pe_rva_entry_point always at the beginning of the text section */
5440 header->pe.pe_rva_entry_point = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_TEXT].rva);
5442 header->nt.pe_image_base = GUINT32_FROM_LE (virtual_base);
5443 header->nt.pe_section_align = GUINT32_FROM_LE (VIRT_ALIGN);
5444 header->nt.pe_file_alignment = GUINT32_FROM_LE (FILE_ALIGN);
5445 header->nt.pe_os_major = GUINT16_FROM_LE (4);
5446 header->nt.pe_os_minor = GUINT16_FROM_LE (0);
5447 header->nt.pe_subsys_major = GUINT16_FROM_LE (4);
5448 size = section_start;
5449 size += FILE_ALIGN - 1;
5450 size &= ~(FILE_ALIGN - 1);
5451 header->nt.pe_header_size = GUINT32_FROM_LE (size);
5452 size = image_size;
5453 size += VIRT_ALIGN - 1;
5454 size &= ~(VIRT_ALIGN - 1);
5455 header->nt.pe_image_size = GUINT32_FROM_LE (size);
5458 // Translate the PEFileKind value to the value expected by the Windows loader
5461 short kind;
5464 // PEFileKinds.Dll == 1
5465 // PEFileKinds.ConsoleApplication == 2
5466 // PEFileKinds.WindowApplication == 3
5468 // need to get:
5469 // IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
5470 // IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
5472 if (assemblyb->pekind == 3)
5473 kind = 2;
5474 else
5475 kind = 3;
5477 header->nt.pe_subsys_required = GUINT16_FROM_LE (kind);
5479 header->nt.pe_stack_reserve = GUINT32_FROM_LE (0x00100000);
5480 header->nt.pe_stack_commit = GUINT32_FROM_LE (0x00001000);
5481 header->nt.pe_heap_reserve = GUINT32_FROM_LE (0x00100000);
5482 header->nt.pe_heap_commit = GUINT32_FROM_LE (0x00001000);
5483 header->nt.pe_loader_flags = GUINT32_FROM_LE (0);
5484 header->nt.pe_data_dir_count = GUINT32_FROM_LE (16);
5486 /* fill data directory entries */
5488 header->datadir.pe_resource_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].size);
5489 header->datadir.pe_resource_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RSRC].rva);
5491 header->datadir.pe_reloc_table.size = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].size);
5492 header->datadir.pe_reloc_table.rva = GUINT32_FROM_LE (assembly->sections [MONO_SECTION_RELOC].rva);
5494 header->datadir.pe_cli_header.size = GUINT32_FROM_LE (72);
5495 header->datadir.pe_cli_header.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->cli_header_offset);
5496 header->datadir.pe_iat.size = GUINT32_FROM_LE (8);
5497 header->datadir.pe_iat.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
5498 /* patch entrypoint name */
5499 if (assemblyb->pekind == 1)
5500 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorDllMain", 12);
5501 else
5502 memcpy (assembly->code.data + assembly->imp_names_offset + 2, "_CorExeMain", 12);
5503 /* patch imported function RVA name */
5504 rva = (guint32*)(assembly->code.data + assembly->iat_offset);
5505 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset);
5507 /* the import table */
5508 header->datadir.pe_import_table.size = GUINT32_FROM_LE (79); /* FIXME: magic number? */
5509 header->datadir.pe_import_table.rva = GUINT32_FROM_LE (assembly->text_rva + assembly->idt_offset);
5510 /* patch imported dll RVA name and other entries in the dir */
5511 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, name_rva));
5512 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->imp_names_offset + 14); /* 14 is hint+strlen+1 of func name */
5513 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_address_table_rva));
5514 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->iat_offset);
5515 rva = (guint32*)(assembly->code.data + assembly->idt_offset + G_STRUCT_OFFSET (MonoIDT, import_lookup_table));
5516 *rva = GUINT32_FROM_LE (assembly->text_rva + assembly->ilt_offset);
5518 p = (guchar*)(assembly->code.data + assembly->ilt_offset);
5519 value = (assembly->text_rva + assembly->imp_names_offset);
5520 *p++ = (value) & 0xff;
5521 *p++ = (value >> 8) & (0xff);
5522 *p++ = (value >> 16) & (0xff);
5523 *p++ = (value >> 24) & (0xff);
5525 /* the CLI header info */
5526 cli_header = (MonoCLIHeader*)(assembly->code.data + assembly->cli_header_offset);
5527 cli_header->ch_size = GUINT32_FROM_LE (72);
5528 cli_header->ch_runtime_major = GUINT16_FROM_LE (2);
5529 if (mono_framework_version () > 1)
5530 cli_header->ch_runtime_minor = GUINT16_FROM_LE (5);
5531 else
5532 cli_header->ch_runtime_minor = GUINT16_FROM_LE (0);
5533 cli_header->ch_flags = GUINT32_FROM_LE (assemblyb->pe_kind);
5534 if (assemblyb->entry_point) {
5535 guint32 table_idx = 0;
5536 if (!strcmp (assemblyb->entry_point->object.vtable->klass->name, "MethodBuilder")) {
5537 MonoReflectionMethodBuilder *methodb = (MonoReflectionMethodBuilder*)assemblyb->entry_point;
5538 table_idx = methodb->table_idx;
5539 } else {
5540 table_idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->method_to_table_idx, assemblyb->entry_point->method));
5542 cli_header->ch_entry_point = GUINT32_FROM_LE (table_idx | MONO_TOKEN_METHOD_DEF);
5543 } else {
5544 cli_header->ch_entry_point = GUINT32_FROM_LE (0);
5546 /* The embedded managed resources */
5547 text_offset = assembly->text_rva + assembly->code.index;
5548 cli_header->ch_resources.rva = GUINT32_FROM_LE (text_offset);
5549 cli_header->ch_resources.size = GUINT32_FROM_LE (assembly->resources.index);
5550 text_offset += assembly->resources.index;
5551 cli_header->ch_metadata.rva = GUINT32_FROM_LE (text_offset);
5552 cli_header->ch_metadata.size = GUINT32_FROM_LE (assembly->meta_size);
5553 text_offset += assembly->meta_size;
5554 if (assembly->strong_name_size) {
5555 cli_header->ch_strong_name.rva = GUINT32_FROM_LE (text_offset);
5556 cli_header->ch_strong_name.size = GUINT32_FROM_LE (assembly->strong_name_size);
5557 text_offset += assembly->strong_name_size;
5560 /* write the section tables and section content */
5561 section = (MonoSectionTable*)(pefile->data + section_start);
5562 for (i = 0; i < MONO_SECTION_MAX; ++i) {
5563 static const char section_names [][7] = {
5564 ".text", ".rsrc", ".reloc"
5566 if (!assembly->sections [i].size)
5567 continue;
5568 strcpy (section->st_name, section_names [i]);
5569 /*g_print ("output section %s (%d), size: %d\n", section->st_name, i, assembly->sections [i].size);*/
5570 section->st_virtual_address = GUINT32_FROM_LE (assembly->sections [i].rva);
5571 section->st_virtual_size = GUINT32_FROM_LE (assembly->sections [i].size);
5572 section->st_raw_data_size = GUINT32_FROM_LE (GUINT32_TO_LE (section->st_virtual_size) + (FILE_ALIGN - 1));
5573 section->st_raw_data_size &= GUINT32_FROM_LE (~(FILE_ALIGN - 1));
5574 section->st_raw_data_ptr = GUINT32_FROM_LE (assembly->sections [i].offset);
5575 section->st_flags = GUINT32_FROM_LE (assembly->sections [i].attrs);
5576 section ++;
5579 checked_write_file (file, pefile->data, pefile->index);
5581 mono_dynamic_stream_reset (pefile);
5583 for (i = 0; i < MONO_SECTION_MAX; ++i) {
5584 if (!assembly->sections [i].size)
5585 continue;
5587 if (SetFilePointer (file, assembly->sections [i].offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
5588 g_error ("SetFilePointer returned %d\n", GetLastError ());
5590 switch (i) {
5591 case MONO_SECTION_TEXT:
5592 /* patch entry point */
5593 p = (guchar*)(assembly->code.data + 2);
5594 value = (virtual_base + assembly->text_rva + assembly->iat_offset);
5595 *p++ = (value) & 0xff;
5596 *p++ = (value >> 8) & 0xff;
5597 *p++ = (value >> 16) & 0xff;
5598 *p++ = (value >> 24) & 0xff;
5600 checked_write_file (file, assembly->code.data, assembly->code.index);
5601 checked_write_file (file, assembly->resources.data, assembly->resources.index);
5602 checked_write_file (file, assembly->image.raw_metadata, assembly->meta_size);
5603 checked_write_file (file, assembly->strong_name, assembly->strong_name_size);
5606 g_free (assembly->image.raw_metadata);
5607 break;
5608 case MONO_SECTION_RELOC: {
5609 struct {
5610 guint32 page_rva;
5611 guint32 block_size;
5612 guint16 type_and_offset;
5613 guint16 term;
5614 } reloc;
5616 g_assert (sizeof (reloc) == 12);
5618 reloc.page_rva = GUINT32_FROM_LE (assembly->text_rva);
5619 reloc.block_size = GUINT32_FROM_LE (12);
5622 * the entrypoint is always at the start of the text section
5623 * 3 is IMAGE_REL_BASED_HIGHLOW
5624 * 2 is patch_size_rva - text_rva
5626 reloc.type_and_offset = GUINT16_FROM_LE ((3 << 12) + (2));
5627 reloc.term = 0;
5629 checked_write_file (file, &reloc, sizeof (reloc));
5631 break;
5633 case MONO_SECTION_RSRC:
5634 if (assembly->win32_res) {
5636 /* Fixup the offsets in the IMAGE_RESOURCE_DATA_ENTRY structures */
5637 fixup_resource_directory (assembly->win32_res, assembly->win32_res, assembly->sections [i].rva);
5638 checked_write_file (file, assembly->win32_res, assembly->win32_res_size);
5640 break;
5641 default:
5642 g_assert_not_reached ();
5646 /* check that the file is properly padded */
5647 if (SetFilePointer (file, file_offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
5648 g_error ("SetFilePointer returned %d\n", GetLastError ());
5649 if (! SetEndOfFile (file))
5650 g_error ("SetEndOfFile returned %d\n", GetLastError ());
5652 mono_dynamic_stream_reset (&assembly->code);
5653 mono_dynamic_stream_reset (&assembly->us);
5654 mono_dynamic_stream_reset (&assembly->blob);
5655 mono_dynamic_stream_reset (&assembly->guid);
5656 mono_dynamic_stream_reset (&assembly->sheap);
5658 g_hash_table_foreach (assembly->blob_cache, (GHFunc)g_free, NULL);
5659 g_hash_table_destroy (assembly->blob_cache);
5660 assembly->blob_cache = NULL;
5663 #else /* DISABLE_REFLECTION_EMIT_SAVE */
5665 void
5666 mono_image_create_pefile (MonoReflectionModuleBuilder *mb, HANDLE file)
5668 g_assert_not_reached ();
5671 #endif /* DISABLE_REFLECTION_EMIT_SAVE */
5673 #ifndef DISABLE_REFLECTION_EMIT
5675 MonoReflectionModule *
5676 mono_image_load_module_dynamic (MonoReflectionAssemblyBuilder *ab, MonoString *fileName)
5678 char *name;
5679 MonoImage *image;
5680 MonoImageOpenStatus status;
5681 MonoDynamicAssembly *assembly;
5682 guint32 module_count;
5683 MonoImage **new_modules;
5684 gboolean *new_modules_loaded;
5686 name = mono_string_to_utf8 (fileName);
5688 image = mono_image_open (name, &status);
5689 if (!image) {
5690 MonoException *exc;
5691 if (status == MONO_IMAGE_ERROR_ERRNO)
5692 exc = mono_get_exception_file_not_found (fileName);
5693 else
5694 exc = mono_get_exception_bad_image_format (name);
5695 g_free (name);
5696 mono_raise_exception (exc);
5699 g_free (name);
5701 assembly = ab->dynamic_assembly;
5702 image->assembly = (MonoAssembly*)assembly;
5704 module_count = image->assembly->image->module_count;
5705 new_modules = g_new0 (MonoImage *, module_count + 1);
5706 new_modules_loaded = g_new0 (gboolean, module_count + 1);
5708 if (image->assembly->image->modules)
5709 memcpy (new_modules, image->assembly->image->modules, module_count * sizeof (MonoImage *));
5710 if (image->assembly->image->modules_loaded)
5711 memcpy (new_modules_loaded, image->assembly->image->modules_loaded, module_count * sizeof (gboolean));
5712 new_modules [module_count] = image;
5713 new_modules_loaded [module_count] = TRUE;
5714 mono_image_addref (image);
5716 g_free (image->assembly->image->modules);
5717 image->assembly->image->modules = new_modules;
5718 image->assembly->image->modules_loaded = new_modules_loaded;
5719 image->assembly->image->module_count ++;
5721 mono_assembly_load_references (image, &status);
5722 if (status) {
5723 mono_image_close (image);
5724 mono_raise_exception (mono_get_exception_file_not_found (fileName));
5727 return mono_module_get_object (mono_domain_get (), image);
5730 #endif /* DISABLE_REFLECTION_EMIT */
5733 * We need to return always the same object for MethodInfo, FieldInfo etc..
5734 * but we need to consider the reflected type.
5735 * type uses a different hash, since it uses custom hash/equal functions.
5738 typedef struct {
5739 gpointer item;
5740 MonoClass *refclass;
5741 } ReflectedEntry;
5743 static gboolean
5744 reflected_equal (gconstpointer a, gconstpointer b) {
5745 const ReflectedEntry *ea = a;
5746 const ReflectedEntry *eb = b;
5748 return (ea->item == eb->item) && (ea->refclass == eb->refclass);
5751 static guint
5752 reflected_hash (gconstpointer a) {
5753 const ReflectedEntry *ea = a;
5754 return mono_aligned_addr_hash (ea->item);
5757 #define CHECK_OBJECT(t,p,k) \
5758 do { \
5759 t _obj; \
5760 ReflectedEntry e; \
5761 e.item = (p); \
5762 e.refclass = (k); \
5763 mono_domain_lock (domain); \
5764 if (!domain->refobject_hash) \
5765 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC); \
5766 if ((_obj = mono_g_hash_table_lookup (domain->refobject_hash, &e))) { \
5767 mono_domain_unlock (domain); \
5768 return _obj; \
5770 mono_domain_unlock (domain); \
5771 } while (0)
5773 #ifdef HAVE_BOEHM_GC
5774 /* ReflectedEntry doesn't need to be GC tracked */
5775 #define ALLOC_REFENTRY g_new0 (ReflectedEntry, 1)
5776 #define FREE_REFENTRY(entry) g_free ((entry))
5777 #define REFENTRY_REQUIRES_CLEANUP
5778 #else
5779 #define ALLOC_REFENTRY mono_mempool_alloc (domain->mp, sizeof (ReflectedEntry))
5780 /* FIXME: */
5781 #define FREE_REFENTRY(entry)
5782 #endif
5784 #define CACHE_OBJECT(t,p,o,k) \
5785 do { \
5786 t _obj; \
5787 ReflectedEntry pe; \
5788 pe.item = (p); \
5789 pe.refclass = (k); \
5790 mono_domain_lock (domain); \
5791 if (!domain->refobject_hash) \
5792 domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC); \
5793 _obj = mono_g_hash_table_lookup (domain->refobject_hash, &pe); \
5794 if (!_obj) { \
5795 ReflectedEntry *e = ALLOC_REFENTRY; \
5796 e->item = (p); \
5797 e->refclass = (k); \
5798 mono_g_hash_table_insert (domain->refobject_hash, e,o); \
5799 _obj = o; \
5801 mono_domain_unlock (domain); \
5802 return _obj; \
5803 } while (0)
5805 static void
5806 clear_cached_object (MonoDomain *domain, gpointer o, MonoClass *klass)
5808 mono_domain_lock (domain);
5809 if (domain->refobject_hash) {
5810 ReflectedEntry pe;
5811 gpointer orig_pe, orig_value;
5813 pe.item = o;
5814 pe.refclass = klass;
5815 if (mono_g_hash_table_lookup_extended (domain->refobject_hash, &pe, &orig_pe, &orig_value)) {
5816 mono_g_hash_table_remove (domain->refobject_hash, &pe);
5817 FREE_REFENTRY (orig_pe);
5820 mono_domain_unlock (domain);
5823 #ifdef REFENTRY_REQUIRES_CLEANUP
5824 static void
5825 cleanup_refobject_hash (gpointer key, gpointer value, gpointer user_data)
5827 FREE_REFENTRY (key);
5829 #endif
5831 void
5832 mono_reflection_cleanup_domain (MonoDomain *domain)
5834 if (domain->refobject_hash) {
5835 /*let's avoid scanning the whole hashtable if not needed*/
5836 #ifdef REFENTRY_REQUIRES_CLEANUP
5837 mono_g_hash_table_foreach (domain->refobject_hash, cleanup_refobject_hash, NULL);
5838 #endif
5839 mono_g_hash_table_destroy (domain->refobject_hash);
5840 domain->refobject_hash = NULL;
5844 #ifndef DISABLE_REFLECTION_EMIT
5845 static gpointer
5846 register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly)
5848 CACHE_OBJECT (MonoReflectionAssembly *, assembly, res, NULL);
5851 static gpointer
5852 register_module (MonoDomain *domain, MonoReflectionModuleBuilder *res, MonoDynamicImage *module)
5854 CACHE_OBJECT (MonoReflectionModuleBuilder *, module, res, NULL);
5857 void
5858 mono_image_module_basic_init (MonoReflectionModuleBuilder *moduleb)
5860 MonoDynamicImage *image = moduleb->dynamic_image;
5861 MonoReflectionAssemblyBuilder *ab = moduleb->assemblyb;
5862 if (!image) {
5863 int module_count;
5864 MonoImage **new_modules;
5865 MonoImage *ass;
5867 * FIXME: we already created an image in mono_image_basic_init (), but
5868 * we don't know which module it belongs to, since that is only
5869 * determined at assembly save time.
5871 /*image = (MonoDynamicImage*)ab->dynamic_assembly->assembly.image; */
5872 image = create_dynamic_mono_image (ab->dynamic_assembly, mono_string_to_utf8 (ab->name), mono_string_to_utf8 (moduleb->module.fqname));
5874 moduleb->module.image = &image->image;
5875 moduleb->dynamic_image = image;
5876 register_module (mono_object_domain (moduleb), moduleb, image);
5878 /* register the module with the assembly */
5879 ass = ab->dynamic_assembly->assembly.image;
5880 module_count = ass->module_count;
5881 new_modules = g_new0 (MonoImage *, module_count + 1);
5883 if (ass->modules)
5884 memcpy (new_modules, ass->modules, module_count * sizeof (MonoImage *));
5885 new_modules [module_count] = &image->image;
5886 mono_image_addref (&image->image);
5888 g_free (ass->modules);
5889 ass->modules = new_modules;
5890 ass->module_count ++;
5894 void
5895 mono_image_set_wrappers_type (MonoReflectionModuleBuilder *moduleb, MonoReflectionType *type)
5897 MonoDynamicImage *image = moduleb->dynamic_image;
5899 g_assert (type->type);
5900 image->wrappers_type = mono_class_from_mono_type (type->type);
5903 #endif
5906 * mono_assembly_get_object:
5907 * @domain: an app domain
5908 * @assembly: an assembly
5910 * Return an System.Reflection.Assembly object representing the MonoAssembly @assembly.
5912 MonoReflectionAssembly*
5913 mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly)
5915 static MonoClass *System_Reflection_Assembly;
5916 MonoReflectionAssembly *res;
5918 CHECK_OBJECT (MonoReflectionAssembly *, assembly, NULL);
5919 if (!System_Reflection_Assembly)
5920 System_Reflection_Assembly = mono_class_from_name (
5921 mono_defaults.corlib, "System.Reflection", "Assembly");
5922 res = (MonoReflectionAssembly *)mono_object_new (domain, System_Reflection_Assembly);
5923 res->assembly = assembly;
5925 CACHE_OBJECT (MonoReflectionAssembly *, assembly, res, NULL);
5930 MonoReflectionModule*
5931 mono_module_get_object (MonoDomain *domain, MonoImage *image)
5933 static MonoClass *System_Reflection_Module;
5934 MonoReflectionModule *res;
5935 char* basename;
5937 CHECK_OBJECT (MonoReflectionModule *, image, NULL);
5938 if (!System_Reflection_Module)
5939 System_Reflection_Module = mono_class_from_name (
5940 mono_defaults.corlib, "System.Reflection", "Module");
5941 res = (MonoReflectionModule *)mono_object_new (domain, System_Reflection_Module);
5943 res->image = image;
5944 MONO_OBJECT_SETREF (res, assembly, (MonoReflectionAssembly *) mono_assembly_get_object(domain, image->assembly));
5946 MONO_OBJECT_SETREF (res, fqname, mono_string_new (domain, image->name));
5947 basename = g_path_get_basename (image->name);
5948 MONO_OBJECT_SETREF (res, name, mono_string_new (domain, basename));
5949 MONO_OBJECT_SETREF (res, scopename, mono_string_new (domain, image->module_name));
5951 g_free (basename);
5953 if (image->assembly->image == image) {
5954 res->token = mono_metadata_make_token (MONO_TABLE_MODULE, 1);
5955 } else {
5956 int i;
5957 res->token = 0;
5958 if (image->assembly->image->modules) {
5959 for (i = 0; i < image->assembly->image->module_count; i++) {
5960 if (image->assembly->image->modules [i] == image)
5961 res->token = mono_metadata_make_token (MONO_TABLE_MODULEREF, i + 1);
5963 g_assert (res->token);
5967 CACHE_OBJECT (MonoReflectionModule *, image, res, NULL);
5970 MonoReflectionModule*
5971 mono_module_file_get_object (MonoDomain *domain, MonoImage *image, int table_index)
5973 static MonoClass *System_Reflection_Module;
5974 MonoReflectionModule *res;
5975 MonoTableInfo *table;
5976 guint32 cols [MONO_FILE_SIZE];
5977 const char *name;
5978 guint32 i, name_idx;
5979 const char *val;
5981 if (!System_Reflection_Module)
5982 System_Reflection_Module = mono_class_from_name (
5983 mono_defaults.corlib, "System.Reflection", "Module");
5984 res = (MonoReflectionModule *)mono_object_new (domain, System_Reflection_Module);
5986 table = &image->tables [MONO_TABLE_FILE];
5987 g_assert (table_index < table->rows);
5988 mono_metadata_decode_row (table, table_index, cols, MONO_FILE_SIZE);
5990 res->image = NULL;
5991 MONO_OBJECT_SETREF (res, assembly, (MonoReflectionAssembly *) mono_assembly_get_object(domain, image->assembly));
5992 name = mono_metadata_string_heap (image, cols [MONO_FILE_NAME]);
5994 /* Check whenever the row has a corresponding row in the moduleref table */
5995 table = &image->tables [MONO_TABLE_MODULEREF];
5996 for (i = 0; i < table->rows; ++i) {
5997 name_idx = mono_metadata_decode_row_col (table, i, MONO_MODULEREF_NAME);
5998 val = mono_metadata_string_heap (image, name_idx);
5999 if (strcmp (val, name) == 0)
6000 res->image = image->modules [i];
6003 MONO_OBJECT_SETREF (res, fqname, mono_string_new (domain, name));
6004 MONO_OBJECT_SETREF (res, name, mono_string_new (domain, name));
6005 MONO_OBJECT_SETREF (res, scopename, mono_string_new (domain, name));
6006 res->is_resource = cols [MONO_FILE_FLAGS] && FILE_CONTAINS_NO_METADATA;
6007 res->token = mono_metadata_make_token (MONO_TABLE_FILE, table_index + 1);
6009 return res;
6012 static gboolean
6013 mymono_metadata_type_equal (MonoType *t1, MonoType *t2)
6015 if ((t1->type != t2->type) ||
6016 (t1->byref != t2->byref))
6017 return FALSE;
6019 switch (t1->type) {
6020 case MONO_TYPE_VOID:
6021 case MONO_TYPE_BOOLEAN:
6022 case MONO_TYPE_CHAR:
6023 case MONO_TYPE_I1:
6024 case MONO_TYPE_U1:
6025 case MONO_TYPE_I2:
6026 case MONO_TYPE_U2:
6027 case MONO_TYPE_I4:
6028 case MONO_TYPE_U4:
6029 case MONO_TYPE_I8:
6030 case MONO_TYPE_U8:
6031 case MONO_TYPE_R4:
6032 case MONO_TYPE_R8:
6033 case MONO_TYPE_STRING:
6034 case MONO_TYPE_I:
6035 case MONO_TYPE_U:
6036 case MONO_TYPE_OBJECT:
6037 case MONO_TYPE_TYPEDBYREF:
6038 return TRUE;
6039 case MONO_TYPE_VALUETYPE:
6040 case MONO_TYPE_CLASS:
6041 case MONO_TYPE_SZARRAY:
6042 return t1->data.klass == t2->data.klass;
6043 case MONO_TYPE_PTR:
6044 return mymono_metadata_type_equal (t1->data.type, t2->data.type);
6045 case MONO_TYPE_ARRAY:
6046 if (t1->data.array->rank != t2->data.array->rank)
6047 return FALSE;
6048 return t1->data.array->eklass == t2->data.array->eklass;
6049 case MONO_TYPE_GENERICINST: {
6050 int i;
6051 MonoGenericInst *i1 = t1->data.generic_class->context.class_inst;
6052 MonoGenericInst *i2 = t2->data.generic_class->context.class_inst;
6053 if (i1->type_argc != i2->type_argc)
6054 return FALSE;
6055 if (!mono_metadata_type_equal (&t1->data.generic_class->container_class->byval_arg,
6056 &t2->data.generic_class->container_class->byval_arg))
6057 return FALSE;
6058 /* FIXME: we should probably just compare the instance pointers directly. */
6059 for (i = 0; i < i1->type_argc; ++i) {
6060 if (!mono_metadata_type_equal (i1->type_argv [i], i2->type_argv [i]))
6061 return FALSE;
6063 return TRUE;
6065 case MONO_TYPE_VAR:
6066 case MONO_TYPE_MVAR:
6067 return t1->data.generic_param == t2->data.generic_param;
6068 default:
6069 g_error ("implement type compare for %0x!", t1->type);
6070 return FALSE;
6073 return FALSE;
6076 static guint
6077 mymono_metadata_type_hash (MonoType *t1)
6079 guint hash;
6081 hash = t1->type;
6083 hash |= t1->byref << 6; /* do not collide with t1->type values */
6084 switch (t1->type) {
6085 case MONO_TYPE_VALUETYPE:
6086 case MONO_TYPE_CLASS:
6087 case MONO_TYPE_SZARRAY:
6088 /* check if the distribution is good enough */
6089 return ((hash << 5) - hash) ^ g_str_hash (t1->data.klass->name);
6090 case MONO_TYPE_PTR:
6091 return ((hash << 5) - hash) ^ mymono_metadata_type_hash (t1->data.type);
6092 case MONO_TYPE_GENERICINST: {
6093 int i;
6094 MonoGenericInst *inst = t1->data.generic_class->context.class_inst;
6095 hash += g_str_hash (t1->data.generic_class->container_class->name);
6096 hash *= 13;
6097 for (i = 0; i < inst->type_argc; ++i) {
6098 hash += mymono_metadata_type_hash (inst->type_argv [i]);
6099 hash *= 13;
6101 return hash;
6104 return hash;
6107 static MonoReflectionGenericClass*
6108 mono_generic_class_get_object (MonoDomain *domain, MonoType *geninst)
6110 static MonoClass *System_Reflection_MonoGenericClass;
6111 MonoReflectionGenericClass *res;
6112 MonoClass *klass, *gklass;
6114 if (!System_Reflection_MonoGenericClass) {
6115 System_Reflection_MonoGenericClass = mono_class_from_name (
6116 mono_defaults.corlib, "System.Reflection", "MonoGenericClass");
6117 g_assert (System_Reflection_MonoGenericClass);
6120 klass = mono_class_from_mono_type (geninst);
6121 gklass = klass->generic_class->container_class;
6123 mono_class_init (klass);
6125 #ifdef HAVE_SGEN_GC
6126 res = (MonoReflectionGenericClass *) mono_gc_alloc_pinned_obj (mono_class_vtable (domain, System_Reflection_MonoGenericClass), mono_class_instance_size (System_Reflection_MonoGenericClass));
6127 #else
6128 res = (MonoReflectionGenericClass *) mono_object_new (domain, System_Reflection_MonoGenericClass);
6129 #endif
6131 res->type.type = geninst;
6132 g_assert (gklass->reflection_info);
6133 g_assert (!strcmp (((MonoObject*)gklass->reflection_info)->vtable->klass->name, "TypeBuilder"));
6134 MONO_OBJECT_SETREF (res, generic_type, gklass->reflection_info);
6136 return res;
6139 static gboolean
6140 verify_safe_for_managed_space (MonoType *type)
6142 switch (type->type) {
6143 #ifdef DEBUG_HARDER
6144 case MONO_TYPE_ARRAY:
6145 return verify_safe_for_managed_space (&type->data.array->eklass->byval_arg);
6146 case MONO_TYPE_PTR:
6147 return verify_safe_for_managed_space (type->data.type);
6148 case MONO_TYPE_SZARRAY:
6149 return verify_safe_for_managed_space (&type->data.klass->byval_arg);
6150 case MONO_TYPE_GENERICINST: {
6151 MonoGenericInst *inst = type->data.generic_class->inst;
6152 int i;
6153 if (!inst->is_open)
6154 break;
6155 for (i = 0; i < inst->type_argc; ++i)
6156 if (!verify_safe_for_managed_space (inst->type_argv [i]))
6157 return FALSE;
6158 break;
6160 #endif
6161 case MONO_TYPE_VAR:
6162 case MONO_TYPE_MVAR:
6163 return TRUE;
6165 return TRUE;
6169 * mono_type_get_object:
6170 * @domain: an app domain
6171 * @type: a type
6173 * Return an System.MonoType object representing the type @type.
6175 MonoReflectionType*
6176 mono_type_get_object (MonoDomain *domain, MonoType *type)
6178 MonoReflectionType *res;
6179 MonoClass *klass = mono_class_from_mono_type (type);
6181 /*we must avoid using @type as it might have come
6182 * from a mono_metadata_type_dup and the caller
6183 * expects that is can be freed.
6184 * Using the right type from
6186 type = klass->byval_arg.byref == type->byref ? &klass->byval_arg : &klass->this_arg;
6188 /* void is very common */
6189 if (type->type == MONO_TYPE_VOID && domain->typeof_void)
6190 return (MonoReflectionType*)domain->typeof_void;
6193 * If the vtable of the given class was already created, we can use
6194 * the MonoType from there and avoid all locking and hash table lookups.
6196 * We cannot do this for TypeBuilders as mono_reflection_create_runtime_class expects
6197 * that the resulting object is different.
6199 if (type == &klass->byval_arg && !klass->image->dynamic) {
6200 MonoVTable *vtable = mono_class_try_get_vtable (domain, klass);
6201 if (vtable && vtable->type)
6202 return vtable->type;
6205 mono_loader_lock (); /*FIXME mono_class_init and mono_class_vtable acquire it*/
6206 mono_domain_lock (domain);
6207 if (!domain->type_hash)
6208 domain->type_hash = mono_g_hash_table_new_type ((GHashFunc)mymono_metadata_type_hash,
6209 (GCompareFunc)mymono_metadata_type_equal, MONO_HASH_VALUE_GC);
6210 if ((res = mono_g_hash_table_lookup (domain->type_hash, type))) {
6211 mono_domain_unlock (domain);
6212 mono_loader_unlock ();
6213 return res;
6215 /* Create a MonoGenericClass object for instantiations of not finished TypeBuilders */
6216 if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder) {
6217 res = (MonoReflectionType *)mono_generic_class_get_object (domain, type);
6218 mono_g_hash_table_insert (domain->type_hash, type, res);
6219 mono_domain_unlock (domain);
6220 mono_loader_unlock ();
6221 return res;
6224 if (!verify_safe_for_managed_space (type)) {
6225 mono_domain_unlock (domain);
6226 mono_loader_unlock ();
6227 mono_raise_exception (mono_get_exception_invalid_operation ("This type cannot be propagated to managed space"));
6230 if (klass->reflection_info && !klass->wastypebuilder) {
6231 /* g_assert_not_reached (); */
6232 /* should this be considered an error condition? */
6233 if (!type->byref) {
6234 mono_domain_unlock (domain);
6235 mono_loader_unlock ();
6236 return klass->reflection_info;
6239 // FIXME: Get rid of this, do it in the icalls for Type
6240 mono_class_init (klass);
6241 #ifdef HAVE_SGEN_GC
6242 res = (MonoReflectionType *)mono_gc_alloc_pinned_obj (mono_class_vtable (domain, mono_defaults.monotype_class), mono_class_instance_size (mono_defaults.monotype_class));
6243 #else
6244 res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class);
6245 #endif
6246 res->type = type;
6247 mono_g_hash_table_insert (domain->type_hash, type, res);
6249 if (type->type == MONO_TYPE_VOID)
6250 MONO_OBJECT_SETREF (domain, typeof_void, res);
6252 mono_domain_unlock (domain);
6253 mono_loader_unlock ();
6254 return res;
6258 * mono_method_get_object:
6259 * @domain: an app domain
6260 * @method: a method
6261 * @refclass: the reflected type (can be NULL)
6263 * Return an System.Reflection.MonoMethod object representing the method @method.
6265 MonoReflectionMethod*
6266 mono_method_get_object (MonoDomain *domain, MonoMethod *method, MonoClass *refclass)
6269 * We use the same C representation for methods and constructors, but the type
6270 * name in C# is different.
6272 static MonoClass *System_Reflection_MonoMethod = NULL;
6273 static MonoClass *System_Reflection_MonoCMethod = NULL;
6274 static MonoClass *System_Reflection_MonoGenericMethod = NULL;
6275 static MonoClass *System_Reflection_MonoGenericCMethod = NULL;
6276 MonoClass *klass;
6277 MonoReflectionMethod *ret;
6279 if (method->is_inflated) {
6280 MonoReflectionGenericMethod *gret;
6282 refclass = method->klass;
6283 CHECK_OBJECT (MonoReflectionMethod *, method, refclass);
6284 if ((*method->name == '.') && (!strcmp (method->name, ".ctor") || !strcmp (method->name, ".cctor"))) {
6285 if (!System_Reflection_MonoGenericCMethod)
6286 System_Reflection_MonoGenericCMethod = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoGenericCMethod");
6287 klass = System_Reflection_MonoGenericCMethod;
6288 } else {
6289 if (!System_Reflection_MonoGenericMethod)
6290 System_Reflection_MonoGenericMethod = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoGenericMethod");
6291 klass = System_Reflection_MonoGenericMethod;
6293 gret = (MonoReflectionGenericMethod*)mono_object_new (domain, klass);
6294 gret->method.method = method;
6295 MONO_OBJECT_SETREF (gret, method.name, mono_string_new (domain, method->name));
6296 MONO_OBJECT_SETREF (gret, method.reftype, mono_type_get_object (domain, &refclass->byval_arg));
6297 CACHE_OBJECT (MonoReflectionMethod *, method, (MonoReflectionMethod*)gret, refclass);
6300 if (!refclass)
6301 refclass = method->klass;
6303 CHECK_OBJECT (MonoReflectionMethod *, method, refclass);
6304 if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0)) {
6305 if (!System_Reflection_MonoCMethod)
6306 System_Reflection_MonoCMethod = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoCMethod");
6307 klass = System_Reflection_MonoCMethod;
6309 else {
6310 if (!System_Reflection_MonoMethod)
6311 System_Reflection_MonoMethod = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoMethod");
6312 klass = System_Reflection_MonoMethod;
6314 ret = (MonoReflectionMethod*)mono_object_new (domain, klass);
6315 ret->method = method;
6316 MONO_OBJECT_SETREF (ret, reftype, mono_type_get_object (domain, &refclass->byval_arg));
6317 CACHE_OBJECT (MonoReflectionMethod *, method, ret, refclass);
6321 * mono_method_clear_object:
6323 * Clear the cached reflection objects for the dynamic method METHOD.
6325 void
6326 mono_method_clear_object (MonoDomain *domain, MonoMethod *method)
6328 MonoClass *klass;
6329 g_assert (method->dynamic);
6331 klass = method->klass;
6332 while (klass) {
6333 clear_cached_object (domain, method, klass);
6334 klass = klass->parent;
6336 /* Added by mono_param_get_objects () */
6337 clear_cached_object (domain, &(method->signature), NULL);
6338 klass = method->klass;
6339 while (klass) {
6340 clear_cached_object (domain, &(method->signature), klass);
6341 klass = klass->parent;
6346 * mono_field_get_object:
6347 * @domain: an app domain
6348 * @klass: a type
6349 * @field: a field
6351 * Return an System.Reflection.MonoField object representing the field @field
6352 * in class @klass.
6354 MonoReflectionField*
6355 mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *field)
6357 MonoReflectionField *res;
6358 static MonoClass *monofield_klass;
6360 CHECK_OBJECT (MonoReflectionField *, field, klass);
6361 if (!monofield_klass)
6362 monofield_klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
6363 res = (MonoReflectionField *)mono_object_new (domain, monofield_klass);
6364 res->klass = klass;
6365 res->field = field;
6366 MONO_OBJECT_SETREF (res, name, mono_string_new (domain, mono_field_get_name (field)));
6367 if (is_field_on_inst (field))
6368 res->attrs = get_field_on_inst_generic_type (field)->attrs;
6369 else
6370 res->attrs = field->type->attrs;
6371 MONO_OBJECT_SETREF (res, type, mono_type_get_object (domain, field->type));
6372 CACHE_OBJECT (MonoReflectionField *, field, res, klass);
6376 * mono_property_get_object:
6377 * @domain: an app domain
6378 * @klass: a type
6379 * @property: a property
6381 * Return an System.Reflection.MonoProperty object representing the property @property
6382 * in class @klass.
6384 MonoReflectionProperty*
6385 mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *property)
6387 MonoReflectionProperty *res;
6388 static MonoClass *monoproperty_klass;
6390 CHECK_OBJECT (MonoReflectionProperty *, property, klass);
6391 if (!monoproperty_klass)
6392 monoproperty_klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
6393 res = (MonoReflectionProperty *)mono_object_new (domain, monoproperty_klass);
6394 res->klass = klass;
6395 res->property = property;
6396 CACHE_OBJECT (MonoReflectionProperty *, property, res, klass);
6400 * mono_event_get_object:
6401 * @domain: an app domain
6402 * @klass: a type
6403 * @event: a event
6405 * Return an System.Reflection.MonoEvent object representing the event @event
6406 * in class @klass.
6408 MonoReflectionEvent*
6409 mono_event_get_object (MonoDomain *domain, MonoClass *klass, MonoEvent *event)
6411 MonoReflectionEvent *res;
6412 MonoReflectionMonoEvent *mono_event;
6413 static MonoClass *monoevent_klass;
6415 CHECK_OBJECT (MonoReflectionEvent *, event, klass);
6416 if (!monoevent_klass)
6417 monoevent_klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoEvent");
6418 mono_event = (MonoReflectionMonoEvent *)mono_object_new (domain, monoevent_klass);
6419 mono_event->klass = klass;
6420 mono_event->event = event;
6421 res = (MonoReflectionEvent*)mono_event;
6422 CACHE_OBJECT (MonoReflectionEvent *, event, res, klass);
6426 * mono_get_reflection_missing_object:
6427 * @domain: Domain where the object lives
6429 * Returns the System.Reflection.Missing.Value singleton object
6430 * (of type System.Reflection.Missing).
6432 * Used as the value for ParameterInfo.DefaultValue when Optional
6433 * is present
6435 static MonoObject *
6436 mono_get_reflection_missing_object (MonoDomain *domain)
6438 MonoObject *obj;
6439 static MonoClassField *missing_value_field = NULL;
6441 if (!missing_value_field) {
6442 MonoClass *missing_klass;
6443 missing_klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "Missing");
6444 mono_class_init (missing_klass);
6445 missing_value_field = mono_class_get_field_from_name (missing_klass, "Value");
6446 g_assert (missing_value_field);
6448 obj = mono_field_get_value_object (domain, missing_value_field, NULL);
6449 g_assert (obj);
6450 return obj;
6453 static MonoObject*
6454 get_dbnull (MonoDomain *domain, MonoObject **dbnull)
6456 if (!*dbnull)
6457 *dbnull = mono_get_dbnull_object (domain);
6458 return *dbnull;
6461 static MonoObject*
6462 get_reflection_missing (MonoDomain *domain, MonoObject **reflection_missing)
6464 if (!*reflection_missing)
6465 *reflection_missing = mono_get_reflection_missing_object (domain);
6466 return *reflection_missing;
6470 * mono_param_get_objects:
6471 * @domain: an app domain
6472 * @method: a method
6474 * Return an System.Reflection.ParameterInfo array object representing the parameters
6475 * in the method @method.
6477 MonoArray*
6478 mono_param_get_objects_internal (MonoDomain *domain, MonoMethod *method, MonoClass *refclass)
6480 static MonoClass *System_Reflection_ParameterInfo;
6481 static MonoClass *System_Reflection_ParameterInfo_array;
6482 MonoArray *res = NULL;
6483 MonoReflectionMethod *member = NULL;
6484 MonoReflectionParameter *param = NULL;
6485 char **names, **blobs = NULL;
6486 guint32 *types = NULL;
6487 MonoType *type = NULL;
6488 MonoObject *dbnull = NULL;
6489 MonoObject *missing = NULL;
6490 MonoMarshalSpec **mspecs;
6491 MonoMethodSignature *sig;
6492 MonoVTable *pinfo_vtable;
6493 int i;
6495 if (!System_Reflection_ParameterInfo_array) {
6496 MonoClass *klass;
6498 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
6499 mono_memory_barrier ();
6500 System_Reflection_ParameterInfo = klass;
6502 klass = mono_array_class_get (klass, 1);
6503 mono_memory_barrier ();
6504 System_Reflection_ParameterInfo_array = klass;
6507 if (!mono_method_signature (method)->param_count)
6508 return mono_array_new_specific (mono_class_vtable (domain, System_Reflection_ParameterInfo_array), 0);
6510 /* Note: the cache is based on the address of the signature into the method
6511 * since we already cache MethodInfos with the method as keys.
6513 CHECK_OBJECT (MonoArray*, &(method->signature), refclass);
6515 sig = mono_method_signature (method);
6516 member = mono_method_get_object (domain, method, refclass);
6517 names = g_new (char *, sig->param_count);
6518 mono_method_get_param_names (method, (const char **) names);
6520 mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
6521 mono_method_get_marshal_info (method, mspecs);
6523 res = mono_array_new_specific (mono_class_vtable (domain, System_Reflection_ParameterInfo_array), sig->param_count);
6524 pinfo_vtable = mono_class_vtable (domain, System_Reflection_ParameterInfo);
6525 for (i = 0; i < sig->param_count; ++i) {
6526 param = (MonoReflectionParameter *)mono_object_new_specific (pinfo_vtable);
6527 MONO_OBJECT_SETREF (param, ClassImpl, mono_type_get_object (domain, sig->params [i]));
6528 MONO_OBJECT_SETREF (param, MemberImpl, (MonoObject*)member);
6529 MONO_OBJECT_SETREF (param, NameImpl, mono_string_new (domain, names [i]));
6530 param->PositionImpl = i;
6531 param->AttrsImpl = sig->params [i]->attrs;
6533 if (!(param->AttrsImpl & PARAM_ATTRIBUTE_HAS_DEFAULT)) {
6534 if (param->AttrsImpl & PARAM_ATTRIBUTE_OPTIONAL)
6535 MONO_OBJECT_SETREF (param, DefaultValueImpl, get_reflection_missing (domain, &missing));
6536 else
6537 MONO_OBJECT_SETREF (param, DefaultValueImpl, get_dbnull (domain, &dbnull));
6538 } else {
6540 if (!blobs) {
6541 blobs = g_new0 (char *, sig->param_count);
6542 types = g_new0 (guint32, sig->param_count);
6543 get_default_param_value_blobs (method, blobs, types);
6546 /* Build MonoType for the type from the Constant Table */
6547 if (!type)
6548 type = g_new0 (MonoType, 1);
6549 type->type = types [i];
6550 type->data.klass = NULL;
6551 if (types [i] == MONO_TYPE_CLASS)
6552 type->data.klass = mono_defaults.object_class;
6553 else if ((sig->params [i]->type == MONO_TYPE_VALUETYPE) && sig->params [i]->data.klass->enumtype) {
6554 /* For enums, types [i] contains the base type */
6556 type->type = MONO_TYPE_VALUETYPE;
6557 type->data.klass = mono_class_from_mono_type (sig->params [i]);
6558 } else
6559 type->data.klass = mono_class_from_mono_type (type);
6561 MONO_OBJECT_SETREF (param, DefaultValueImpl, mono_get_object_from_blob (domain, type, blobs [i]));
6563 /* Type in the Constant table is MONO_TYPE_CLASS for nulls */
6564 if (types [i] != MONO_TYPE_CLASS && !param->DefaultValueImpl) {
6565 if (param->AttrsImpl & PARAM_ATTRIBUTE_OPTIONAL)
6566 MONO_OBJECT_SETREF (param, DefaultValueImpl, get_reflection_missing (domain, &missing));
6567 else
6568 MONO_OBJECT_SETREF (param, DefaultValueImpl, get_dbnull (domain, &dbnull));
6573 if (mspecs [i + 1])
6574 MONO_OBJECT_SETREF (param, MarshalAsImpl, (MonoObject*)mono_reflection_marshal_from_marshal_spec (domain, method->klass, mspecs [i + 1]));
6576 mono_array_setref (res, i, param);
6578 g_free (names);
6579 g_free (blobs);
6580 g_free (types);
6581 g_free (type);
6583 for (i = mono_method_signature (method)->param_count; i >= 0; i--)
6584 if (mspecs [i])
6585 mono_metadata_free_marshal_spec (mspecs [i]);
6586 g_free (mspecs);
6588 CACHE_OBJECT (MonoArray *, &(method->signature), res, refclass);
6591 MonoArray*
6592 mono_param_get_objects (MonoDomain *domain, MonoMethod *method)
6594 return mono_param_get_objects_internal (domain, method, NULL);
6598 * mono_method_body_get_object:
6599 * @domain: an app domain
6600 * @method: a method
6602 * Return an System.Reflection.MethodBody object representing the method @method.
6604 MonoReflectionMethodBody*
6605 mono_method_body_get_object (MonoDomain *domain, MonoMethod *method)
6607 static MonoClass *System_Reflection_MethodBody = NULL;
6608 static MonoClass *System_Reflection_LocalVariableInfo = NULL;
6609 static MonoClass *System_Reflection_ExceptionHandlingClause = NULL;
6610 MonoReflectionMethodBody *ret;
6611 MonoMethodNormal *mn;
6612 MonoMethodHeader *header;
6613 guint32 method_rva, local_var_sig_token;
6614 char *ptr;
6615 unsigned char format, flags;
6616 int i;
6618 if (!System_Reflection_MethodBody)
6619 System_Reflection_MethodBody = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MethodBody");
6620 if (!System_Reflection_LocalVariableInfo)
6621 System_Reflection_LocalVariableInfo = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "LocalVariableInfo");
6622 if (!System_Reflection_ExceptionHandlingClause)
6623 System_Reflection_ExceptionHandlingClause = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ExceptionHandlingClause");
6625 CHECK_OBJECT (MonoReflectionMethodBody *, method, NULL);
6627 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
6628 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
6629 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6630 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME))
6631 return NULL;
6632 mn = (MonoMethodNormal *)method;
6633 header = mono_method_get_header (method);
6635 /* Obtain local vars signature token */
6636 method_rva = mono_metadata_decode_row_col (&method->klass->image->tables [MONO_TABLE_METHOD], mono_metadata_token_index (method->token) - 1, MONO_METHOD_RVA);
6637 ptr = mono_image_rva_map (method->klass->image, method_rva);
6638 flags = *(const unsigned char *) ptr;
6639 format = flags & METHOD_HEADER_FORMAT_MASK;
6640 switch (format){
6641 case METHOD_HEADER_TINY_FORMAT:
6642 case METHOD_HEADER_TINY_FORMAT1:
6643 local_var_sig_token = 0;
6644 break;
6645 case METHOD_HEADER_FAT_FORMAT:
6646 ptr += 2;
6647 ptr += 2;
6648 ptr += 4;
6649 local_var_sig_token = read32 (ptr);
6650 break;
6651 default:
6652 g_assert_not_reached ();
6655 ret = (MonoReflectionMethodBody*)mono_object_new (domain, System_Reflection_MethodBody);
6657 ret->init_locals = header->init_locals;
6658 ret->max_stack = header->max_stack;
6659 ret->local_var_sig_token = local_var_sig_token;
6660 MONO_OBJECT_SETREF (ret, il, mono_array_new_cached (domain, mono_defaults.byte_class, header->code_size));
6661 memcpy (mono_array_addr (ret->il, guint8, 0), header->code, header->code_size);
6663 /* Locals */
6664 MONO_OBJECT_SETREF (ret, locals, mono_array_new_cached (domain, System_Reflection_LocalVariableInfo, header->num_locals));
6665 for (i = 0; i < header->num_locals; ++i) {
6666 MonoReflectionLocalVariableInfo *info = (MonoReflectionLocalVariableInfo*)mono_object_new (domain, System_Reflection_LocalVariableInfo);
6667 MONO_OBJECT_SETREF (info, local_type, mono_type_get_object (domain, header->locals [i]));
6668 info->is_pinned = header->locals [i]->pinned;
6669 info->local_index = i;
6670 mono_array_setref (ret->locals, i, info);
6673 /* Exceptions */
6674 MONO_OBJECT_SETREF (ret, clauses, mono_array_new_cached (domain, System_Reflection_ExceptionHandlingClause, header->num_clauses));
6675 for (i = 0; i < header->num_clauses; ++i) {
6676 MonoReflectionExceptionHandlingClause *info = (MonoReflectionExceptionHandlingClause*)mono_object_new (domain, System_Reflection_ExceptionHandlingClause);
6677 MonoExceptionClause *clause = &header->clauses [i];
6679 info->flags = clause->flags;
6680 info->try_offset = clause->try_offset;
6681 info->try_length = clause->try_len;
6682 info->handler_offset = clause->handler_offset;
6683 info->handler_length = clause->handler_len;
6684 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
6685 info->filter_offset = clause->data.filter_offset;
6686 else if (clause->data.catch_class)
6687 MONO_OBJECT_SETREF (info, catch_type, mono_type_get_object (mono_domain_get (), &clause->data.catch_class->byval_arg));
6689 mono_array_setref (ret->clauses, i, info);
6692 CACHE_OBJECT (MonoReflectionMethodBody *, method, ret, NULL);
6693 return ret;
6697 * mono_get_dbnull_object:
6698 * @domain: Domain where the object lives
6700 * Returns the System.DBNull.Value singleton object
6702 * Used as the value for ParameterInfo.DefaultValue
6704 MonoObject *
6705 mono_get_dbnull_object (MonoDomain *domain)
6707 MonoObject *obj;
6708 static MonoClassField *dbnull_value_field = NULL;
6710 if (!dbnull_value_field) {
6711 MonoClass *dbnull_klass;
6712 dbnull_klass = mono_class_from_name (mono_defaults.corlib, "System", "DBNull");
6713 mono_class_init (dbnull_klass);
6714 dbnull_value_field = mono_class_get_field_from_name (dbnull_klass, "Value");
6715 g_assert (dbnull_value_field);
6717 obj = mono_field_get_value_object (domain, dbnull_value_field, NULL);
6718 g_assert (obj);
6719 return obj;
6722 static void
6723 get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types)
6725 guint32 param_index, i, lastp, crow = 0;
6726 guint32 param_cols [MONO_PARAM_SIZE], const_cols [MONO_CONSTANT_SIZE];
6727 gint32 idx;
6729 MonoClass *klass = method->klass;
6730 MonoImage *image = klass->image;
6731 MonoMethodSignature *methodsig = mono_method_signature (method);
6733 MonoTableInfo *constt;
6734 MonoTableInfo *methodt;
6735 MonoTableInfo *paramt;
6737 if (!methodsig->param_count)
6738 return;
6740 mono_class_init (klass);
6742 if (klass->image->dynamic) {
6743 MonoReflectionMethodAux *aux;
6744 if (method->is_inflated)
6745 method = ((MonoMethodInflated*)method)->declaring;
6746 aux = g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
6747 if (aux && aux->param_defaults) {
6748 memcpy (blobs, &(aux->param_defaults [1]), methodsig->param_count * sizeof (char*));
6749 memcpy (types, &(aux->param_default_types [1]), methodsig->param_count * sizeof (guint32));
6751 return;
6754 methodt = &klass->image->tables [MONO_TABLE_METHOD];
6755 paramt = &klass->image->tables [MONO_TABLE_PARAM];
6756 constt = &image->tables [MONO_TABLE_CONSTANT];
6758 idx = mono_method_get_index (method) - 1;
6759 g_assert (idx != -1);
6761 param_index = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
6762 if (idx + 1 < methodt->rows)
6763 lastp = mono_metadata_decode_row_col (methodt, idx + 1, MONO_METHOD_PARAMLIST);
6764 else
6765 lastp = paramt->rows + 1;
6767 for (i = param_index; i < lastp; ++i) {
6768 guint32 paramseq;
6770 mono_metadata_decode_row (paramt, i - 1, param_cols, MONO_PARAM_SIZE);
6771 paramseq = param_cols [MONO_PARAM_SEQUENCE];
6773 if (!param_cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_DEFAULT)
6774 continue;
6776 crow = mono_metadata_get_constant_index (image, MONO_TOKEN_PARAM_DEF | i, crow + 1);
6777 if (!crow) {
6778 continue;
6781 mono_metadata_decode_row (constt, crow - 1, const_cols, MONO_CONSTANT_SIZE);
6782 blobs [paramseq - 1] = (gpointer) mono_metadata_blob_heap (image, const_cols [MONO_CONSTANT_VALUE]);
6783 types [paramseq - 1] = const_cols [MONO_CONSTANT_TYPE];
6786 return;
6789 static MonoObject *
6790 mono_get_object_from_blob (MonoDomain *domain, MonoType *type, const char *blob)
6792 void *retval;
6793 MonoClass *klass;
6794 MonoObject *object;
6795 MonoType *basetype = type;
6797 if (!blob)
6798 return NULL;
6800 klass = mono_class_from_mono_type (type);
6801 if (klass->valuetype) {
6802 object = mono_object_new (domain, klass);
6803 retval = ((gchar *) object + sizeof (MonoObject));
6804 if (klass->enumtype)
6805 basetype = mono_class_enum_basetype (klass);
6806 } else {
6807 retval = &object;
6810 if (!mono_get_constant_value_from_blob (domain, basetype->type, blob, retval))
6811 return object;
6812 else
6813 return NULL;
6816 static int
6817 assembly_name_to_aname (MonoAssemblyName *assembly, char *p) {
6818 int found_sep;
6819 char *s;
6821 memset (assembly, 0, sizeof (MonoAssemblyName));
6822 assembly->name = p;
6823 assembly->culture = "";
6824 memset (assembly->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
6826 while (*p && (isalnum (*p) || *p == '.' || *p == '-' || *p == '_' || *p == '$' || *p == '@'))
6827 p++;
6828 found_sep = 0;
6829 while (g_ascii_isspace (*p) || *p == ',') {
6830 *p++ = 0;
6831 found_sep = 1;
6832 continue;
6834 /* failed */
6835 if (!found_sep)
6836 return 1;
6837 while (*p) {
6838 if (*p == 'V' && g_ascii_strncasecmp (p, "Version=", 8) == 0) {
6839 p += 8;
6840 assembly->major = strtoul (p, &s, 10);
6841 if (s == p || *s != '.')
6842 return 1;
6843 p = ++s;
6844 assembly->minor = strtoul (p, &s, 10);
6845 if (s == p || *s != '.')
6846 return 1;
6847 p = ++s;
6848 assembly->build = strtoul (p, &s, 10);
6849 if (s == p || *s != '.')
6850 return 1;
6851 p = ++s;
6852 assembly->revision = strtoul (p, &s, 10);
6853 if (s == p)
6854 return 1;
6855 p = s;
6856 } else if (*p == 'C' && g_ascii_strncasecmp (p, "Culture=", 8) == 0) {
6857 p += 8;
6858 if (g_ascii_strncasecmp (p, "neutral", 7) == 0) {
6859 assembly->culture = "";
6860 p += 7;
6861 } else {
6862 assembly->culture = p;
6863 while (*p && *p != ',') {
6864 p++;
6867 } else if (*p == 'P' && g_ascii_strncasecmp (p, "PublicKeyToken=", 15) == 0) {
6868 p += 15;
6869 if (strncmp (p, "null", 4) == 0) {
6870 p += 4;
6871 } else {
6872 int len;
6873 gchar *start = p;
6874 while (*p && *p != ',') {
6875 p++;
6877 len = (p - start + 1);
6878 if (len > MONO_PUBLIC_KEY_TOKEN_LENGTH)
6879 len = MONO_PUBLIC_KEY_TOKEN_LENGTH;
6880 g_strlcpy ((char*)assembly->public_key_token, start, len);
6882 } else {
6883 while (*p && *p != ',')
6884 p++;
6886 found_sep = 0;
6887 while (g_ascii_isspace (*p) || *p == ',') {
6888 *p++ = 0;
6889 found_sep = 1;
6890 continue;
6892 /* failed */
6893 if (!found_sep)
6894 return 1;
6897 return 0;
6901 * mono_reflection_parse_type:
6902 * @name: type name
6904 * Parse a type name as accepted by the GetType () method and output the info
6905 * extracted in the info structure.
6906 * the name param will be mangled, so, make a copy before passing it to this function.
6907 * The fields in info will be valid until the memory pointed to by name is valid.
6909 * See also mono_type_get_name () below.
6911 * Returns: 0 on parse error.
6913 static int
6914 _mono_reflection_parse_type (char *name, char **endptr, gboolean is_recursed,
6915 MonoTypeNameParse *info)
6917 char *start, *p, *w, *temp, *last_point, *startn;
6918 int in_modifiers = 0;
6919 int isbyref = 0, rank, arity = 0, i;
6921 start = p = w = name;
6923 //FIXME could we just zero the whole struct? memset (&info, 0, sizeof (MonoTypeNameParse))
6924 memset (&info->assembly, 0, sizeof (MonoAssemblyName));
6925 info->name = info->name_space = NULL;
6926 info->nested = NULL;
6927 info->modifiers = NULL;
6928 info->type_arguments = NULL;
6930 /* last_point separates the namespace from the name */
6931 last_point = NULL;
6932 /* Skips spaces */
6933 while (*p == ' ') p++, start++, w++, name++;
6935 while (*p) {
6936 switch (*p) {
6937 case '+':
6938 *p = 0; /* NULL terminate the name */
6939 startn = p + 1;
6940 info->nested = g_list_append (info->nested, startn);
6941 /* we have parsed the nesting namespace + name */
6942 if (info->name)
6943 break;
6944 if (last_point) {
6945 info->name_space = start;
6946 *last_point = 0;
6947 info->name = last_point + 1;
6948 } else {
6949 info->name_space = (char *)"";
6950 info->name = start;
6952 break;
6953 case '.':
6954 last_point = p;
6955 break;
6956 case '\\':
6957 ++p;
6958 break;
6959 case '&':
6960 case '*':
6961 case '[':
6962 case ',':
6963 case ']':
6964 in_modifiers = 1;
6965 break;
6966 case '`':
6967 ++p;
6968 i = strtol (p, &temp, 10);
6969 arity += i;
6970 if (p == temp)
6971 return 0;
6972 p = temp-1;
6973 break;
6974 default:
6975 break;
6977 if (in_modifiers)
6978 break;
6979 // *w++ = *p++;
6980 p++;
6983 if (!info->name) {
6984 if (last_point) {
6985 info->name_space = start;
6986 *last_point = 0;
6987 info->name = last_point + 1;
6988 } else {
6989 info->name_space = (char *)"";
6990 info->name = start;
6993 while (*p) {
6994 switch (*p) {
6995 case '&':
6996 if (isbyref) /* only one level allowed by the spec */
6997 return 0;
6998 isbyref = 1;
6999 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (0));
7000 *p++ = 0;
7001 break;
7002 case '*':
7003 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-1));
7004 *p++ = 0;
7005 break;
7006 case '[':
7007 if (arity != 0) {
7008 *p++ = 0;
7009 info->type_arguments = g_ptr_array_new ();
7010 for (i = 0; i < arity; i++) {
7011 MonoTypeNameParse *subinfo = g_new0 (MonoTypeNameParse, 1);
7012 gboolean fqname = FALSE;
7014 g_ptr_array_add (info->type_arguments, subinfo);
7016 if (*p == '[') {
7017 p++;
7018 fqname = TRUE;
7021 if (!_mono_reflection_parse_type (p, &p, TRUE, subinfo))
7022 return 0;
7024 if (fqname) {
7025 char *aname;
7027 if (*p != ',')
7028 return 0;
7029 *p++ = 0;
7031 aname = p;
7032 while (*p && (*p != ']'))
7033 p++;
7035 if (*p != ']')
7036 return 0;
7038 *p++ = 0;
7039 while (*aname) {
7040 if (g_ascii_isspace (*aname)) {
7041 ++aname;
7042 continue;
7044 break;
7046 if (!*aname ||
7047 !assembly_name_to_aname (&subinfo->assembly, aname))
7048 return 0;
7051 if (i + 1 < arity) {
7052 if (*p != ',')
7053 return 0;
7054 } else {
7055 if (*p != ']')
7056 return 0;
7058 *p++ = 0;
7061 arity = 0;
7062 break;
7064 rank = 1;
7065 *p++ = 0;
7066 while (*p) {
7067 if (*p == ']')
7068 break;
7069 if (*p == ',')
7070 rank++;
7071 else if (*p == '*') /* '*' means unknown lower bound */
7072 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-2));
7073 else
7074 return 0;
7075 ++p;
7077 if (*p++ != ']')
7078 return 0;
7079 info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank));
7080 break;
7081 case ']':
7082 if (is_recursed)
7083 goto end;
7084 return 0;
7085 case ',':
7086 if (is_recursed)
7087 goto end;
7088 *p++ = 0;
7089 while (*p) {
7090 if (g_ascii_isspace (*p)) {
7091 ++p;
7092 continue;
7094 break;
7096 if (!*p)
7097 return 0; /* missing assembly name */
7098 if (!assembly_name_to_aname (&info->assembly, p))
7099 return 0;
7100 break;
7101 default:
7102 return 0;
7104 if (info->assembly.name)
7105 break;
7107 // *w = 0; /* terminate class name */
7108 end:
7109 if (!info->name || !*info->name)
7110 return 0;
7111 if (endptr)
7112 *endptr = p;
7113 /* add other consistency checks */
7114 return 1;
7118 mono_reflection_parse_type (char *name, MonoTypeNameParse *info)
7120 return _mono_reflection_parse_type (name, NULL, FALSE, info);
7123 static MonoType*
7124 _mono_reflection_get_type_from_info (MonoTypeNameParse *info, MonoImage *image, gboolean ignorecase)
7126 gboolean type_resolve = FALSE;
7127 MonoType *type;
7128 MonoImage *rootimage = image;
7130 if (info->assembly.name) {
7131 MonoAssembly *assembly = mono_assembly_loaded (&info->assembly);
7132 if (!assembly && image && image->assembly && mono_assembly_names_equal (&info->assembly, &image->assembly->aname))
7134 * This could happen in the AOT compiler case when the search hook is not
7135 * installed.
7137 assembly = image->assembly;
7138 if (!assembly) {
7139 /* then we must load the assembly ourselve - see #60439 */
7140 assembly = mono_assembly_load (&info->assembly, NULL, NULL);
7141 if (!assembly)
7142 return NULL;
7144 image = assembly->image;
7145 } else if (!image) {
7146 image = mono_defaults.corlib;
7149 type = mono_reflection_get_type_with_rootimage (rootimage, image, info, ignorecase, &type_resolve);
7150 if (type == NULL && !info->assembly.name && image != mono_defaults.corlib) {
7151 image = mono_defaults.corlib;
7152 type = mono_reflection_get_type_with_rootimage (rootimage, image, info, ignorecase, &type_resolve);
7155 return type;
7158 static MonoType*
7159 mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase)
7161 MonoClass *klass;
7162 GList *mod;
7163 int modval;
7164 gboolean bounded = FALSE;
7166 if (!image)
7167 image = mono_defaults.corlib;
7169 if (ignorecase)
7170 klass = mono_class_from_name_case (image, info->name_space, info->name);
7171 else
7172 klass = mono_class_from_name (image, info->name_space, info->name);
7173 if (!klass)
7174 return NULL;
7175 for (mod = info->nested; mod; mod = mod->next) {
7176 gpointer iter = NULL;
7177 MonoClass *parent;
7179 parent = klass;
7180 mono_class_init (parent);
7182 while ((klass = mono_class_get_nested_types (parent, &iter))) {
7183 if (ignorecase) {
7184 if (g_strcasecmp (klass->name, mod->data) == 0)
7185 break;
7186 } else {
7187 if (strcmp (klass->name, mod->data) == 0)
7188 break;
7191 if (!klass)
7192 break;
7194 if (!klass)
7195 return NULL;
7196 mono_class_init (klass);
7198 if (info->type_arguments) {
7199 MonoType **type_args = g_new0 (MonoType *, info->type_arguments->len);
7200 MonoReflectionType *the_type;
7201 MonoType *instance;
7202 int i;
7204 for (i = 0; i < info->type_arguments->len; i++) {
7205 MonoTypeNameParse *subinfo = g_ptr_array_index (info->type_arguments, i);
7207 type_args [i] = _mono_reflection_get_type_from_info (subinfo, rootimage, ignorecase);
7208 if (!type_args [i]) {
7209 g_free (type_args);
7210 return NULL;
7214 the_type = mono_type_get_object (mono_domain_get (), &klass->byval_arg);
7216 instance = mono_reflection_bind_generic_parameters (
7217 the_type, info->type_arguments->len, type_args);
7219 g_free (type_args);
7220 if (!instance)
7221 return NULL;
7223 klass = mono_class_from_mono_type (instance);
7226 for (mod = info->modifiers; mod; mod = mod->next) {
7227 modval = GPOINTER_TO_UINT (mod->data);
7228 if (!modval) { /* byref: must be last modifier */
7229 return &klass->this_arg;
7230 } else if (modval == -1) {
7231 klass = mono_ptr_class_get (&klass->byval_arg);
7232 } else if (modval == -2) {
7233 bounded = TRUE;
7234 } else { /* array rank */
7235 klass = mono_bounded_array_class_get (klass, modval, bounded);
7237 mono_class_init (klass);
7240 return &klass->byval_arg;
7244 * mono_reflection_get_type:
7245 * @image: a metadata context
7246 * @info: type description structure
7247 * @ignorecase: flag for case-insensitive string compares
7248 * @type_resolve: whenever type resolve was already tried
7250 * Build a MonoType from the type description in @info.
7254 MonoType*
7255 mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve) {
7256 return mono_reflection_get_type_with_rootimage(image, image, info, ignorecase, type_resolve);
7259 static MonoType*
7260 mono_reflection_get_type_internal_dynamic (MonoImage *rootimage, MonoAssembly *assembly, MonoTypeNameParse *info, gboolean ignorecase)
7262 MonoReflectionAssemblyBuilder *abuilder = (MonoReflectionAssemblyBuilder*)mono_assembly_get_object (mono_domain_get (), assembly);
7263 MonoType *type;
7264 int i;
7266 g_assert (assembly->dynamic);
7268 /* Enumerate all modules */
7270 type = NULL;
7271 if (abuilder->modules) {
7272 for (i = 0; i < mono_array_length (abuilder->modules); ++i) {
7273 MonoReflectionModuleBuilder *mb = mono_array_get (abuilder->modules, MonoReflectionModuleBuilder*, i);
7274 type = mono_reflection_get_type_internal (rootimage, &mb->dynamic_image->image, info, ignorecase);
7275 if (type)
7276 break;
7280 if (!type && abuilder->loaded_modules) {
7281 for (i = 0; i < mono_array_length (abuilder->loaded_modules); ++i) {
7282 MonoReflectionModule *mod = mono_array_get (abuilder->loaded_modules, MonoReflectionModule*, i);
7283 type = mono_reflection_get_type_internal (rootimage, mod->image, info, ignorecase);
7284 if (type)
7285 break;
7289 return type;
7292 MonoType*
7293 mono_reflection_get_type_with_rootimage (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase, gboolean *type_resolve)
7295 MonoType *type;
7296 MonoReflectionAssembly *assembly;
7297 GString *fullName;
7298 GList *mod;
7300 if (image && image->dynamic)
7301 type = mono_reflection_get_type_internal_dynamic (rootimage, image->assembly, info, ignorecase);
7302 else
7303 type = mono_reflection_get_type_internal (rootimage, image, info, ignorecase);
7304 if (type)
7305 return type;
7306 if (!mono_domain_has_type_resolve (mono_domain_get ()))
7307 return NULL;
7309 if (type_resolve) {
7310 if (*type_resolve)
7311 return NULL;
7312 else
7313 *type_resolve = TRUE;
7316 /* Reconstruct the type name */
7317 fullName = g_string_new ("");
7318 if (info->name_space && (info->name_space [0] != '\0'))
7319 g_string_printf (fullName, "%s.%s", info->name_space, info->name);
7320 else
7321 g_string_printf (fullName, info->name);
7322 for (mod = info->nested; mod; mod = mod->next)
7323 g_string_append_printf (fullName, "+%s", (char*)mod->data);
7325 assembly = mono_domain_try_type_resolve ( mono_domain_get (), fullName->str, NULL);
7326 if (assembly) {
7327 if (assembly->assembly->dynamic)
7328 type = mono_reflection_get_type_internal_dynamic (rootimage, assembly->assembly, info, ignorecase);
7329 else
7330 type = mono_reflection_get_type_internal (rootimage, assembly->assembly->image,
7331 info, ignorecase);
7333 g_string_free (fullName, TRUE);
7334 return type;
7337 void
7338 mono_reflection_free_type_info (MonoTypeNameParse *info)
7340 g_list_free (info->modifiers);
7341 g_list_free (info->nested);
7343 if (info->type_arguments) {
7344 int i;
7346 for (i = 0; i < info->type_arguments->len; i++) {
7347 MonoTypeNameParse *subinfo = g_ptr_array_index (info->type_arguments, i);
7349 mono_reflection_free_type_info (subinfo);
7350 /*We free the subinfo since it is allocated by _mono_reflection_parse_type*/
7351 g_free (subinfo);
7354 g_ptr_array_free (info->type_arguments, TRUE);
7359 * mono_reflection_type_from_name:
7360 * @name: type name.
7361 * @image: a metadata context (can be NULL).
7363 * Retrieves a MonoType from its @name. If the name is not fully qualified,
7364 * it defaults to get the type from @image or, if @image is NULL or loading
7365 * from it fails, uses corlib.
7368 MonoType*
7369 mono_reflection_type_from_name (char *name, MonoImage *image)
7371 MonoType *type = NULL;
7372 MonoTypeNameParse info;
7373 char *tmp;
7375 /* Make a copy since parse_type modifies its argument */
7376 tmp = g_strdup (name);
7378 /*g_print ("requested type %s\n", str);*/
7379 if (mono_reflection_parse_type (tmp, &info)) {
7380 type = _mono_reflection_get_type_from_info (&info, image, FALSE);
7383 g_free (tmp);
7384 mono_reflection_free_type_info (&info);
7385 return type;
7389 * mono_reflection_get_token:
7391 * Return the metadata token of OBJ which should be an object
7392 * representing a metadata element.
7394 guint32
7395 mono_reflection_get_token (MonoObject *obj)
7397 MonoClass *klass;
7398 guint32 token = 0;
7400 klass = obj->vtable->klass;
7402 if (strcmp (klass->name, "MethodBuilder") == 0) {
7403 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
7405 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
7406 } else if (strcmp (klass->name, "ConstructorBuilder") == 0) {
7407 MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
7409 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
7410 } else if (strcmp (klass->name, "FieldBuilder") == 0) {
7411 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)obj;
7413 /* Call mono_image_create_token so the object gets added to the tokens hash table */
7414 token = mono_image_create_token (((MonoReflectionTypeBuilder*)fb->typeb)->module->dynamic_image, obj, FALSE, TRUE);
7415 } else if (strcmp (klass->name, "TypeBuilder") == 0) {
7416 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
7417 token = tb->table_idx | MONO_TOKEN_TYPE_DEF;
7418 } else if (strcmp (klass->name, "MonoType") == 0) {
7419 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
7420 token = mono_class_from_mono_type (type)->type_token;
7421 } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
7422 strcmp (klass->name, "MonoMethod") == 0 ||
7423 strcmp (klass->name, "MonoGenericMethod") == 0 ||
7424 strcmp (klass->name, "MonoGenericCMethod") == 0) {
7425 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
7426 if (m->method->is_inflated) {
7427 MonoMethodInflated *inflated = (MonoMethodInflated *) m->method;
7428 return inflated->declaring->token;
7429 } else {
7430 token = m->method->token;
7432 } else if (strcmp (klass->name, "MonoField") == 0) {
7433 MonoReflectionField *f = (MonoReflectionField*)obj;
7435 if (is_field_on_inst (f->field)) {
7436 MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass*)f->field->parent->generic_class;
7437 int field_index = f->field - dgclass->fields;
7438 MonoObject *obj;
7440 g_assert (field_index >= 0 && field_index < dgclass->count_fields);
7441 obj = dgclass->field_objects [field_index];
7442 return mono_reflection_get_token (obj);
7444 token = mono_class_get_field_token (f->field);
7445 } else if (strcmp (klass->name, "MonoProperty") == 0) {
7446 MonoReflectionProperty *p = (MonoReflectionProperty*)obj;
7448 token = mono_class_get_property_token (p->property);
7449 } else if (strcmp (klass->name, "MonoEvent") == 0) {
7450 MonoReflectionMonoEvent *p = (MonoReflectionMonoEvent*)obj;
7452 token = mono_class_get_event_token (p->event);
7453 } else if (strcmp (klass->name, "ParameterInfo") == 0) {
7454 MonoReflectionParameter *p = (MonoReflectionParameter*)obj;
7456 token = mono_method_get_param_token (((MonoReflectionMethod*)p->MemberImpl)->method, p->PositionImpl);
7457 } else if (strcmp (klass->name, "Module") == 0) {
7458 MonoReflectionModule *m = (MonoReflectionModule*)obj;
7460 token = m->token;
7461 } else if (strcmp (klass->name, "Assembly") == 0) {
7462 token = mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1);
7463 } else {
7464 gchar *msg = g_strdup_printf ("MetadataToken is not supported for type '%s.%s'", klass->name_space, klass->name);
7465 MonoException *ex = mono_get_exception_not_implemented (msg);
7466 g_free (msg);
7467 mono_raise_exception (ex);
7470 return token;
7473 static void*
7474 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end)
7476 int slen, type = t->type;
7477 MonoClass *tklass = t->data.klass;
7479 handle_enum:
7480 switch (type) {
7481 case MONO_TYPE_U1:
7482 case MONO_TYPE_I1:
7483 case MONO_TYPE_BOOLEAN: {
7484 MonoBoolean *bval = g_malloc (sizeof (MonoBoolean));
7485 *bval = *p;
7486 *end = p + 1;
7487 return bval;
7489 case MONO_TYPE_CHAR:
7490 case MONO_TYPE_U2:
7491 case MONO_TYPE_I2: {
7492 guint16 *val = g_malloc (sizeof (guint16));
7493 *val = read16 (p);
7494 *end = p + 2;
7495 return val;
7497 #if SIZEOF_VOID_P == 4
7498 case MONO_TYPE_U:
7499 case MONO_TYPE_I:
7500 #endif
7501 case MONO_TYPE_R4:
7502 case MONO_TYPE_U4:
7503 case MONO_TYPE_I4: {
7504 guint32 *val = g_malloc (sizeof (guint32));
7505 *val = read32 (p);
7506 *end = p + 4;
7507 return val;
7509 #if SIZEOF_VOID_P == 8
7510 case MONO_TYPE_U: /* error out instead? this should probably not happen */
7511 case MONO_TYPE_I:
7512 #endif
7513 case MONO_TYPE_U8:
7514 case MONO_TYPE_I8: {
7515 guint64 *val = g_malloc (sizeof (guint64));
7516 *val = read64 (p);
7517 *end = p + 8;
7518 return val;
7520 case MONO_TYPE_R8: {
7521 double *val = g_malloc (sizeof (double));
7522 readr8 (p, val);
7523 *end = p + 8;
7524 return val;
7526 case MONO_TYPE_VALUETYPE:
7527 if (t->data.klass->enumtype) {
7528 type = mono_class_enum_basetype (t->data.klass)->type;
7529 goto handle_enum;
7530 } else {
7531 g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
7533 break;
7534 case MONO_TYPE_STRING:
7535 if (*p == (char)0xFF) {
7536 *end = p + 1;
7537 return NULL;
7539 slen = mono_metadata_decode_value (p, &p);
7540 *end = p + slen;
7541 return mono_string_new_len (mono_domain_get (), p, slen);
7542 case MONO_TYPE_CLASS: {
7543 char *n;
7544 MonoType *t;
7545 if (*p == (char)0xFF) {
7546 *end = p + 1;
7547 return NULL;
7549 handle_type:
7550 slen = mono_metadata_decode_value (p, &p);
7551 n = g_memdup (p, slen + 1);
7552 n [slen] = 0;
7553 t = mono_reflection_type_from_name (n, image);
7554 if (!t)
7555 g_warning ("Cannot load type '%s'", n);
7556 g_free (n);
7557 *end = p + slen;
7558 if (t)
7559 return mono_type_get_object (mono_domain_get (), t);
7560 else
7561 return NULL;
7563 case MONO_TYPE_OBJECT: {
7564 char subt = *p++;
7565 MonoObject *obj;
7566 MonoClass *subc = NULL;
7567 void *val;
7569 if (subt == 0x50) {
7570 goto handle_type;
7571 } else if (subt == 0x0E) {
7572 type = MONO_TYPE_STRING;
7573 goto handle_enum;
7574 } else if (subt == 0x1D) {
7575 MonoType simple_type = {{0}};
7576 int etype = *p;
7577 p ++;
7579 if (etype == 0x51)
7580 /* See Partition II, Appendix B3 */
7581 etype = MONO_TYPE_OBJECT;
7582 type = MONO_TYPE_SZARRAY;
7583 simple_type.type = etype;
7584 tklass = mono_class_from_mono_type (&simple_type);
7585 goto handle_enum;
7586 } else if (subt == 0x55) {
7587 char *n;
7588 MonoType *t;
7589 slen = mono_metadata_decode_value (p, &p);
7590 n = g_memdup (p, slen + 1);
7591 n [slen] = 0;
7592 t = mono_reflection_type_from_name (n, image);
7593 if (!t)
7594 g_error ("Cannot load type '%s'", n);
7595 g_free (n);
7596 p += slen;
7597 subc = mono_class_from_mono_type (t);
7598 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
7599 MonoType simple_type = {{0}};
7600 simple_type.type = subt;
7601 subc = mono_class_from_mono_type (&simple_type);
7602 } else {
7603 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
7605 val = load_cattr_value (image, &subc->byval_arg, p, end);
7606 obj = mono_object_new (mono_domain_get (), subc);
7607 memcpy ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
7608 g_free (val);
7609 return obj;
7611 case MONO_TYPE_SZARRAY: {
7612 MonoArray *arr;
7613 guint32 i, alen, basetype;
7614 alen = read32 (p);
7615 p += 4;
7616 if (alen == 0xffffffff) {
7617 *end = p;
7618 return NULL;
7620 arr = mono_array_new (mono_domain_get(), tklass, alen);
7621 basetype = tklass->byval_arg.type;
7622 if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
7623 basetype = mono_class_enum_basetype (tklass)->type;
7624 switch (basetype)
7626 case MONO_TYPE_U1:
7627 case MONO_TYPE_I1:
7628 case MONO_TYPE_BOOLEAN:
7629 for (i = 0; i < alen; i++) {
7630 MonoBoolean val = *p++;
7631 mono_array_set (arr, MonoBoolean, i, val);
7633 break;
7634 case MONO_TYPE_CHAR:
7635 case MONO_TYPE_U2:
7636 case MONO_TYPE_I2:
7637 for (i = 0; i < alen; i++) {
7638 guint16 val = read16 (p);
7639 mono_array_set (arr, guint16, i, val);
7640 p += 2;
7642 break;
7643 case MONO_TYPE_R4:
7644 case MONO_TYPE_U4:
7645 case MONO_TYPE_I4:
7646 for (i = 0; i < alen; i++) {
7647 guint32 val = read32 (p);
7648 mono_array_set (arr, guint32, i, val);
7649 p += 4;
7651 break;
7652 case MONO_TYPE_R8:
7653 for (i = 0; i < alen; i++) {
7654 double val;
7655 readr8 (p, &val);
7656 mono_array_set (arr, double, i, val);
7657 p += 8;
7659 break;
7660 case MONO_TYPE_U8:
7661 case MONO_TYPE_I8:
7662 for (i = 0; i < alen; i++) {
7663 guint64 val = read64 (p);
7664 mono_array_set (arr, guint64, i, val);
7665 p += 8;
7667 break;
7668 case MONO_TYPE_CLASS:
7669 case MONO_TYPE_OBJECT:
7670 case MONO_TYPE_STRING:
7671 for (i = 0; i < alen; i++) {
7672 MonoObject *item = load_cattr_value (image, &tklass->byval_arg, p, &p);
7673 mono_array_setref (arr, i, item);
7675 break;
7676 default:
7677 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
7679 *end=p;
7680 return arr;
7682 default:
7683 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
7685 return NULL;
7688 static MonoObject*
7689 create_cattr_typed_arg (MonoType *t, MonoObject *val)
7691 static MonoClass *klass;
7692 static MonoMethod *ctor;
7693 MonoObject *retval;
7694 void *params [2], *unboxed;
7696 if (!klass)
7697 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "CustomAttributeTypedArgument");
7698 if (!ctor)
7699 ctor = mono_class_get_method_from_name (klass, ".ctor", 2);
7701 params [0] = mono_type_get_object (mono_domain_get (), t);
7702 params [1] = val;
7703 retval = mono_object_new (mono_domain_get (), klass);
7704 unboxed = mono_object_unbox (retval);
7705 mono_runtime_invoke (ctor, unboxed, params, NULL);
7707 return retval;
7710 static MonoObject*
7711 create_cattr_named_arg (void *minfo, MonoObject *typedarg)
7713 static MonoClass *klass;
7714 static MonoMethod *ctor;
7715 MonoObject *retval;
7716 void *unboxed, *params [2];
7718 if (!klass)
7719 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "CustomAttributeNamedArgument");
7720 if (!ctor)
7721 ctor = mono_class_get_method_from_name (klass, ".ctor", 2);
7723 params [0] = minfo;
7724 params [1] = typedarg;
7725 retval = mono_object_new (mono_domain_get (), klass);
7726 unboxed = mono_object_unbox (retval);
7727 mono_runtime_invoke (ctor, unboxed, params, NULL);
7729 return retval;
7732 static gboolean
7733 type_is_reference (MonoType *type)
7735 switch (type->type) {
7736 case MONO_TYPE_BOOLEAN:
7737 case MONO_TYPE_CHAR:
7738 case MONO_TYPE_U:
7739 case MONO_TYPE_I:
7740 case MONO_TYPE_U1:
7741 case MONO_TYPE_I1:
7742 case MONO_TYPE_U2:
7743 case MONO_TYPE_I2:
7744 case MONO_TYPE_U4:
7745 case MONO_TYPE_I4:
7746 case MONO_TYPE_U8:
7747 case MONO_TYPE_I8:
7748 case MONO_TYPE_R8:
7749 case MONO_TYPE_R4:
7750 case MONO_TYPE_VALUETYPE:
7751 return FALSE;
7752 default:
7753 return TRUE;
7757 static void
7758 free_param_data (MonoMethodSignature *sig, void **params) {
7759 int i;
7760 for (i = 0; i < sig->param_count; ++i) {
7761 if (!type_is_reference (sig->params [i]))
7762 g_free (params [i]);
7767 * Find the field index in the metadata FieldDef table.
7769 static guint32
7770 find_field_index (MonoClass *klass, MonoClassField *field) {
7771 int i;
7773 for (i = 0; i < klass->field.count; ++i) {
7774 if (field == &klass->fields [i])
7775 return klass->field.first + 1 + i;
7777 return 0;
7781 * Find the property index in the metadata Property table.
7783 static guint32
7784 find_property_index (MonoClass *klass, MonoProperty *property) {
7785 int i;
7787 for (i = 0; i < klass->ext->property.count; ++i) {
7788 if (property == &klass->ext->properties [i])
7789 return klass->ext->property.first + 1 + i;
7791 return 0;
7795 * Find the event index in the metadata Event table.
7797 static guint32
7798 find_event_index (MonoClass *klass, MonoEvent *event) {
7799 int i;
7801 for (i = 0; i < klass->ext->event.count; ++i) {
7802 if (event == &klass->ext->events [i])
7803 return klass->ext->event.first + 1 + i;
7805 return 0;
7808 static MonoObject*
7809 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len)
7811 const char *p = (const char*)data;
7812 const char *named;
7813 guint32 i, j, num_named;
7814 MonoObject *attr;
7815 void *params_buf [32];
7816 void **params;
7817 MonoMethodSignature *sig;
7819 mono_class_init (method->klass);
7821 if (len == 0) {
7822 attr = mono_object_new (mono_domain_get (), method->klass);
7823 mono_runtime_invoke (method, attr, NULL, NULL);
7824 return attr;
7827 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
7828 return NULL;
7830 /*g_print ("got attr %s\n", method->klass->name);*/
7832 sig = mono_method_signature (method);
7833 if (sig->param_count < 32)
7834 params = params_buf;
7835 else
7836 /* Allocate using GC so it gets GC tracking */
7837 params = mono_gc_alloc_fixed (sig->param_count * sizeof (void*), NULL);
7839 /* skip prolog */
7840 p += 2;
7841 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
7842 params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p);
7845 named = p;
7846 attr = mono_object_new (mono_domain_get (), method->klass);
7847 mono_runtime_invoke (method, attr, params, NULL);
7848 free_param_data (method->signature, params);
7849 num_named = read16 (named);
7850 named += 2;
7851 for (j = 0; j < num_named; j++) {
7852 gint name_len;
7853 char *name, named_type, data_type;
7854 named_type = *named++;
7855 data_type = *named++; /* type of data */
7856 if (data_type == MONO_TYPE_SZARRAY)
7857 data_type = *named++;
7858 if (data_type == MONO_TYPE_ENUM) {
7859 gint type_len;
7860 char *type_name;
7861 type_len = mono_metadata_decode_blob_size (named, &named);
7862 type_name = g_malloc (type_len + 1);
7863 memcpy (type_name, named, type_len);
7864 type_name [type_len] = 0;
7865 named += type_len;
7866 /* FIXME: lookup the type and check type consistency */
7867 g_free (type_name);
7869 name_len = mono_metadata_decode_blob_size (named, &named);
7870 name = g_malloc (name_len + 1);
7871 memcpy (name, named, name_len);
7872 name [name_len] = 0;
7873 named += name_len;
7874 if (named_type == 0x53) {
7875 MonoClassField *field = mono_class_get_field_from_name (mono_object_class (attr), name);
7876 void *val = load_cattr_value (image, field->type, named, &named);
7877 mono_field_set_value (attr, field, val);
7878 if (!type_is_reference (field->type))
7879 g_free (val);
7880 } else if (named_type == 0x54) {
7881 MonoProperty *prop;
7882 void *pparams [1];
7883 MonoType *prop_type;
7885 prop = mono_class_get_property_from_name (mono_object_class (attr), name);
7886 /* can we have more that 1 arg in a custom attr named property? */
7887 prop_type = prop->get? mono_method_signature (prop->get)->ret :
7888 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
7889 pparams [0] = load_cattr_value (image, prop_type, named, &named);
7890 mono_property_set_value (prop, attr, pparams, NULL);
7891 if (!type_is_reference (prop_type))
7892 g_free (pparams [0]);
7894 g_free (name);
7897 if (params != params_buf)
7898 mono_gc_free_fixed (params);
7900 return attr;
7903 static MonoObject*
7904 create_custom_attr_data (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len)
7906 MonoArray *typedargs, *namedargs;
7907 MonoClass *attrklass;
7908 static MonoMethod *ctor;
7909 MonoDomain *domain;
7910 MonoObject *attr;
7911 const char *p = (const char*)data;
7912 const char *named;
7913 guint32 i, j, num_named;
7914 void *params [3];
7916 mono_class_init (method->klass);
7918 if (!ctor)
7919 ctor = mono_class_get_method_from_name (mono_defaults.customattribute_data_class, ".ctor", 3);
7921 domain = mono_domain_get ();
7922 if (len == 0) {
7923 /* This is for Attributes with no parameters */
7924 attr = mono_object_new (domain, mono_defaults.customattribute_data_class);
7925 params [0] = mono_method_get_object (domain, method, NULL);
7926 params [1] = params [2] = NULL;
7927 mono_runtime_invoke (method, attr, params, NULL);
7928 return attr;
7931 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
7932 return NULL;
7934 typedargs = mono_array_new (domain, mono_get_object_class (), mono_method_signature (method)->param_count);
7936 /* skip prolog */
7937 p += 2;
7938 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
7939 MonoObject *obj, *typedarg;
7940 void *val;
7942 val = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p);
7943 obj = type_is_reference (mono_method_signature (method)->params [i]) ?
7944 val : mono_value_box (domain, mono_class_from_mono_type (mono_method_signature (method)->params [i]), val);
7945 typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj);
7946 mono_array_setref (typedargs, i, typedarg);
7948 if (!type_is_reference (mono_method_signature (method)->params [i]))
7949 g_free (val);
7952 named = p;
7953 num_named = read16 (named);
7954 namedargs = mono_array_new (domain, mono_get_object_class (), num_named);
7955 named += 2;
7956 attrklass = method->klass;
7957 for (j = 0; j < num_named; j++) {
7958 gint name_len;
7959 char *name, named_type, data_type;
7960 named_type = *named++;
7961 data_type = *named++; /* type of data */
7962 if (data_type == MONO_TYPE_SZARRAY)
7963 data_type = *named++;
7964 if (data_type == MONO_TYPE_ENUM) {
7965 gint type_len;
7966 char *type_name;
7967 type_len = mono_metadata_decode_blob_size (named, &named);
7968 type_name = g_malloc (type_len + 1);
7969 memcpy (type_name, named, type_len);
7970 type_name [type_len] = 0;
7971 named += type_len;
7972 /* FIXME: lookup the type and check type consistency */
7973 g_free (type_name);
7975 name_len = mono_metadata_decode_blob_size (named, &named);
7976 name = g_malloc (name_len + 1);
7977 memcpy (name, named, name_len);
7978 name [name_len] = 0;
7979 named += name_len;
7980 if (named_type == 0x53) {
7981 MonoObject *obj, *typedarg, *namedarg;
7982 MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
7983 void *minfo, *val = load_cattr_value (image, field->type, named, &named);
7985 minfo = mono_field_get_object (domain, NULL, field);
7986 obj = type_is_reference (field->type) ? val : mono_value_box (domain, mono_class_from_mono_type (field->type), val);
7987 typedarg = create_cattr_typed_arg (field->type, obj);
7988 namedarg = create_cattr_named_arg (minfo, typedarg);
7989 mono_array_setref (namedargs, j, namedarg);
7990 if (!type_is_reference (field->type))
7991 g_free (val);
7992 } else if (named_type == 0x54) {
7993 MonoObject *obj, *typedarg, *namedarg;
7994 MonoType *prop_type;
7995 void *val, *minfo;
7996 MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
7998 prop_type = prop->get? mono_method_signature (prop->get)->ret :
7999 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
8000 minfo = mono_property_get_object (domain, NULL, prop);
8001 val = load_cattr_value (image, prop_type, named, &named);
8002 obj = type_is_reference (prop_type) ? val : mono_value_box (domain, mono_class_from_mono_type (prop_type), val);
8003 typedarg = create_cattr_typed_arg (prop_type, obj);
8004 namedarg = create_cattr_named_arg (minfo, typedarg);
8005 mono_array_setref (namedargs, j, namedarg);
8006 if (!type_is_reference (prop_type))
8007 g_free (val);
8009 g_free (name);
8011 attr = mono_object_new (domain, mono_defaults.customattribute_data_class);
8012 params [0] = mono_method_get_object (domain, method, NULL);
8013 params [1] = typedargs;
8014 params [2] = namedargs;
8015 mono_runtime_invoke (ctor, attr, params, NULL);
8016 return attr;
8019 MonoArray*
8020 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
8022 MonoArray *result;
8023 MonoObject *attr;
8024 int i;
8026 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, cinfo->num_attrs);
8027 for (i = 0; i < cinfo->num_attrs; ++i) {
8028 if (!cinfo->attrs [i].ctor)
8029 /* The cattr type is not finished yet */
8030 /* We should include the type name but cinfo doesn't contain it */
8031 mono_raise_exception (mono_get_exception_type_load (NULL, NULL));
8032 attr = create_custom_attr (cinfo->image, cinfo->attrs [i].ctor, cinfo->attrs [i].data, cinfo->attrs [i].data_size);
8033 mono_array_setref (result, i, attr);
8035 return result;
8038 static MonoArray*
8039 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass)
8041 MonoArray *result;
8042 MonoObject *attr;
8043 int i, n;
8045 n = 0;
8046 for (i = 0; i < cinfo->num_attrs; ++i) {
8047 if (mono_class_is_assignable_from (attr_klass, cinfo->attrs [i].ctor->klass))
8048 n ++;
8051 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, n);
8052 n = 0;
8053 for (i = 0; i < cinfo->num_attrs; ++i) {
8054 if (mono_class_is_assignable_from (attr_klass, cinfo->attrs [i].ctor->klass)) {
8055 attr = create_custom_attr (cinfo->image, cinfo->attrs [i].ctor, cinfo->attrs [i].data, cinfo->attrs [i].data_size);
8056 mono_array_setref (result, n, attr);
8057 n ++;
8060 return result;
8063 static MonoArray*
8064 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo)
8066 MonoArray *result;
8067 MonoObject *attr;
8068 int i;
8070 result = mono_array_new (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs);
8071 for (i = 0; i < cinfo->num_attrs; ++i) {
8072 attr = create_custom_attr_data (cinfo->image, cinfo->attrs [i].ctor, cinfo->attrs [i].data, cinfo->attrs [i].data_size);
8073 mono_array_setref (result, i, attr);
8075 return result;
8079 * mono_custom_attrs_from_index:
8081 * Returns: NULL if no attributes are found or if a loading error occurs.
8083 MonoCustomAttrInfo*
8084 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
8086 guint32 mtoken, i, len;
8087 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
8088 MonoTableInfo *ca;
8089 MonoCustomAttrInfo *ainfo;
8090 GList *tmp, *list = NULL;
8091 const char *data;
8093 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
8095 i = mono_metadata_custom_attrs_from_index (image, idx);
8096 if (!i)
8097 return NULL;
8098 i --;
8099 while (i < ca->rows) {
8100 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
8101 break;
8102 list = g_list_prepend (list, GUINT_TO_POINTER (i));
8103 ++i;
8105 len = g_list_length (list);
8106 if (!len)
8107 return NULL;
8108 ainfo = g_malloc0 (sizeof (MonoCustomAttrInfo) + sizeof (MonoCustomAttrEntry) * (len - MONO_ZERO_LEN_ARRAY));
8109 ainfo->num_attrs = len;
8110 ainfo->image = image;
8111 for (i = 0, tmp = list; i < len; ++i, tmp = tmp->next) {
8112 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
8113 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
8114 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
8115 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
8116 mtoken |= MONO_TOKEN_METHOD_DEF;
8117 break;
8118 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
8119 mtoken |= MONO_TOKEN_MEMBER_REF;
8120 break;
8121 default:
8122 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
8123 break;
8125 ainfo->attrs [i].ctor = mono_get_method (image, mtoken, NULL);
8126 if (!ainfo->attrs [i].ctor) {
8127 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x", image->name, mtoken);
8128 g_list_free (list);
8129 g_free (ainfo);
8130 return NULL;
8132 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
8133 ainfo->attrs [i].data_size = mono_metadata_decode_value (data, &data);
8134 ainfo->attrs [i].data = (guchar*)data;
8136 g_list_free (list);
8138 return ainfo;
8141 MonoCustomAttrInfo*
8142 mono_custom_attrs_from_method (MonoMethod *method)
8144 guint32 idx;
8147 * An instantiated method has the same cattrs as the generic method definition.
8149 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
8150 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
8152 if (method->is_inflated)
8153 method = ((MonoMethodInflated *) method)->declaring;
8155 if (method->dynamic || method->klass->image->dynamic)
8156 return lookup_custom_attr (method->klass->image, method);
8158 if (!method->token)
8159 /* Synthetic methods */
8160 return NULL;
8162 idx = mono_method_get_index (method);
8163 idx <<= MONO_CUSTOM_ATTR_BITS;
8164 idx |= MONO_CUSTOM_ATTR_METHODDEF;
8165 return mono_custom_attrs_from_index (method->klass->image, idx);
8168 MonoCustomAttrInfo*
8169 mono_custom_attrs_from_class (MonoClass *klass)
8171 guint32 idx;
8173 if (klass->generic_class)
8174 klass = klass->generic_class->container_class;
8176 if (klass->image->dynamic)
8177 return lookup_custom_attr (klass->image, klass);
8179 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
8180 idx = mono_metadata_token_index (klass->sizes.generic_param_token);
8181 idx <<= MONO_CUSTOM_ATTR_BITS;
8182 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
8183 } else {
8184 idx = mono_metadata_token_index (klass->type_token);
8185 idx <<= MONO_CUSTOM_ATTR_BITS;
8186 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
8188 return mono_custom_attrs_from_index (klass->image, idx);
8191 MonoCustomAttrInfo*
8192 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
8194 guint32 idx;
8196 if (assembly->image->dynamic)
8197 return lookup_custom_attr (assembly->image, assembly);
8198 idx = 1; /* there is only one assembly */
8199 idx <<= MONO_CUSTOM_ATTR_BITS;
8200 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
8201 return mono_custom_attrs_from_index (assembly->image, idx);
8204 static MonoCustomAttrInfo*
8205 mono_custom_attrs_from_module (MonoImage *image)
8207 guint32 idx;
8209 if (image->dynamic)
8210 return lookup_custom_attr (image, image);
8211 idx = 1; /* there is only one module */
8212 idx <<= MONO_CUSTOM_ATTR_BITS;
8213 idx |= MONO_CUSTOM_ATTR_MODULE;
8214 return mono_custom_attrs_from_index (image, idx);
8217 MonoCustomAttrInfo*
8218 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
8220 guint32 idx;
8222 if (klass->image->dynamic) {
8223 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
8224 return lookup_custom_attr (klass->image, property);
8226 idx = find_property_index (klass, property);
8227 idx <<= MONO_CUSTOM_ATTR_BITS;
8228 idx |= MONO_CUSTOM_ATTR_PROPERTY;
8229 return mono_custom_attrs_from_index (klass->image, idx);
8232 MonoCustomAttrInfo*
8233 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
8235 guint32 idx;
8237 if (klass->image->dynamic) {
8238 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
8239 return lookup_custom_attr (klass->image, event);
8241 idx = find_event_index (klass, event);
8242 idx <<= MONO_CUSTOM_ATTR_BITS;
8243 idx |= MONO_CUSTOM_ATTR_EVENT;
8244 return mono_custom_attrs_from_index (klass->image, idx);
8247 MonoCustomAttrInfo*
8248 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
8250 guint32 idx;
8251 if (klass->image->dynamic) {
8252 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
8253 return lookup_custom_attr (klass->image, field);
8255 idx = find_field_index (klass, field);
8256 idx <<= MONO_CUSTOM_ATTR_BITS;
8257 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
8258 return mono_custom_attrs_from_index (klass->image, idx);
8261 MonoCustomAttrInfo*
8262 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
8264 MonoTableInfo *ca;
8265 guint32 i, idx, method_index;
8266 guint32 param_list, param_last, param_pos, found;
8267 MonoImage *image;
8268 MonoReflectionMethodAux *aux;
8271 * An instantiated method has the same cattrs as the generic method definition.
8273 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
8274 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
8276 if (method->is_inflated)
8277 method = ((MonoMethodInflated *) method)->declaring;
8279 if (method->klass->image->dynamic) {
8280 MonoCustomAttrInfo *res, *ainfo;
8281 int size;
8283 aux = g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
8284 if (!aux || !aux->param_cattr)
8285 return NULL;
8287 /* Need to copy since it will be freed later */
8288 ainfo = aux->param_cattr [param];
8289 size = sizeof (MonoCustomAttrInfo) + sizeof (MonoCustomAttrEntry) * (ainfo->num_attrs - MONO_ZERO_LEN_ARRAY);
8290 res = g_malloc0 (size);
8291 memcpy (res, ainfo, size);
8292 return res;
8295 image = method->klass->image;
8296 method_index = mono_method_get_index (method);
8297 ca = &image->tables [MONO_TABLE_METHOD];
8299 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
8300 if (method_index == ca->rows) {
8301 ca = &image->tables [MONO_TABLE_PARAM];
8302 param_last = ca->rows + 1;
8303 } else {
8304 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
8305 ca = &image->tables [MONO_TABLE_PARAM];
8307 found = FALSE;
8308 for (i = param_list; i < param_last; ++i) {
8309 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
8310 if (param_pos == param) {
8311 found = TRUE;
8312 break;
8315 if (!found)
8316 return NULL;
8317 idx = i;
8318 idx <<= MONO_CUSTOM_ATTR_BITS;
8319 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
8320 return mono_custom_attrs_from_index (image, idx);
8323 gboolean
8324 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
8326 int i;
8327 MonoClass *klass;
8328 for (i = 0; i < ainfo->num_attrs; ++i) {
8329 klass = ainfo->attrs [i].ctor->klass;
8330 if (mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
8331 return TRUE;
8333 return FALSE;
8336 MonoObject*
8337 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
8339 int i, attr_index;
8340 MonoClass *klass;
8341 MonoArray *attrs;
8343 attr_index = -1;
8344 for (i = 0; i < ainfo->num_attrs; ++i) {
8345 klass = ainfo->attrs [i].ctor->klass;
8346 if (mono_class_has_parent (klass, attr_klass)) {
8347 attr_index = i;
8348 break;
8351 if (attr_index == -1)
8352 return NULL;
8354 attrs = mono_custom_attrs_construct (ainfo);
8355 if (attrs)
8356 return mono_array_get (attrs, MonoObject*, attr_index);
8357 else
8358 return NULL;
8362 * mono_reflection_get_custom_attrs_info:
8363 * @obj: a reflection object handle
8365 * Return the custom attribute info for attributes defined for the
8366 * reflection handle @obj. The objects.
8368 * FIXME this function leaks like a sieve for SRE objects.
8370 MonoCustomAttrInfo*
8371 mono_reflection_get_custom_attrs_info (MonoObject *obj)
8373 MonoClass *klass;
8374 MonoCustomAttrInfo *cinfo = NULL;
8376 klass = obj->vtable->klass;
8377 if (klass == mono_defaults.monotype_class) {
8378 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj);
8379 klass = mono_class_from_mono_type (type);
8380 cinfo = mono_custom_attrs_from_class (klass);
8381 } else if (strcmp ("Assembly", klass->name) == 0) {
8382 MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
8383 cinfo = mono_custom_attrs_from_assembly (rassembly->assembly);
8384 } else if (strcmp ("Module", klass->name) == 0) {
8385 MonoReflectionModule *module = (MonoReflectionModule*)obj;
8386 cinfo = mono_custom_attrs_from_module (module->image);
8387 } else if (strcmp ("MonoProperty", klass->name) == 0) {
8388 MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj;
8389 cinfo = mono_custom_attrs_from_property (rprop->property->parent, rprop->property);
8390 } else if (strcmp ("MonoEvent", klass->name) == 0) {
8391 MonoReflectionMonoEvent *revent = (MonoReflectionMonoEvent*)obj;
8392 cinfo = mono_custom_attrs_from_event (revent->event->parent, revent->event);
8393 } else if (strcmp ("MonoField", klass->name) == 0) {
8394 MonoReflectionField *rfield = (MonoReflectionField*)obj;
8395 cinfo = mono_custom_attrs_from_field (rfield->field->parent, rfield->field);
8396 } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
8397 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
8398 cinfo = mono_custom_attrs_from_method (rmethod->method);
8399 } else if ((strcmp ("MonoGenericMethod", klass->name) == 0) || (strcmp ("MonoGenericCMethod", klass->name) == 0)) {
8400 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
8401 cinfo = mono_custom_attrs_from_method (rmethod->method);
8402 } else if (strcmp ("ParameterInfo", klass->name) == 0) {
8403 MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
8404 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl;
8405 cinfo = mono_custom_attrs_from_param (rmethod->method, param->PositionImpl + 1);
8406 } else if (strcmp ("AssemblyBuilder", klass->name) == 0) {
8407 MonoReflectionAssemblyBuilder *assemblyb = (MonoReflectionAssemblyBuilder*)obj;
8408 cinfo = mono_custom_attrs_from_builders (NULL, assemblyb->assembly.assembly->image, assemblyb->cattrs);
8409 } else if (strcmp ("TypeBuilder", klass->name) == 0) {
8410 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
8411 cinfo = mono_custom_attrs_from_builders (NULL, &tb->module->dynamic_image->image, tb->cattrs);
8412 } else if (strcmp ("ModuleBuilder", klass->name) == 0) {
8413 MonoReflectionModuleBuilder *mb = (MonoReflectionModuleBuilder*)obj;
8414 cinfo = mono_custom_attrs_from_builders (NULL, &mb->dynamic_image->image, mb->cattrs);
8415 } else if (strcmp ("ConstructorBuilder", klass->name) == 0) {
8416 MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder*)obj;
8417 cinfo = mono_custom_attrs_from_builders (NULL, cb->mhandle->klass->image, cb->cattrs);
8418 } else if (strcmp ("MethodBuilder", klass->name) == 0) {
8419 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder*)obj;
8420 cinfo = mono_custom_attrs_from_builders (NULL, mb->mhandle->klass->image, mb->cattrs);
8421 } else if (strcmp ("FieldBuilder", klass->name) == 0) {
8422 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder*)obj;
8423 cinfo = mono_custom_attrs_from_builders (NULL, &((MonoReflectionTypeBuilder*)fb->typeb)->module->dynamic_image->image, fb->cattrs);
8424 } else if (strcmp ("MonoGenericClass", klass->name) == 0) {
8425 MonoReflectionGenericClass *gclass = (MonoReflectionGenericClass*)obj;
8426 cinfo = mono_reflection_get_custom_attrs_info ((MonoObject*)gclass->generic_type);
8427 } else { /* handle other types here... */
8428 g_error ("get custom attrs not yet supported for %s", klass->name);
8431 return cinfo;
8435 * mono_reflection_get_custom_attrs_by_type:
8436 * @obj: a reflection object handle
8438 * Return an array with all the custom attributes defined of the
8439 * reflection handle @obj. If @attr_klass is non-NULL, only custom attributes
8440 * of that type are returned. The objects are fully build. Return NULL if a loading error
8441 * occurs.
8443 MonoArray*
8444 mono_reflection_get_custom_attrs_by_type (MonoObject *obj, MonoClass *attr_klass)
8446 MonoArray *result;
8447 MonoCustomAttrInfo *cinfo;
8449 cinfo = mono_reflection_get_custom_attrs_info (obj);
8450 if (cinfo) {
8451 if (attr_klass)
8452 result = mono_custom_attrs_construct_by_type (cinfo, attr_klass);
8453 else
8454 result = mono_custom_attrs_construct (cinfo);
8455 if (!cinfo->cached)
8456 mono_custom_attrs_free (cinfo);
8457 } else {
8458 if (mono_loader_get_last_error ())
8459 return NULL;
8460 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, 0);
8463 return result;
8467 * mono_reflection_get_custom_attrs:
8468 * @obj: a reflection object handle
8470 * Return an array with all the custom attributes defined of the
8471 * reflection handle @obj. The objects are fully build. Return NULL if a loading error
8472 * occurs.
8474 MonoArray*
8475 mono_reflection_get_custom_attrs (MonoObject *obj)
8477 return mono_reflection_get_custom_attrs_by_type (obj, NULL);
8481 * mono_reflection_get_custom_attrs_data:
8482 * @obj: a reflection obj handle
8484 * Returns an array of System.Reflection.CustomAttributeData,
8485 * which include information about attributes reflected on
8486 * types loaded using the Reflection Only methods
8488 MonoArray*
8489 mono_reflection_get_custom_attrs_data (MonoObject *obj)
8491 MonoArray *result;
8492 MonoCustomAttrInfo *cinfo;
8494 cinfo = mono_reflection_get_custom_attrs_info (obj);
8495 if (cinfo) {
8496 result = mono_custom_attrs_data_construct (cinfo);
8497 if (!cinfo->cached)
8498 mono_custom_attrs_free (cinfo);
8499 } else
8500 result = mono_array_new (mono_domain_get (), mono_defaults.customattribute_data_class, 0);
8502 return result;
8505 static MonoReflectionType*
8506 mono_reflection_type_get_underlying_system_type (MonoReflectionType* t)
8508 MonoMethod *method_get_underlying_system_type;
8510 method_get_underlying_system_type = mono_object_get_virtual_method ((MonoObject *) t,
8511 mono_class_get_method_from_name (mono_object_class (t),
8512 "get_UnderlyingSystemType",
8513 0));
8514 return (MonoReflectionType *) mono_runtime_invoke (method_get_underlying_system_type, t, NULL, NULL);
8517 #ifndef DISABLE_REFLECTION_EMIT
8519 static gboolean
8520 is_corlib_type (MonoClass *class)
8522 return class->image == mono_defaults.corlib;
8525 static gboolean
8526 is_usertype (MonoReflectionType *ref)
8528 MonoClass *class = mono_object_class (ref);
8529 return class->image != mono_defaults.corlib || strcmp ("TypeDelegator", class->name) == 0;
8532 #define check_corlib_type_cached(_class, _namespace, _name) do { \
8533 static MonoClass *cached_class; \
8534 if (cached_class) \
8535 return cached_class == _class; \
8536 if (is_corlib_type (_class) && !strcmp (_name, _class->name) && !strcmp (_namespace, _class->name_space)) { \
8537 cached_class = _class; \
8538 return TRUE; \
8540 return FALSE; \
8541 } while (0) \
8543 static gboolean
8544 is_sre_array (MonoClass *class)
8546 check_corlib_type_cached (class, "System.Reflection.Emit", "ArrayType");
8549 static gboolean
8550 is_sre_byref (MonoClass *class)
8552 check_corlib_type_cached (class, "System.Reflection.Emit", "ByRefType");
8555 static gboolean
8556 is_sre_pointer (MonoClass *class)
8558 check_corlib_type_cached (class, "System.Reflection.Emit", "PointerType");
8561 MonoType*
8562 mono_reflection_type_get_handle (MonoReflectionType* ref)
8564 MonoClass *class;
8565 if (!ref)
8566 return NULL;
8567 if (ref->type)
8568 return ref->type;
8570 if (is_usertype (ref)) {
8571 ref = mono_reflection_type_get_underlying_system_type (ref);
8572 g_assert (!is_usertype (ref)); /*FIXME fail better*/
8573 if (ref->type)
8574 return ref->type;
8577 class = mono_object_class (ref);
8579 if (is_sre_array (class)) {
8580 MonoType *res;
8581 MonoReflectionArrayType *sre_array = (MonoReflectionArrayType*)ref;
8582 MonoType *base = mono_reflection_type_get_handle (sre_array->element_type);
8583 g_assert (base);
8584 res = &mono_array_class_get (mono_class_from_mono_type (base), sre_array->rank)->byval_arg;
8585 sre_array->type.type = res;
8586 return res;
8587 } else if (is_sre_byref (class)) {
8588 MonoType *res;
8589 MonoReflectionDerivedType *sre_byref = (MonoReflectionDerivedType*)ref;
8590 MonoType *base = mono_reflection_type_get_handle (sre_byref->element_type);
8591 g_assert (base);
8592 res = &mono_class_from_mono_type (base)->this_arg;
8593 sre_byref->type.type = res;
8594 return res;
8595 } else if (is_sre_pointer (class)) {
8596 MonoType *res;
8597 MonoReflectionDerivedType *sre_pointer = (MonoReflectionDerivedType*)ref;
8598 MonoType *base = mono_reflection_type_get_handle (sre_pointer->element_type);
8599 g_assert (base);
8600 res = &mono_ptr_class_get (base)->byval_arg;
8601 sre_pointer->type.type = res;
8602 return res;
8605 g_error ("Cannot handle corlib user type %s", mono_type_full_name (&mono_object_class(ref)->byval_arg));
8606 return NULL;
8609 static MonoReflectionType*
8610 mono_reflection_type_resolve_user_types (MonoReflectionType *type)
8612 if (!type || type->type)
8613 return type;
8615 if (is_usertype (type)) {
8616 type = mono_reflection_type_get_underlying_system_type (type);
8617 if (is_usertype (type))
8618 mono_raise_exception (mono_get_exception_not_supported ("User defined subclasses of System.Type are not yet supported22"));
8621 return type;
8624 void
8625 mono_reflection_create_unmanaged_type (MonoReflectionType *type)
8627 mono_reflection_type_get_handle (type);
8631 * LOCKING: Assumes the loader lock is held.
8633 static MonoMethodSignature*
8634 parameters_to_signature (MonoImage *image, MonoArray *parameters) {
8635 MonoMethodSignature *sig;
8636 int count, i;
8638 count = parameters? mono_array_length (parameters): 0;
8640 sig = image_g_malloc0 (image, sizeof (MonoMethodSignature) + sizeof (MonoType*) * count);
8641 sig->param_count = count;
8642 sig->sentinelpos = -1; /* FIXME */
8643 for (i = 0; i < count; ++i)
8644 sig->params [i] = mono_type_array_get_and_resolve (parameters, i);
8645 return sig;
8649 * LOCKING: Assumes the loader lock is held.
8651 static MonoMethodSignature*
8652 ctor_builder_to_signature (MonoImage *image, MonoReflectionCtorBuilder *ctor) {
8653 MonoMethodSignature *sig;
8655 sig = parameters_to_signature (image, ctor->parameters);
8656 sig->hasthis = ctor->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
8657 sig->ret = &mono_defaults.void_class->byval_arg;
8658 return sig;
8662 * LOCKING: Assumes the loader lock is held.
8664 static MonoMethodSignature*
8665 method_builder_to_signature (MonoImage *image, MonoReflectionMethodBuilder *method) {
8666 MonoMethodSignature *sig;
8668 sig = parameters_to_signature (image, method->parameters);
8669 sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
8670 sig->ret = method->rtype? mono_reflection_type_get_handle ((MonoReflectionType*)method->rtype): &mono_defaults.void_class->byval_arg;
8671 sig->generic_param_count = method->generic_params ? mono_array_length (method->generic_params) : 0;
8672 return sig;
8675 static MonoMethodSignature*
8676 dynamic_method_to_signature (MonoReflectionDynamicMethod *method) {
8677 MonoMethodSignature *sig;
8679 sig = parameters_to_signature (NULL, method->parameters);
8680 sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
8681 sig->ret = method->rtype? mono_reflection_type_get_handle (method->rtype): &mono_defaults.void_class->byval_arg;
8682 sig->generic_param_count = 0;
8683 return sig;
8686 static void
8687 get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type)
8689 MonoClass *klass = mono_object_class (prop);
8690 if (strcmp (klass->name, "PropertyBuilder") == 0) {
8691 MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *)prop;
8692 *name = mono_string_to_utf8 (pb->name);
8693 *type = mono_reflection_type_get_handle ((MonoReflectionType*)pb->type);
8694 } else {
8695 MonoReflectionProperty *p = (MonoReflectionProperty *)prop;
8696 *name = g_strdup (p->property->name);
8697 if (p->property->get)
8698 *type = mono_method_signature (p->property->get)->ret;
8699 else
8700 *type = mono_method_signature (p->property->set)->params [mono_method_signature (p->property->set)->param_count - 1];
8704 static void
8705 get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
8707 MonoClass *klass = mono_object_class (field);
8708 if (strcmp (klass->name, "FieldBuilder") == 0) {
8709 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)field;
8710 *name = mono_string_to_utf8 (fb->name);
8711 *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type);
8712 } else {
8713 MonoReflectionField *f = (MonoReflectionField *)field;
8714 *name = g_strdup (mono_field_get_name (f->field));
8715 *type = f->field->type;
8718 #endif /* !DISABLE_REFLECTION_EMIT */
8721 * Encode a value in a custom attribute stream of bytes.
8722 * The value to encode is either supplied as an object in argument val
8723 * (valuetypes are boxed), or as a pointer to the data in the
8724 * argument argval.
8725 * @type represents the type of the value
8726 * @buffer is the start of the buffer
8727 * @p the current position in the buffer
8728 * @buflen contains the size of the buffer and is used to return the new buffer size
8729 * if this needs to be realloced.
8730 * @retbuffer and @retp return the start and the position of the buffer
8732 static void
8733 encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg, char *argval)
8735 MonoTypeEnum simple_type;
8737 if ((p-buffer) + 10 >= *buflen) {
8738 char *newbuf;
8739 *buflen *= 2;
8740 newbuf = g_realloc (buffer, *buflen);
8741 p = newbuf + (p-buffer);
8742 buffer = newbuf;
8744 if (!argval)
8745 argval = ((char*)arg + sizeof (MonoObject));
8746 simple_type = type->type;
8747 handle_enum:
8748 switch (simple_type) {
8749 case MONO_TYPE_BOOLEAN:
8750 case MONO_TYPE_U1:
8751 case MONO_TYPE_I1:
8752 *p++ = *argval;
8753 break;
8754 case MONO_TYPE_CHAR:
8755 case MONO_TYPE_U2:
8756 case MONO_TYPE_I2:
8757 swap_with_size (p, argval, 2, 1);
8758 p += 2;
8759 break;
8760 case MONO_TYPE_U4:
8761 case MONO_TYPE_I4:
8762 case MONO_TYPE_R4:
8763 swap_with_size (p, argval, 4, 1);
8764 p += 4;
8765 break;
8766 case MONO_TYPE_R8:
8767 #if defined(ARM_FPU_FPA) && G_BYTE_ORDER == G_LITTLE_ENDIAN
8768 p [0] = argval [4];
8769 p [1] = argval [5];
8770 p [2] = argval [6];
8771 p [3] = argval [7];
8772 p [4] = argval [0];
8773 p [5] = argval [1];
8774 p [6] = argval [2];
8775 p [7] = argval [3];
8776 #else
8777 swap_with_size (p, argval, 8, 1);
8778 #endif
8779 p += 8;
8780 break;
8781 case MONO_TYPE_U8:
8782 case MONO_TYPE_I8:
8783 swap_with_size (p, argval, 8, 1);
8784 p += 8;
8785 break;
8786 case MONO_TYPE_VALUETYPE:
8787 if (type->data.klass->enumtype) {
8788 simple_type = mono_class_enum_basetype (type->data.klass)->type;
8789 goto handle_enum;
8790 } else {
8791 g_warning ("generic valutype %s not handled in custom attr value decoding", type->data.klass->name);
8793 break;
8794 case MONO_TYPE_STRING: {
8795 char *str;
8796 guint32 slen;
8797 if (!arg) {
8798 *p++ = 0xFF;
8799 break;
8801 str = mono_string_to_utf8 ((MonoString*)arg);
8802 slen = strlen (str);
8803 if ((p-buffer) + 10 + slen >= *buflen) {
8804 char *newbuf;
8805 *buflen *= 2;
8806 *buflen += slen;
8807 newbuf = g_realloc (buffer, *buflen);
8808 p = newbuf + (p-buffer);
8809 buffer = newbuf;
8811 mono_metadata_encode_value (slen, p, &p);
8812 memcpy (p, str, slen);
8813 p += slen;
8814 g_free (str);
8815 break;
8817 case MONO_TYPE_CLASS: {
8818 char *str;
8819 guint32 slen;
8820 MonoClass *k;
8821 if (!arg) {
8822 *p++ = 0xFF;
8823 break;
8825 k = mono_object_class (arg);
8826 if (!mono_object_isinst (arg, mono_defaults.monotype_class) &&
8827 (strcmp (k->name, "TypeBuilder") || strcmp (k->name_space, "System.Reflection.Emit"))) {
8828 MonoReflectionType* rt = mono_reflection_type_get_underlying_system_type ((MonoReflectionType*) arg);
8829 MonoClass *rtc;
8831 if (rt && (rtc = mono_object_class (rt)) &&
8832 (mono_object_isinst ((MonoObject *) rt, mono_defaults.monotype_class) ||
8833 !strcmp (rtc->name, "TypeBuilder") || !strcmp (rtc->name_space, "System.Reflection.Emit"))) {
8834 arg = (MonoObject *) rt;
8835 k = rtc;
8836 } else
8837 g_error ("Only System.Type allowed, not %s.%s", k->name_space, k->name);
8839 handle_type:
8840 str = type_get_qualified_name (((MonoReflectionType*)arg)->type, NULL);
8841 slen = strlen (str);
8842 if ((p-buffer) + 10 + slen >= *buflen) {
8843 char *newbuf;
8844 *buflen *= 2;
8845 *buflen += slen;
8846 newbuf = g_realloc (buffer, *buflen);
8847 p = newbuf + (p-buffer);
8848 buffer = newbuf;
8850 mono_metadata_encode_value (slen, p, &p);
8851 memcpy (p, str, slen);
8852 p += slen;
8853 g_free (str);
8854 break;
8856 case MONO_TYPE_SZARRAY: {
8857 int len, i;
8858 MonoClass *eclass, *arg_eclass;
8860 if (!arg) {
8861 *p++ = 0xff; *p++ = 0xff; *p++ = 0xff; *p++ = 0xff;
8862 break;
8864 len = mono_array_length ((MonoArray*)arg);
8865 *p++ = len & 0xff;
8866 *p++ = (len >> 8) & 0xff;
8867 *p++ = (len >> 16) & 0xff;
8868 *p++ = (len >> 24) & 0xff;
8869 *retp = p;
8870 *retbuffer = buffer;
8871 eclass = type->data.klass;
8872 arg_eclass = mono_object_class (arg)->element_class;
8874 if (!eclass) {
8875 /* Happens when we are called from the MONO_TYPE_OBJECT case below */
8876 eclass = mono_defaults.object_class;
8878 if (eclass == mono_defaults.object_class && arg_eclass->valuetype) {
8879 char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
8880 int elsize = mono_class_array_element_size (arg_eclass);
8881 for (i = 0; i < len; ++i) {
8882 encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &arg_eclass->byval_arg, NULL, elptr);
8883 elptr += elsize;
8885 } else if (eclass->valuetype && arg_eclass->valuetype) {
8886 char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
8887 int elsize = mono_class_array_element_size (eclass);
8888 for (i = 0; i < len; ++i) {
8889 encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, NULL, elptr);
8890 elptr += elsize;
8892 } else {
8893 for (i = 0; i < len; ++i) {
8894 encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, mono_array_get ((MonoArray*)arg, MonoObject*, i), NULL);
8897 break;
8899 case MONO_TYPE_OBJECT: {
8900 MonoClass *klass;
8901 char *str;
8902 guint32 slen;
8905 * The parameter type is 'object' but the type of the actual
8906 * argument is not. So we have to add type information to the blob
8907 * too. This is completely undocumented in the spec.
8910 if (arg == NULL) {
8911 *p++ = MONO_TYPE_STRING; // It's same hack as MS uses
8912 *p++ = 0xFF;
8913 break;
8916 klass = mono_object_class (arg);
8918 if (mono_object_isinst (arg, mono_defaults.systemtype_class)) {
8919 *p++ = 0x50;
8920 goto handle_type;
8921 } else if (klass->enumtype) {
8922 *p++ = 0x55;
8923 } else if (klass == mono_defaults.string_class) {
8924 simple_type = MONO_TYPE_STRING;
8925 *p++ = 0x0E;
8926 goto handle_enum;
8927 } else if (klass->rank == 1) {
8928 *p++ = 0x1D;
8929 if (klass->element_class->byval_arg.type == MONO_TYPE_OBJECT)
8930 /* See Partition II, Appendix B3 */
8931 *p++ = 0x51;
8932 else
8933 *p++ = klass->element_class->byval_arg.type;
8934 encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &klass->byval_arg, arg, NULL);
8935 break;
8936 } else if (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8) {
8937 *p++ = simple_type = klass->byval_arg.type;
8938 goto handle_enum;
8939 } else {
8940 g_error ("unhandled type in custom attr");
8942 str = type_get_qualified_name (mono_class_get_type(klass), NULL);
8943 slen = strlen (str);
8944 if ((p-buffer) + 10 + slen >= *buflen) {
8945 char *newbuf;
8946 *buflen *= 2;
8947 *buflen += slen;
8948 newbuf = g_realloc (buffer, *buflen);
8949 p = newbuf + (p-buffer);
8950 buffer = newbuf;
8952 mono_metadata_encode_value (slen, p, &p);
8953 memcpy (p, str, slen);
8954 p += slen;
8955 g_free (str);
8956 simple_type = mono_class_enum_basetype (klass)->type;
8957 goto handle_enum;
8959 default:
8960 g_error ("type 0x%02x not yet supported in custom attr encoder", simple_type);
8962 *retp = p;
8963 *retbuffer = buffer;
8966 static void
8967 encode_field_or_prop_type (MonoType *type, char *p, char **retp)
8969 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
8970 char *str = type_get_qualified_name (type, NULL);
8971 int slen = strlen (str);
8973 *p++ = 0x55;
8975 * This seems to be optional...
8976 * *p++ = 0x80;
8978 mono_metadata_encode_value (slen, p, &p);
8979 memcpy (p, str, slen);
8980 p += slen;
8981 g_free (str);
8982 } else if (type->type == MONO_TYPE_OBJECT) {
8983 *p++ = 0x51;
8984 } else if (type->type == MONO_TYPE_CLASS) {
8985 /* it should be a type: encode_cattr_value () has the check */
8986 *p++ = 0x50;
8987 } else {
8988 mono_metadata_encode_value (type->type, p, &p);
8989 if (type->type == MONO_TYPE_SZARRAY)
8990 /* See the examples in Partition VI, Annex B */
8991 encode_field_or_prop_type (&type->data.klass->byval_arg, p, &p);
8994 *retp = p;
8997 #ifndef DISABLE_REFLECTION_EMIT
8998 static void
8999 encode_named_val (MonoReflectionAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, char *name, MonoObject *value)
9001 int len;
9002 /* Preallocate a large enough buffer */
9003 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
9004 char *str = type_get_qualified_name (type, NULL);
9005 len = strlen (str);
9006 g_free (str);
9007 } else if (type->type == MONO_TYPE_SZARRAY && type->data.klass->enumtype) {
9008 char *str = type_get_qualified_name (&type->data.klass->byval_arg, NULL);
9009 len = strlen (str);
9010 g_free (str);
9011 } else {
9012 len = 0;
9014 len += strlen (name);
9016 if ((p-buffer) + 20 + len >= *buflen) {
9017 char *newbuf;
9018 *buflen *= 2;
9019 *buflen += len;
9020 newbuf = g_realloc (buffer, *buflen);
9021 p = newbuf + (p-buffer);
9022 buffer = newbuf;
9025 encode_field_or_prop_type (type, p, &p);
9027 len = strlen (name);
9028 mono_metadata_encode_value (len, p, &p);
9029 memcpy (p, name, len);
9030 p += len;
9031 encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, buflen, type, value, NULL);
9032 *retp = p;
9033 *retbuffer = buffer;
9037 * mono_reflection_get_custom_attrs_blob:
9038 * @ctor: custom attribute constructor
9039 * @ctorArgs: arguments o the constructor
9040 * @properties:
9041 * @propValues:
9042 * @fields:
9043 * @fieldValues:
9045 * Creates the blob of data that needs to be saved in the metadata and that represents
9046 * the custom attributed described by @ctor, @ctorArgs etc.
9047 * Returns: a Byte array representing the blob of data.
9049 MonoArray*
9050 mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
9052 MonoArray *result;
9053 MonoMethodSignature *sig;
9054 MonoObject *arg;
9055 char *buffer, *p;
9056 guint32 buflen, i;
9058 MONO_ARCH_SAVE_REGS;
9060 if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
9061 /* sig is freed later so allocate it in the heap */
9062 sig = ctor_builder_to_signature (NULL, (MonoReflectionCtorBuilder*)ctor);
9063 } else {
9064 sig = mono_method_signature (((MonoReflectionMethod*)ctor)->method);
9067 g_assert (mono_array_length (ctorArgs) == sig->param_count);
9068 buflen = 256;
9069 p = buffer = g_malloc (buflen);
9070 /* write the prolog */
9071 *p++ = 1;
9072 *p++ = 0;
9073 for (i = 0; i < sig->param_count; ++i) {
9074 arg = mono_array_get (ctorArgs, MonoObject*, i);
9075 encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, &buflen, sig->params [i], arg, NULL);
9077 i = 0;
9078 if (properties)
9079 i += mono_array_length (properties);
9080 if (fields)
9081 i += mono_array_length (fields);
9082 *p++ = i & 0xff;
9083 *p++ = (i >> 8) & 0xff;
9084 if (properties) {
9085 MonoObject *prop;
9086 for (i = 0; i < mono_array_length (properties); ++i) {
9087 MonoType *ptype;
9088 char *pname;
9090 prop = mono_array_get (properties, gpointer, i);
9091 get_prop_name_and_type (prop, &pname, &ptype);
9092 *p++ = 0x54; /* PROPERTY signature */
9093 encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ptype, pname, (MonoObject*)mono_array_get (propValues, gpointer, i));
9094 g_free (pname);
9098 if (fields) {
9099 MonoObject *field;
9100 for (i = 0; i < mono_array_length (fields); ++i) {
9101 MonoType *ftype;
9102 char *fname;
9104 field = mono_array_get (fields, gpointer, i);
9105 get_field_name_and_type (field, &fname, &ftype);
9106 *p++ = 0x53; /* FIELD signature */
9107 encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ftype, fname, (MonoObject*)mono_array_get (fieldValues, gpointer, i));
9108 g_free (fname);
9112 g_assert (p - buffer <= buflen);
9113 buflen = p - buffer;
9114 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
9115 p = mono_array_addr (result, char, 0);
9116 memcpy (p, buffer, buflen);
9117 g_free (buffer);
9118 if (strcmp (ctor->vtable->klass->name, "MonoCMethod"))
9119 g_free (sig);
9120 return result;
9124 * mono_reflection_setup_internal_class:
9125 * @tb: a TypeBuilder object
9127 * Creates a MonoClass that represents the TypeBuilder.
9128 * This is a trick that lets us simplify a lot of reflection code
9129 * (and will allow us to support Build and Run assemblies easier).
9131 void
9132 mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
9134 MonoClass *klass, *parent;
9136 MONO_ARCH_SAVE_REGS;
9138 RESOLVE_TYPE (tb->parent);
9140 mono_loader_lock ();
9142 if (tb->parent) {
9143 /* check so we can compile corlib correctly */
9144 if (strcmp (mono_object_class (tb->parent)->name, "TypeBuilder") == 0) {
9145 /* mono_class_setup_mono_type () guaranteess type->data.klass is valid */
9146 parent = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent)->data.klass;
9147 } else {
9148 parent = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent));
9150 } else {
9151 parent = NULL;
9154 /* the type has already being created: it means we just have to change the parent */
9155 if (tb->type.type) {
9156 klass = mono_class_from_mono_type (tb->type.type);
9157 klass->parent = NULL;
9158 /* fool mono_class_setup_parent */
9159 klass->supertypes = NULL;
9160 mono_class_setup_parent (klass, parent);
9161 mono_class_setup_mono_type (klass);
9162 mono_loader_unlock ();
9163 return;
9166 klass = mono_image_alloc0 (&tb->module->dynamic_image->image, sizeof (MonoClass));
9168 klass->image = &tb->module->dynamic_image->image;
9170 klass->inited = 1; /* we lie to the runtime */
9171 klass->name = mono_string_to_utf8_image (klass->image, tb->name);
9172 klass->name_space = mono_string_to_utf8_image (klass->image, tb->nspace);
9173 klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx;
9174 klass->flags = tb->attrs;
9176 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
9178 klass->element_class = klass;
9180 MOVING_GC_REGISTER (&klass->reflection_info);
9181 klass->reflection_info = tb;
9183 /* Put into cache so mono_class_get () will find it */
9184 mono_image_add_to_name_cache (klass->image, klass->name_space, klass->name, tb->table_idx);
9186 mono_g_hash_table_insert (tb->module->dynamic_image->tokens,
9187 GUINT_TO_POINTER (MONO_TOKEN_TYPE_DEF | tb->table_idx), tb);
9189 if (parent != NULL) {
9190 mono_class_setup_parent (klass, parent);
9191 } else if (strcmp (klass->name, "Object") == 0 && strcmp (klass->name_space, "System") == 0) {
9192 const char *old_n = klass->name;
9193 /* trick to get relative numbering right when compiling corlib */
9194 klass->name = "BuildingObject";
9195 mono_class_setup_parent (klass, mono_defaults.object_class);
9196 klass->name = old_n;
9199 if ((!strcmp (klass->name, "ValueType") && !strcmp (klass->name_space, "System")) ||
9200 (!strcmp (klass->name, "Object") && !strcmp (klass->name_space, "System")) ||
9201 (!strcmp (klass->name, "Enum") && !strcmp (klass->name_space, "System"))) {
9202 klass->instance_size = sizeof (MonoObject);
9203 klass->size_inited = 1;
9204 mono_class_setup_vtable_general (klass, NULL, 0);
9207 mono_class_setup_mono_type (klass);
9209 mono_class_setup_supertypes (klass);
9212 * FIXME: handle interfaces.
9215 tb->type.type = &klass->byval_arg;
9217 if (tb->nesting_type) {
9218 g_assert (tb->nesting_type->type);
9219 klass->nested_in = mono_class_from_mono_type (mono_reflection_type_get_handle (tb->nesting_type));
9222 /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/
9224 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
9226 mono_loader_unlock ();
9230 * mono_reflection_setup_generic_class:
9231 * @tb: a TypeBuilder object
9233 * Setup the generic class before adding the first generic parameter.
9235 void
9236 mono_reflection_setup_generic_class (MonoReflectionTypeBuilder *tb)
9241 * mono_reflection_create_generic_class:
9242 * @tb: a TypeBuilder object
9244 * Creates the generic class after all generic parameters have been added.
9246 void
9247 mono_reflection_create_generic_class (MonoReflectionTypeBuilder *tb)
9249 MonoClass *klass;
9250 int count, i;
9252 MONO_ARCH_SAVE_REGS;
9254 klass = mono_class_from_mono_type (tb->type.type);
9256 count = tb->generic_params ? mono_array_length (tb->generic_params) : 0;
9258 if (klass->generic_container || (count == 0))
9259 return;
9261 g_assert (tb->generic_container && (tb->generic_container->owner.klass == klass));
9263 klass->generic_container = mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
9265 klass->generic_container->owner.klass = klass;
9266 klass->generic_container->type_argc = count;
9267 klass->generic_container->type_params = mono_image_alloc0 (klass->image, sizeof (MonoGenericParamFull) * count);
9269 klass->is_generic = 1;
9271 for (i = 0; i < count; i++) {
9272 MonoReflectionGenericParam *gparam = mono_array_get (tb->generic_params, gpointer, i);
9273 MonoGenericParamFull *param = (MonoGenericParamFull *) mono_reflection_type_get_handle ((MonoReflectionType*)gparam)->data.generic_param;
9274 klass->generic_container->type_params [i] = *param;
9275 /*Make sure we are a diferent type instance */
9276 klass->generic_container->type_params [i].param.owner = klass->generic_container;
9277 klass->generic_container->type_params [i].info.pklass = NULL;
9279 g_assert (klass->generic_container->type_params [i].param.owner);
9282 klass->generic_container->context.class_inst = mono_get_shared_generic_inst (klass->generic_container);
9286 * mono_reflection_create_internal_class:
9287 * @tb: a TypeBuilder object
9289 * Actually create the MonoClass that is associated with the TypeBuilder.
9291 void
9292 mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
9294 MonoClass *klass;
9296 MONO_ARCH_SAVE_REGS;
9298 klass = mono_class_from_mono_type (tb->type.type);
9300 mono_loader_lock ();
9301 if (klass->enumtype && mono_class_enum_basetype (klass) == NULL) {
9302 MonoReflectionFieldBuilder *fb;
9303 MonoClass *ec;
9304 MonoType *enum_basetype;
9306 g_assert (tb->fields != NULL);
9307 g_assert (mono_array_length (tb->fields) >= 1);
9309 fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, 0);
9311 if (!mono_type_is_valid_enum_basetype (mono_reflection_type_get_handle ((MonoReflectionType*)fb->type))) {
9312 mono_loader_unlock ();
9313 return;
9316 enum_basetype = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type);
9317 klass->element_class = mono_class_from_mono_type (enum_basetype);
9318 if (!klass->element_class)
9319 klass->element_class = mono_class_from_mono_type (enum_basetype);
9322 * get the element_class from the current corlib.
9324 ec = default_class_from_mono_type (enum_basetype);
9325 klass->instance_size = ec->instance_size;
9326 klass->size_inited = 1;
9328 * this is almost safe to do with enums and it's needed to be able
9329 * to create objects of the enum type (for use in SetConstant).
9331 /* FIXME: Does this mean enums can't have method overrides ? */
9332 mono_class_setup_vtable_general (klass, NULL, 0);
9334 mono_loader_unlock ();
9337 static MonoMarshalSpec*
9338 mono_marshal_spec_from_builder (MonoImage *image, MonoAssembly *assembly,
9339 MonoReflectionMarshal *minfo)
9341 MonoMarshalSpec *res;
9343 res = image_g_new0 (image, MonoMarshalSpec, 1);
9344 res->native = minfo->type;
9346 switch (minfo->type) {
9347 case MONO_NATIVE_LPARRAY:
9348 res->data.array_data.elem_type = minfo->eltype;
9349 if (minfo->has_size) {
9350 res->data.array_data.param_num = minfo->param_num;
9351 res->data.array_data.num_elem = minfo->count;
9352 res->data.array_data.elem_mult = minfo->param_num == -1 ? 0 : 1;
9354 else {
9355 res->data.array_data.param_num = -1;
9356 res->data.array_data.num_elem = -1;
9357 res->data.array_data.elem_mult = -1;
9359 break;
9361 case MONO_NATIVE_BYVALTSTR:
9362 case MONO_NATIVE_BYVALARRAY:
9363 res->data.array_data.num_elem = minfo->count;
9364 break;
9366 case MONO_NATIVE_CUSTOM:
9367 if (minfo->marshaltyperef)
9368 res->data.custom_data.custom_name =
9369 type_get_fully_qualified_name (mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef));
9370 if (minfo->mcookie)
9371 res->data.custom_data.cookie = mono_string_to_utf8 (minfo->mcookie);
9372 break;
9374 default:
9375 break;
9378 return res;
9380 #endif /* !DISABLE_REFLECTION_EMIT */
9382 MonoReflectionMarshal*
9383 mono_reflection_marshal_from_marshal_spec (MonoDomain *domain, MonoClass *klass,
9384 MonoMarshalSpec *spec)
9386 static MonoClass *System_Reflection_Emit_UnmanagedMarshalClass;
9387 MonoReflectionMarshal *minfo;
9388 MonoType *mtype;
9390 if (!System_Reflection_Emit_UnmanagedMarshalClass) {
9391 System_Reflection_Emit_UnmanagedMarshalClass = mono_class_from_name (
9392 mono_defaults.corlib, "System.Reflection.Emit", "UnmanagedMarshal");
9393 g_assert (System_Reflection_Emit_UnmanagedMarshalClass);
9396 minfo = (MonoReflectionMarshal*)mono_object_new (domain, System_Reflection_Emit_UnmanagedMarshalClass);
9397 minfo->type = spec->native;
9399 switch (minfo->type) {
9400 case MONO_NATIVE_LPARRAY:
9401 minfo->eltype = spec->data.array_data.elem_type;
9402 minfo->count = spec->data.array_data.num_elem;
9403 minfo->param_num = spec->data.array_data.param_num;
9404 break;
9406 case MONO_NATIVE_BYVALTSTR:
9407 case MONO_NATIVE_BYVALARRAY:
9408 minfo->count = spec->data.array_data.num_elem;
9409 break;
9411 case MONO_NATIVE_CUSTOM:
9412 if (spec->data.custom_data.custom_name) {
9413 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, klass->image);
9414 if (mtype)
9415 MONO_OBJECT_SETREF (minfo, marshaltyperef, mono_type_get_object (domain, mtype));
9417 MONO_OBJECT_SETREF (minfo, marshaltype, mono_string_new (domain, spec->data.custom_data.custom_name));
9419 if (spec->data.custom_data.cookie)
9420 MONO_OBJECT_SETREF (minfo, mcookie, mono_string_new (domain, spec->data.custom_data.cookie));
9421 break;
9423 default:
9424 break;
9427 return minfo;
9430 #ifndef DISABLE_REFLECTION_EMIT
9431 static MonoMethod*
9432 reflection_methodbuilder_to_mono_method (MonoClass *klass,
9433 ReflectionMethodBuilder *rmb,
9434 MonoMethodSignature *sig)
9436 MonoMethod *m;
9437 MonoMethodNormal *pm;
9438 MonoMarshalSpec **specs;
9439 MonoReflectionMethodAux *method_aux;
9440 MonoImage *image;
9441 gboolean dynamic;
9442 int i;
9445 * Methods created using a MethodBuilder should have their memory allocated
9446 * inside the image mempool, while dynamic methods should have their memory
9447 * malloc'd.
9449 dynamic = rmb->refs != NULL;
9450 image = dynamic ? NULL : klass->image;
9452 if (!dynamic)
9453 g_assert (!klass->generic_class);
9455 mono_loader_lock ();
9457 if ((rmb->attrs & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
9458 (rmb->iattrs & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
9459 m = (MonoMethod *)image_g_new0 (image, MonoMethodPInvoke, 1);
9460 else if (rmb->refs)
9461 m = (MonoMethod *)image_g_new0 (image, MonoMethodWrapper, 1);
9462 else
9463 m = (MonoMethod *)image_g_new0 (image, MonoMethodNormal, 1);
9465 pm = (MonoMethodNormal*)m;
9467 m->dynamic = dynamic;
9468 m->slot = -1;
9469 m->flags = rmb->attrs;
9470 m->iflags = rmb->iattrs;
9471 m->name = mono_string_to_utf8_image (image, rmb->name);
9472 m->klass = klass;
9473 m->signature = sig;
9474 m->skip_visibility = rmb->skip_visibility;
9475 if (rmb->table_idx)
9476 m->token = MONO_TOKEN_METHOD_DEF | (*rmb->table_idx);
9478 if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
9479 if (klass == mono_defaults.string_class && !strcmp (m->name, ".ctor"))
9480 m->string_ctor = 1;
9482 m->signature->pinvoke = 1;
9483 } else if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
9484 m->signature->pinvoke = 1;
9486 method_aux = image_g_new0 (image, MonoReflectionMethodAux, 1);
9488 method_aux->dllentry = rmb->dllentry ? mono_string_to_utf8_image (image, rmb->dllentry) : image_strdup (image, m->name);
9489 method_aux->dll = mono_string_to_utf8_image (image, rmb->dll);
9491 ((MonoMethodPInvoke*)m)->piflags = (rmb->native_cc << 8) | (rmb->charset ? (rmb->charset - 1) * 2 : 0) | rmb->extra_flags;
9493 if (klass->image->dynamic)
9494 g_hash_table_insert (((MonoDynamicImage*)klass->image)->method_aux_hash, m, method_aux);
9496 mono_loader_unlock ();
9498 return m;
9499 } else if (!(m->flags & METHOD_ATTRIBUTE_ABSTRACT) &&
9500 !(m->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
9501 MonoMethodHeader *header;
9502 guint32 code_size;
9503 gint32 max_stack, i;
9504 gint32 num_locals = 0;
9505 gint32 num_clauses = 0;
9506 guint8 *code;
9508 if (rmb->ilgen) {
9509 code = mono_array_addr (rmb->ilgen->code, guint8, 0);
9510 code_size = rmb->ilgen->code_len;
9511 max_stack = rmb->ilgen->max_stack;
9512 num_locals = rmb->ilgen->locals ? mono_array_length (rmb->ilgen->locals) : 0;
9513 if (rmb->ilgen->ex_handlers)
9514 num_clauses = method_count_clauses (rmb->ilgen);
9515 } else {
9516 if (rmb->code) {
9517 code = mono_array_addr (rmb->code, guint8, 0);
9518 code_size = mono_array_length (rmb->code);
9519 /* we probably need to run a verifier on the code... */
9520 max_stack = 8;
9522 else {
9523 code = NULL;
9524 code_size = 0;
9525 max_stack = 8;
9529 header = image_g_malloc0 (image, sizeof (MonoMethodHeader) +
9530 (num_locals - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
9531 header->code_size = code_size;
9532 header->code = image_g_malloc (image, code_size);
9533 memcpy ((char*)header->code, code, code_size);
9534 header->max_stack = max_stack;
9535 header->init_locals = rmb->init_locals;
9536 header->num_locals = num_locals;
9538 for (i = 0; i < num_locals; ++i) {
9539 MonoReflectionLocalBuilder *lb =
9540 mono_array_get (rmb->ilgen->locals, MonoReflectionLocalBuilder*, i);
9542 header->locals [i] = image_g_new0 (image, MonoType, 1);
9543 memcpy (header->locals [i], mono_reflection_type_get_handle ((MonoReflectionType*)lb->type), sizeof (MonoType));
9546 header->num_clauses = num_clauses;
9547 if (num_clauses) {
9548 header->clauses = method_encode_clauses (image, (MonoDynamicImage*)klass->image,
9549 rmb->ilgen, num_clauses);
9552 pm->header = header;
9555 if (rmb->generic_params) {
9556 int count = mono_array_length (rmb->generic_params);
9557 MonoGenericContainer *container;
9559 container = rmb->generic_container;
9560 if (container) {
9561 m->is_generic = TRUE;
9562 mono_method_set_generic_container (m, container);
9564 container->type_argc = count;
9565 container->type_params = image_g_new0 (image, MonoGenericParamFull, count);
9566 container->owner.method = m;
9568 for (i = 0; i < count; i++) {
9569 MonoReflectionGenericParam *gp =
9570 mono_array_get (rmb->generic_params, MonoReflectionGenericParam*, i);
9571 MonoGenericParamFull *param = (MonoGenericParamFull *) mono_reflection_type_get_handle ((MonoReflectionType*)gp)->data.generic_param;
9572 container->type_params [i] = *param;
9575 if (klass->generic_container) {
9576 container->parent = klass->generic_container;
9577 container->context.class_inst = klass->generic_container->context.class_inst;
9579 container->context.method_inst = mono_get_shared_generic_inst (container);
9582 if (rmb->refs) {
9583 MonoMethodWrapper *mw = (MonoMethodWrapper*)m;
9584 int i;
9585 void **data;
9587 m->wrapper_type = MONO_WRAPPER_DYNAMIC_METHOD;
9589 mw->method_data = data = image_g_new (image, gpointer, rmb->nrefs + 1);
9590 data [0] = GUINT_TO_POINTER (rmb->nrefs);
9591 for (i = 0; i < rmb->nrefs; ++i)
9592 data [i + 1] = rmb->refs [i];
9595 method_aux = NULL;
9597 /* Parameter info */
9598 if (rmb->pinfo) {
9599 if (!method_aux)
9600 method_aux = image_g_new0 (image, MonoReflectionMethodAux, 1);
9601 method_aux->param_names = image_g_new0 (image, char *, mono_method_signature (m)->param_count + 1);
9602 for (i = 0; i <= m->signature->param_count; ++i) {
9603 MonoReflectionParamBuilder *pb;
9604 if ((pb = mono_array_get (rmb->pinfo, MonoReflectionParamBuilder*, i))) {
9605 if ((i > 0) && (pb->attrs)) {
9606 /* Make a copy since it might point to a shared type structure */
9607 m->signature->params [i - 1] = mono_metadata_type_dup (klass->image, m->signature->params [i - 1]);
9608 m->signature->params [i - 1]->attrs = pb->attrs;
9611 if (pb->attrs & PARAM_ATTRIBUTE_HAS_DEFAULT) {
9612 MonoDynamicImage *assembly;
9613 guint32 idx, def_type, len;
9614 char *p;
9615 const char *p2;
9617 if (!method_aux->param_defaults) {
9618 method_aux->param_defaults = image_g_new0 (image, guint8*, m->signature->param_count + 1);
9619 method_aux->param_default_types = image_g_new0 (image, guint32, m->signature->param_count + 1);
9621 assembly = (MonoDynamicImage*)klass->image;
9622 idx = encode_constant (assembly, pb->def_value, &def_type);
9623 /* Copy the data from the blob since it might get realloc-ed */
9624 p = assembly->blob.data + idx;
9625 len = mono_metadata_decode_blob_size (p, &p2);
9626 len += p2 - p;
9627 method_aux->param_defaults [i] = image_g_malloc (image, len);
9628 method_aux->param_default_types [i] = def_type;
9629 memcpy ((gpointer)method_aux->param_defaults [i], p, len);
9632 if (pb->name)
9633 method_aux->param_names [i] = mono_string_to_utf8_image (image, pb->name);
9634 if (pb->cattrs) {
9635 if (!method_aux->param_cattr)
9636 method_aux->param_cattr = image_g_new0 (image, MonoCustomAttrInfo*, m->signature->param_count + 1);
9637 method_aux->param_cattr [i] = mono_custom_attrs_from_builders (image, klass->image, pb->cattrs);
9643 /* Parameter marshalling */
9644 specs = NULL;
9645 if (rmb->pinfo)
9646 for (i = 0; i < mono_array_length (rmb->pinfo); ++i) {
9647 MonoReflectionParamBuilder *pb;
9648 if ((pb = mono_array_get (rmb->pinfo, MonoReflectionParamBuilder*, i))) {
9649 if (pb->marshal_info) {
9650 if (specs == NULL)
9651 specs = image_g_new0 (image, MonoMarshalSpec*, sig->param_count + 1);
9652 specs [pb->position] =
9653 mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info);
9657 if (specs != NULL) {
9658 if (!method_aux)
9659 method_aux = image_g_new0 (image, MonoReflectionMethodAux, 1);
9660 method_aux->param_marshall = specs;
9663 if (klass->image->dynamic && method_aux)
9664 g_hash_table_insert (((MonoDynamicImage*)klass->image)->method_aux_hash, m, method_aux);
9666 mono_loader_unlock ();
9668 return m;
9671 static MonoMethod*
9672 ctorbuilder_to_mono_method (MonoClass *klass, MonoReflectionCtorBuilder* mb)
9674 ReflectionMethodBuilder rmb;
9675 MonoMethodSignature *sig;
9677 mono_loader_lock ();
9678 sig = ctor_builder_to_signature (klass->image, mb);
9679 mono_loader_unlock ();
9681 reflection_methodbuilder_from_ctor_builder (&rmb, mb);
9683 mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
9684 mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);
9686 /* If we are in a generic class, we might be called multiple times from inflate_method */
9687 if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save && !klass->generic_container) {
9688 /* ilgen is no longer needed */
9689 mb->ilgen = NULL;
9692 return mb->mhandle;
9695 static MonoMethod*
9696 methodbuilder_to_mono_method (MonoClass *klass, MonoReflectionMethodBuilder* mb)
9698 ReflectionMethodBuilder rmb;
9699 MonoMethodSignature *sig;
9701 mono_loader_lock ();
9702 sig = method_builder_to_signature (klass->image, mb);
9703 mono_loader_unlock ();
9705 reflection_methodbuilder_from_method_builder (&rmb, mb);
9707 mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
9708 mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);
9710 /* If we are in a generic class, we might be called multiple times from inflate_method */
9711 if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save && !klass->generic_container) {
9712 /* ilgen is no longer needed */
9713 mb->ilgen = NULL;
9715 return mb->mhandle;
9718 static MonoClassField*
9719 fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb)
9721 MonoClassField *field;
9722 MonoType *custom;
9724 field = g_new0 (MonoClassField, 1);
9726 field->name = mono_string_to_utf8 (fb->name);
9727 if (fb->attrs || fb->modreq || fb->modopt) {
9728 field->type = mono_metadata_type_dup (NULL, mono_reflection_type_get_handle ((MonoReflectionType*)fb->type));
9729 field->type->attrs = fb->attrs;
9731 g_assert (klass->image->dynamic);
9732 custom = add_custom_modifiers ((MonoDynamicImage*)klass->image, field->type, fb->modreq, fb->modopt);
9733 g_free (field->type);
9734 field->type = custom;
9735 } else {
9736 field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type);
9738 if (fb->offset != -1)
9739 field->offset = fb->offset;
9740 field->parent = klass;
9741 mono_save_custom_attrs (klass->image, field, fb->cattrs);
9743 // FIXME: Can't store fb->def_value/RVA, is it needed for field_on_insts ?
9745 return field;
9747 #endif
9749 MonoType*
9750 mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types)
9752 MonoClass *klass;
9753 MonoReflectionTypeBuilder *tb = NULL;
9754 gboolean is_dynamic = FALSE;
9755 MonoDomain *domain;
9756 MonoClass *geninst;
9758 mono_loader_lock ();
9760 domain = mono_object_domain (type);
9762 if (!strcmp (((MonoObject *) type)->vtable->klass->name, "TypeBuilder")) {
9763 tb = (MonoReflectionTypeBuilder *) type;
9765 is_dynamic = TRUE;
9766 } else if (!strcmp (((MonoObject *) type)->vtable->klass->name, "MonoGenericClass")) {
9767 MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;
9769 tb = rgi->generic_type;
9770 is_dynamic = TRUE;
9773 /* FIXME: fix the CreateGenericParameters protocol to avoid the two stage setup of TypeBuilders */
9774 if (tb && tb->generic_container)
9775 mono_reflection_create_generic_class (tb);
9777 klass = mono_class_from_mono_type (mono_reflection_type_get_handle (type));
9778 if (!klass->generic_container) {
9779 mono_loader_unlock ();
9780 return NULL;
9783 if (klass->wastypebuilder) {
9784 tb = (MonoReflectionTypeBuilder *) klass->reflection_info;
9786 is_dynamic = TRUE;
9789 mono_loader_unlock ();
9791 geninst = mono_class_bind_generic_parameters (klass, type_argc, types, is_dynamic);
9793 return &geninst->byval_arg;
9796 MonoClass*
9797 mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType **types, gboolean is_dynamic)
9799 MonoGenericClass *gclass;
9800 MonoGenericInst *inst;
9802 g_assert (klass->generic_container);
9804 inst = mono_metadata_get_generic_inst (type_argc, types);
9805 gclass = mono_metadata_lookup_generic_class (klass, inst, is_dynamic);
9807 return mono_generic_class_get_class (gclass);
9810 MonoReflectionMethod*
9811 mono_reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoArray *types)
9813 MonoClass *klass;
9814 MonoMethod *method, *inflated;
9815 MonoMethodInflated *imethod;
9816 MonoGenericContext tmp_context;
9817 MonoGenericInst *ginst;
9818 MonoType **type_argv;
9819 int count, i;
9821 MONO_ARCH_SAVE_REGS;
9823 if (!strcmp (rmethod->object.vtable->klass->name, "MethodBuilder")) {
9824 #ifndef DISABLE_REFLECTION_EMIT
9825 MonoReflectionMethodBuilder *mb = NULL;
9826 MonoReflectionTypeBuilder *tb;
9827 MonoClass *klass;
9829 mb = (MonoReflectionMethodBuilder *) rmethod;
9830 tb = (MonoReflectionTypeBuilder *) mb->type;
9831 klass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)tb));
9833 method = methodbuilder_to_mono_method (klass, mb);
9834 #else
9835 g_assert_not_reached ();
9836 method = NULL;
9837 #endif
9838 } else {
9839 method = rmethod->method;
9842 klass = method->klass;
9844 if (method->is_inflated)
9845 method = ((MonoMethodInflated *) method)->declaring;
9847 count = mono_method_signature (method)->generic_param_count;
9848 if (count != mono_array_length (types))
9849 return NULL;
9851 type_argv = g_new0 (MonoType *, count);
9852 for (i = 0; i < count; i++) {
9853 MonoReflectionType *garg = mono_array_get (types, gpointer, i);
9854 type_argv [i] = mono_reflection_type_get_handle (garg);
9856 ginst = mono_metadata_get_generic_inst (count, type_argv);
9857 g_free (type_argv);
9859 tmp_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL;
9860 tmp_context.method_inst = ginst;
9862 inflated = mono_class_inflate_generic_method (method, &tmp_context);
9863 imethod = (MonoMethodInflated *) inflated;
9865 if (method->klass->image->dynamic) {
9866 MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image;
9868 * This table maps metadata structures representing inflated methods/fields
9869 * to the reflection objects representing their generic definitions.
9871 mono_loader_lock ();
9872 mono_g_hash_table_insert (image->generic_def_objects, imethod, rmethod);
9873 mono_loader_unlock ();
9876 return mono_method_get_object (mono_object_domain (rmethod), inflated, NULL);
9879 #ifndef DISABLE_REFLECTION_EMIT
9881 static MonoMethod *
9882 inflate_mono_method (MonoClass *klass, MonoMethod *method, MonoObject *obj)
9884 MonoMethodInflated *imethod;
9885 MonoGenericContext *context;
9886 int i;
9889 * With generic code sharing the klass might not be inflated.
9890 * This can happen because classes inflated with their own
9891 * type arguments are "normalized" to the uninflated class.
9893 if (!klass->generic_class)
9894 return method;
9896 context = mono_class_get_context (klass);
9898 if (klass->method.count) {
9899 /* Find the already created inflated method */
9900 for (i = 0; i < klass->method.count; ++i) {
9901 g_assert (klass->methods [i]->is_inflated);
9902 if (((MonoMethodInflated*)klass->methods [i])->declaring == method)
9903 break;
9905 g_assert (i < klass->method.count);
9906 imethod = (MonoMethodInflated*)klass->methods [i];
9907 } else {
9908 imethod = (MonoMethodInflated *) mono_class_inflate_generic_method_full (method, klass, context);
9911 if (method->is_generic && method->klass->image->dynamic) {
9912 MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image;
9914 mono_loader_lock ();
9915 mono_g_hash_table_insert (image->generic_def_objects, imethod, obj);
9916 mono_loader_unlock ();
9918 return (MonoMethod *) imethod;
9921 static MonoMethod *
9922 inflate_method (MonoReflectionGenericClass *type, MonoObject *obj)
9924 MonoMethod *method;
9925 MonoClass *gklass;
9927 gklass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)type->generic_type));
9929 if (!strcmp (obj->vtable->klass->name, "MethodBuilder"))
9930 if (((MonoReflectionMethodBuilder*)obj)->mhandle)
9931 method = ((MonoReflectionMethodBuilder*)obj)->mhandle;
9932 else
9933 method = methodbuilder_to_mono_method (gklass, (MonoReflectionMethodBuilder *) obj);
9934 else if (!strcmp (obj->vtable->klass->name, "ConstructorBuilder"))
9935 method = ctorbuilder_to_mono_method (gklass, (MonoReflectionCtorBuilder *) obj);
9936 else if (!strcmp (obj->vtable->klass->name, "MonoMethod") || !strcmp (obj->vtable->klass->name, "MonoCMethod"))
9937 method = ((MonoReflectionMethod *) obj)->method;
9938 else {
9939 method = NULL; /* prevent compiler warning */
9940 g_assert_not_reached ();
9943 return inflate_mono_method (mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)type)), method, obj);
9946 /*TODO avoid saving custom attrs for generic classes as it's enough to have them on the generic type definition.*/
9947 void
9948 mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *methods,
9949 MonoArray *ctors, MonoArray *fields, MonoArray *properties,
9950 MonoArray *events)
9952 MonoGenericClass *gclass;
9953 MonoDynamicGenericClass *dgclass;
9954 MonoClass *klass, *gklass;
9955 MonoType *gtype;
9956 int i;
9958 MONO_ARCH_SAVE_REGS;
9960 gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type);
9961 klass = mono_class_from_mono_type (gtype);
9962 g_assert (gtype->type == MONO_TYPE_GENERICINST);
9963 gclass = gtype->data.generic_class;
9965 g_assert (gclass->is_dynamic);
9966 dgclass = (MonoDynamicGenericClass *) gclass;
9968 if (dgclass->initialized)
9969 return;
9971 gklass = gclass->container_class;
9972 mono_class_init (gklass);
9974 dgclass->count_methods = methods ? mono_array_length (methods) : 0;
9975 dgclass->count_ctors = ctors ? mono_array_length (ctors) : 0;
9976 dgclass->count_fields = fields ? mono_array_length (fields) : 0;
9977 dgclass->count_properties = properties ? mono_array_length (properties) : 0;
9978 dgclass->count_events = events ? mono_array_length (events) : 0;
9980 dgclass->methods = g_new0 (MonoMethod *, dgclass->count_methods);
9981 dgclass->ctors = g_new0 (MonoMethod *, dgclass->count_ctors);
9982 dgclass->fields = g_new0 (MonoClassField, dgclass->count_fields);
9983 dgclass->properties = g_new0 (MonoProperty, dgclass->count_properties);
9984 dgclass->events = g_new0 (MonoEvent, dgclass->count_events);
9985 dgclass->field_objects = g_new0 (MonoObject*, dgclass->count_fields);
9986 dgclass->field_generic_types = g_new0 (MonoType*, dgclass->count_fields);
9988 for (i = 0; i < dgclass->count_methods; i++) {
9989 MonoObject *obj = mono_array_get (methods, gpointer, i);
9991 dgclass->methods [i] = inflate_method (type, obj);
9994 for (i = 0; i < dgclass->count_ctors; i++) {
9995 MonoObject *obj = mono_array_get (ctors, gpointer, i);
9997 dgclass->ctors [i] = inflate_method (type, obj);
10000 for (i = 0; i < dgclass->count_fields; i++) {
10001 MonoObject *obj = mono_array_get (fields, gpointer, i);
10002 MonoClassField *field, *inflated_field = NULL;
10004 if (!strcmp (obj->vtable->klass->name, "FieldBuilder"))
10005 inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj);
10006 else if (!strcmp (obj->vtable->klass->name, "MonoField"))
10007 field = ((MonoReflectionField *) obj)->field;
10008 else {
10009 field = NULL; /* prevent compiler warning */
10010 g_assert_not_reached ();
10013 dgclass->fields [i] = *field;
10014 dgclass->fields [i].parent = klass;
10015 dgclass->fields [i].type = mono_class_inflate_generic_type (
10016 field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass));
10017 dgclass->field_generic_types [i] = field->type;
10018 MOVING_GC_REGISTER (&dgclass->field_objects [i]);
10019 dgclass->field_objects [i] = obj;
10021 if (inflated_field) {
10022 g_free (inflated_field);
10023 } else {
10024 dgclass->fields [i].name = g_strdup (dgclass->fields [i].name);
10028 for (i = 0; i < dgclass->count_properties; i++) {
10029 MonoObject *obj = mono_array_get (properties, gpointer, i);
10030 MonoProperty *property = &dgclass->properties [i];
10032 if (!strcmp (obj->vtable->klass->name, "PropertyBuilder")) {
10033 MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *) obj;
10035 property->parent = klass;
10036 property->attrs = pb->attrs;
10037 property->name = mono_string_to_utf8 (pb->name);
10038 if (pb->get_method)
10039 property->get = inflate_method (type, (MonoObject *) pb->get_method);
10040 if (pb->set_method)
10041 property->set = inflate_method (type, (MonoObject *) pb->set_method);
10042 } else if (!strcmp (obj->vtable->klass->name, "MonoProperty")) {
10043 *property = *((MonoReflectionProperty *) obj)->property;
10044 property->name = g_strdup (property->name);
10046 if (property->get)
10047 property->get = inflate_mono_method (klass, property->get, NULL);
10048 if (property->set)
10049 property->set = inflate_mono_method (klass, property->set, NULL);
10050 } else
10051 g_assert_not_reached ();
10054 for (i = 0; i < dgclass->count_events; i++) {
10055 MonoObject *obj = mono_array_get (events, gpointer, i);
10056 MonoEvent *event = &dgclass->events [i];
10058 if (!strcmp (obj->vtable->klass->name, "EventBuilder")) {
10059 MonoReflectionEventBuilder *eb = (MonoReflectionEventBuilder *) obj;
10061 event->parent = klass;
10062 event->attrs = eb->attrs;
10063 event->name = mono_string_to_utf8 (eb->name);
10064 if (eb->add_method)
10065 event->add = inflate_method (type, (MonoObject *) eb->add_method);
10066 if (eb->remove_method)
10067 event->remove = inflate_method (type, (MonoObject *) eb->remove_method);
10068 } else if (!strcmp (obj->vtable->klass->name, "MonoEvent")) {
10069 *event = *((MonoReflectionMonoEvent *) obj)->event;
10070 event->name = g_strdup (event->name);
10072 if (event->add)
10073 event->add = inflate_mono_method (klass, event->add, NULL);
10074 if (event->remove)
10075 event->remove = inflate_mono_method (klass, event->remove, NULL);
10076 } else
10077 g_assert_not_reached ();
10080 dgclass->initialized = TRUE;
10083 static void
10084 ensure_generic_class_runtime_vtable (MonoClass *klass)
10086 MonoClass *gklass = klass->generic_class->container_class;
10087 int i;
10089 if (klass->wastypebuilder)
10090 return;
10092 ensure_runtime_vtable (gklass);
10094 klass->method.count = gklass->method.count;
10095 klass->methods = mono_image_alloc (klass->image, sizeof (MonoMethod*) * (klass->method.count + 1));
10097 for (i = 0; i < klass->method.count; i++) {
10098 klass->methods [i] = mono_class_inflate_generic_method_full (
10099 gklass->methods [i], klass, mono_class_get_context (klass));
10102 klass->interface_count = gklass->interface_count;
10103 klass->interfaces = mono_image_alloc (klass->image, sizeof (MonoClass*) * klass->interface_count);
10104 for (i = 0; i < klass->interface_count; ++i) {
10105 MonoType *iface_type = mono_class_inflate_generic_type (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass));
10106 klass->interfaces [i] = mono_class_from_mono_type (iface_type);
10107 mono_metadata_free_type (iface_type);
10109 ensure_runtime_vtable (klass->interfaces [i]);
10111 klass->interfaces_inited = 1;
10113 /*We can only finish with this klass once it's parent has as well*/
10114 if (gklass->wastypebuilder)
10115 klass->wastypebuilder = TRUE;
10116 return;
10119 static void
10120 ensure_runtime_vtable (MonoClass *klass)
10122 MonoReflectionTypeBuilder *tb = klass->reflection_info;
10123 int i, num, j;
10125 if (!klass->image->dynamic || (!tb && !klass->generic_class) || klass->wastypebuilder)
10126 return;
10127 if (klass->parent)
10128 ensure_runtime_vtable (klass->parent);
10130 if (tb) {
10131 num = tb->ctors? mono_array_length (tb->ctors): 0;
10132 num += tb->num_methods;
10133 klass->method.count = num;
10134 klass->methods = mono_image_alloc (klass->image, sizeof (MonoMethod*) * num);
10135 num = tb->ctors? mono_array_length (tb->ctors): 0;
10136 for (i = 0; i < num; ++i)
10137 klass->methods [i] = ctorbuilder_to_mono_method (klass, mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i));
10138 num = tb->num_methods;
10139 j = i;
10140 for (i = 0; i < num; ++i)
10141 klass->methods [j++] = methodbuilder_to_mono_method (klass, mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i));
10143 if (tb->interfaces) {
10144 klass->interface_count = mono_array_length (tb->interfaces);
10145 klass->interfaces = mono_image_alloc (klass->image, sizeof (MonoClass*) * klass->interface_count);
10146 for (i = 0; i < klass->interface_count; ++i) {
10147 MonoType *iface = mono_type_array_get_and_resolve (tb->interfaces, i);
10148 klass->interfaces [i] = mono_class_from_mono_type (iface);
10149 ensure_runtime_vtable (klass->interfaces [i]);
10151 klass->interfaces_inited = 1;
10153 } else if (klass->generic_class){
10154 ensure_generic_class_runtime_vtable (klass);
10157 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
10158 for (i = 0; i < klass->method.count; ++i)
10159 klass->methods [i]->slot = i;
10161 mono_class_setup_interface_offsets (klass);
10162 mono_class_setup_interface_id (klass);
10166 * The generic vtable is needed even if image->run is not set since some
10167 * runtime code like ves_icall_Type_GetMethodsByName depends on
10168 * method->slot being defined.
10172 * tb->methods could not be freed since it is used for determining
10173 * overrides during dynamic vtable construction.
10177 void
10178 mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
10180 MonoReflectionTypeBuilder *tb;
10181 int i, onum;
10183 *overrides = NULL;
10184 *num_overrides = 0;
10186 g_assert (klass->image->dynamic);
10188 if (!klass->reflection_info)
10189 return;
10191 g_assert (strcmp (((MonoObject*)klass->reflection_info)->vtable->klass->name, "TypeBuilder") == 0);
10193 tb = (MonoReflectionTypeBuilder*)klass->reflection_info;
10195 onum = 0;
10196 if (tb->methods) {
10197 for (i = 0; i < tb->num_methods; ++i) {
10198 MonoReflectionMethodBuilder *mb =
10199 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
10200 if (mb->override_method)
10201 onum ++;
10205 if (onum) {
10206 *overrides = g_new0 (MonoMethod*, onum * 2);
10208 onum = 0;
10209 for (i = 0; i < tb->num_methods; ++i) {
10210 MonoReflectionMethodBuilder *mb =
10211 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
10212 if (mb->override_method) {
10213 (*overrides) [onum * 2] =
10214 mb->override_method->method;
10215 (*overrides) [onum * 2 + 1] =
10216 mb->mhandle;
10218 /* FIXME: What if 'override_method' is a MethodBuilder ? */
10219 g_assert (mb->override_method->method);
10220 g_assert (mb->mhandle);
10222 onum ++;
10227 *num_overrides = onum;
10230 static void
10231 typebuilder_setup_fields (MonoClass *klass)
10233 MonoReflectionTypeBuilder *tb = klass->reflection_info;
10234 MonoReflectionFieldBuilder *fb;
10235 MonoClassField *field;
10236 MonoImage *image = klass->image;
10237 const char *p, *p2;
10238 int i;
10239 guint32 len, idx, real_size = 0;
10241 klass->field.count = tb->num_fields;
10242 klass->field.first = 0;
10244 if (tb->class_size) {
10245 g_assert ((tb->packing_size & 0xfffffff0) == 0);
10246 klass->packing_size = tb->packing_size;
10247 real_size = klass->instance_size + tb->class_size;
10250 if (!klass->field.count) {
10251 klass->instance_size = MAX (klass->instance_size, real_size);
10252 return;
10255 klass->fields = image_g_new0 (image, MonoClassField, klass->field.count);
10256 mono_class_alloc_ext (klass);
10257 klass->ext->field_def_values = image_g_new0 (image, MonoFieldDefaultValue, klass->field.count);
10259 for (i = 0; i < klass->field.count; ++i) {
10260 fb = mono_array_get (tb->fields, gpointer, i);
10261 field = &klass->fields [i];
10262 field->name = mono_string_to_utf8_image (image, fb->name);
10263 if (fb->attrs) {
10264 field->type = mono_metadata_type_dup (klass->image, mono_reflection_type_get_handle ((MonoReflectionType*)fb->type));
10265 field->type->attrs = fb->attrs;
10266 } else {
10267 field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type);
10269 if ((fb->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) && fb->rva_data)
10270 klass->ext->field_def_values [i].data = mono_array_addr (fb->rva_data, char, 0);
10271 if (fb->offset != -1)
10272 field->offset = fb->offset;
10273 field->parent = klass;
10274 fb->handle = field;
10275 mono_save_custom_attrs (klass->image, field, fb->cattrs);
10277 if (fb->def_value) {
10278 MonoDynamicImage *assembly = (MonoDynamicImage*)klass->image;
10279 field->type->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT;
10280 idx = encode_constant (assembly, fb->def_value, &klass->ext->field_def_values [i].def_type);
10281 /* Copy the data from the blob since it might get realloc-ed */
10282 p = assembly->blob.data + idx;
10283 len = mono_metadata_decode_blob_size (p, &p2);
10284 len += p2 - p;
10285 klass->ext->field_def_values [i].data = mono_image_alloc (image, len);
10286 memcpy ((gpointer)klass->ext->field_def_values [i].data, p, len);
10290 klass->instance_size = MAX (klass->instance_size, real_size);
10291 mono_class_layout_fields (klass);
10294 static void
10295 typebuilder_setup_properties (MonoClass *klass)
10297 MonoReflectionTypeBuilder *tb = klass->reflection_info;
10298 MonoReflectionPropertyBuilder *pb;
10299 MonoImage *image = klass->image;
10300 MonoProperty *properties;
10301 int i;
10303 if (!klass->ext)
10304 klass->ext = image_g_new0 (image, MonoClassExt, 1);
10306 klass->ext->property.count = tb->properties ? mono_array_length (tb->properties) : 0;
10307 klass->ext->property.first = 0;
10309 properties = image_g_new0 (image, MonoProperty, klass->ext->property.count);
10310 klass->ext->properties = properties;
10311 for (i = 0; i < klass->ext->property.count; ++i) {
10312 pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
10313 properties [i].parent = klass;
10314 properties [i].attrs = pb->attrs;
10315 properties [i].name = mono_string_to_utf8_image (image, pb->name);
10316 if (pb->get_method)
10317 properties [i].get = pb->get_method->mhandle;
10318 if (pb->set_method)
10319 properties [i].set = pb->set_method->mhandle;
10321 mono_save_custom_attrs (klass->image, &properties [i], pb->cattrs);
10325 MonoReflectionEvent *
10326 mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
10328 MonoEvent *event = g_new0 (MonoEvent, 1);
10329 MonoClass *klass;
10330 int j;
10332 klass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)tb));
10334 event->parent = klass;
10335 event->attrs = eb->attrs;
10336 event->name = mono_string_to_utf8 (eb->name);
10337 if (eb->add_method)
10338 event->add = eb->add_method->mhandle;
10339 if (eb->remove_method)
10340 event->remove = eb->remove_method->mhandle;
10341 if (eb->raise_method)
10342 event->raise = eb->raise_method->mhandle;
10344 if (eb->other_methods) {
10345 event->other = g_new0 (MonoMethod*, mono_array_length (eb->other_methods) + 1);
10346 for (j = 0; j < mono_array_length (eb->other_methods); ++j) {
10347 MonoReflectionMethodBuilder *mb =
10348 mono_array_get (eb->other_methods,
10349 MonoReflectionMethodBuilder*, j);
10350 event->other [j] = mb->mhandle;
10354 return mono_event_get_object (mono_object_domain (tb), klass, event);
10357 static void
10358 typebuilder_setup_events (MonoClass *klass)
10360 MonoReflectionTypeBuilder *tb = klass->reflection_info;
10361 MonoReflectionEventBuilder *eb;
10362 MonoImage *image = klass->image;
10363 MonoEvent *events;
10364 int i, j;
10366 if (!klass->ext)
10367 klass->ext = image_g_new0 (image, MonoClassExt, 1);
10369 klass->ext->event.count = tb->events ? mono_array_length (tb->events) : 0;
10370 klass->ext->event.first = 0;
10372 events = image_g_new0 (image, MonoEvent, klass->ext->event.count);
10373 klass->ext->events = events;
10374 for (i = 0; i < klass->ext->event.count; ++i) {
10375 eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
10376 events [i].parent = klass;
10377 events [i].attrs = eb->attrs;
10378 events [i].name = mono_string_to_utf8_image (image, eb->name);
10379 if (eb->add_method)
10380 events [i].add = eb->add_method->mhandle;
10381 if (eb->remove_method)
10382 events [i].remove = eb->remove_method->mhandle;
10383 if (eb->raise_method)
10384 events [i].raise = eb->raise_method->mhandle;
10386 if (eb->other_methods) {
10387 events [i].other = image_g_new0 (image, MonoMethod*, mono_array_length (eb->other_methods) + 1);
10388 for (j = 0; j < mono_array_length (eb->other_methods); ++j) {
10389 MonoReflectionMethodBuilder *mb =
10390 mono_array_get (eb->other_methods,
10391 MonoReflectionMethodBuilder*, j);
10392 events [i].other [j] = mb->mhandle;
10395 mono_save_custom_attrs (klass->image, &events [i], eb->cattrs);
10399 static gboolean
10400 remove_instantiations_of (gpointer key,
10401 gpointer value,
10402 gpointer user_data)
10404 MonoType *type = (MonoType*)key;
10405 MonoClass *klass = (MonoClass*)user_data;
10407 if ((type->type == MONO_TYPE_GENERICINST) && (type->data.generic_class->container_class == klass))
10408 return TRUE;
10409 else
10410 return FALSE;
10413 static void
10414 check_array_for_usertypes (MonoArray *arr)
10416 int i;
10418 if (!arr)
10419 return;
10421 for (i = 0; i < mono_array_length (arr); ++i)
10422 RESOLVE_ARRAY_TYPE_ELEMENT (arr, i);
10425 MonoReflectionType*
10426 mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb)
10428 MonoClass *klass;
10429 MonoDomain* domain;
10430 MonoReflectionType* res;
10431 int i, j;
10433 MONO_ARCH_SAVE_REGS;
10435 domain = mono_object_domain (tb);
10436 klass = mono_class_from_mono_type (tb->type.type);
10439 * Check for user defined Type subclasses.
10441 RESOLVE_TYPE (tb->parent);
10442 check_array_for_usertypes (tb->interfaces);
10443 if (tb->fields) {
10444 for (i = 0; i < mono_array_length (tb->fields); ++i) {
10445 MonoReflectionFieldBuilder *fb = mono_array_get (tb->fields, gpointer, i);
10446 if (fb) {
10447 RESOLVE_TYPE (fb->type);
10448 check_array_for_usertypes (fb->modreq);
10449 check_array_for_usertypes (fb->modopt);
10450 if (fb->marshal_info && fb->marshal_info->marshaltyperef)
10451 RESOLVE_TYPE (fb->marshal_info->marshaltyperef);
10455 if (tb->methods) {
10456 for (i = 0; i < mono_array_length (tb->methods); ++i) {
10457 MonoReflectionMethodBuilder *mb = mono_array_get (tb->methods, gpointer, i);
10458 if (mb) {
10459 RESOLVE_TYPE (mb->rtype);
10460 check_array_for_usertypes (mb->return_modreq);
10461 check_array_for_usertypes (mb->return_modopt);
10462 check_array_for_usertypes (mb->parameters);
10463 if (mb->param_modreq)
10464 for (j = 0; j < mono_array_length (mb->param_modreq); ++j)
10465 check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j));
10466 if (mb->param_modopt)
10467 for (j = 0; j < mono_array_length (mb->param_modopt); ++j)
10468 check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j));
10472 if (tb->ctors) {
10473 for (i = 0; i < mono_array_length (tb->ctors); ++i) {
10474 MonoReflectionCtorBuilder *mb = mono_array_get (tb->ctors, gpointer, i);
10475 if (mb) {
10476 check_array_for_usertypes (mb->parameters);
10477 if (mb->param_modreq)
10478 for (j = 0; j < mono_array_length (mb->param_modreq); ++j)
10479 check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j));
10480 if (mb->param_modopt)
10481 for (j = 0; j < mono_array_length (mb->param_modopt); ++j)
10482 check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j));
10487 mono_save_custom_attrs (klass->image, klass, tb->cattrs);
10490 * we need to lock the domain because the lock will be taken inside
10491 * So, we need to keep the locking order correct.
10493 mono_loader_lock ();
10494 mono_domain_lock (domain);
10495 if (klass->wastypebuilder) {
10496 mono_domain_unlock (domain);
10497 mono_loader_unlock ();
10498 return mono_type_get_object (mono_object_domain (tb), &klass->byval_arg);
10501 * Fields to set in klass:
10502 * the various flags: delegate/unicode/contextbound etc.
10504 klass->flags = tb->attrs;
10505 klass->has_cctor = 1;
10506 klass->has_finalize = 1;
10508 #if 0
10509 if (!((MonoDynamicImage*)klass->image)->run) {
10510 if (klass->generic_container) {
10511 /* FIXME: The code below can't handle generic classes */
10512 klass->wastypebuilder = TRUE;
10513 mono_loader_unlock ();
10514 mono_domain_unlock (domain);
10515 return mono_type_get_object (mono_object_domain (tb), &klass->byval_arg);
10518 #endif
10520 /* enums are done right away */
10521 if (!klass->enumtype)
10522 ensure_runtime_vtable (klass);
10524 if (tb->subtypes) {
10525 for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
10526 MonoReflectionTypeBuilder *subtb = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
10527 mono_class_alloc_ext (klass);
10528 klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)subtb)));
10532 klass->nested_classes_inited = TRUE;
10534 /* fields and object layout */
10535 if (klass->parent) {
10536 if (!klass->parent->size_inited)
10537 mono_class_init (klass->parent);
10538 klass->instance_size = klass->parent->instance_size;
10539 klass->sizes.class_size = 0;
10540 klass->min_align = klass->parent->min_align;
10541 /* if the type has no fields we won't call the field_setup
10542 * routine which sets up klass->has_references.
10544 klass->has_references |= klass->parent->has_references;
10545 } else {
10546 klass->instance_size = sizeof (MonoObject);
10547 klass->min_align = 1;
10550 /* FIXME: handle packing_size and instance_size */
10551 typebuilder_setup_fields (klass);
10553 typebuilder_setup_properties (klass);
10555 typebuilder_setup_events (klass);
10557 klass->wastypebuilder = TRUE;
10560 * If we are a generic TypeBuilder, there might be instantiations in the type cache
10561 * which have type System.Reflection.MonoGenericClass, but after the type is created,
10562 * we want to return normal System.MonoType objects, so clear these out from the cache.
10564 if (domain->type_hash && klass->generic_container)
10565 mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of, klass);
10567 mono_domain_unlock (domain);
10568 mono_loader_unlock ();
10570 if (klass->enumtype && !mono_class_is_valid_enum (klass)) {
10571 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
10572 mono_raise_exception (mono_get_exception_type_load (tb->name, NULL));
10575 res = mono_type_get_object (mono_object_domain (tb), &klass->byval_arg);
10576 g_assert (res != (MonoReflectionType*)tb);
10578 return res;
10581 void
10582 mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
10584 MonoGenericParamFull *param;
10585 MonoImage *image;
10586 MonoClass *pklass;
10588 MONO_ARCH_SAVE_REGS;
10590 param = g_new0 (MonoGenericParamFull, 1);
10592 if (gparam->mbuilder) {
10593 if (!gparam->mbuilder->generic_container) {
10594 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)gparam->mbuilder->type;
10595 MonoClass *klass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)tb));
10596 gparam->mbuilder->generic_container = mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
10597 gparam->mbuilder->generic_container->is_method = TRUE;
10599 * Cannot set owner.method, since the MonoMethod is not created yet.
10600 * Set the image field instead, so type_in_image () works.
10602 gparam->mbuilder->generic_container->image = klass->image;
10604 param->param.owner = gparam->mbuilder->generic_container;
10605 } else if (gparam->tbuilder) {
10606 if (!gparam->tbuilder->generic_container) {
10607 MonoClass *klass = mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder));
10608 gparam->tbuilder->generic_container = mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
10609 gparam->tbuilder->generic_container->owner.klass = klass;
10611 param->param.owner = gparam->tbuilder->generic_container;
10614 param->info.name = mono_string_to_utf8 (gparam->name);
10615 param->param.num = gparam->index;
10617 image = &gparam->tbuilder->module->dynamic_image->image;
10618 pklass = mono_class_from_generic_parameter ((MonoGenericParam *) param, image, gparam->mbuilder != NULL);
10620 gparam->type.type = &pklass->byval_arg;
10622 MOVING_GC_REGISTER (&pklass->reflection_info);
10623 pklass->reflection_info = gparam; /* FIXME: GC pin gparam */
10626 MonoArray *
10627 mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
10629 MonoReflectionModuleBuilder *module = sig->module;
10630 MonoDynamicImage *assembly = module != NULL ? module->dynamic_image : NULL;
10631 guint32 na = sig->arguments ? mono_array_length (sig->arguments) : 0;
10632 guint32 buflen, i;
10633 MonoArray *result;
10634 SigBuffer buf;
10636 check_array_for_usertypes (sig->arguments);
10638 sigbuffer_init (&buf, 32);
10640 sigbuffer_add_value (&buf, 0x07);
10641 sigbuffer_add_value (&buf, na);
10642 if (assembly != NULL){
10643 for (i = 0; i < na; ++i) {
10644 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType*, i);
10645 encode_reflection_type (assembly, type, &buf);
10649 buflen = buf.p - buf.buf;
10650 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
10651 memcpy (mono_array_addr (result, char, 0), buf.buf, buflen);
10652 sigbuffer_free (&buf);
10654 return result;
10657 MonoArray *
10658 mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig)
10660 MonoDynamicImage *assembly = sig->module->dynamic_image;
10661 guint32 na = sig->arguments ? mono_array_length (sig->arguments) : 0;
10662 guint32 buflen, i;
10663 MonoArray *result;
10664 SigBuffer buf;
10666 check_array_for_usertypes (sig->arguments);
10668 sigbuffer_init (&buf, 32);
10670 sigbuffer_add_value (&buf, 0x06);
10671 for (i = 0; i < na; ++i) {
10672 MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType*, i);
10673 encode_reflection_type (assembly, type, &buf);
10676 buflen = buf.p - buf.buf;
10677 result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
10678 memcpy (mono_array_addr (result, char, 0), buf.buf, buflen);
10679 sigbuffer_free (&buf);
10681 return result;
10684 void
10685 mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
10687 ReflectionMethodBuilder rmb;
10688 MonoMethodSignature *sig;
10689 MonoClass *klass;
10690 GSList *l;
10691 int i;
10693 sig = dynamic_method_to_signature (mb);
10695 reflection_methodbuilder_from_dynamic_method (&rmb, mb);
10698 * Resolve references.
10701 * Every second entry in the refs array is reserved for storing handle_class,
10702 * which is needed by the ldtoken implementation in the JIT.
10704 rmb.nrefs = mb->nrefs;
10705 rmb.refs = g_new0 (gpointer, mb->nrefs + 1);
10706 for (i = 0; i < mb->nrefs; i += 2) {
10707 MonoClass *handle_class;
10708 gpointer ref;
10709 MonoObject *obj = mono_array_get (mb->refs, MonoObject*, i);
10711 if (strcmp (obj->vtable->klass->name, "DynamicMethod") == 0) {
10712 MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)obj;
10714 * The referenced DynamicMethod should already be created by the managed
10715 * code, except in the case of circular references. In that case, we store
10716 * method in the refs array, and fix it up later when the referenced
10717 * DynamicMethod is created.
10719 if (method->mhandle) {
10720 ref = method->mhandle;
10721 } else {
10722 /* FIXME: GC object stored in unmanaged memory */
10723 ref = method;
10725 /* FIXME: GC object stored in unmanaged memory */
10726 method->referenced_by = g_slist_append (method->referenced_by, mb);
10728 handle_class = mono_defaults.methodhandle_class;
10729 } else {
10730 MonoException *ex = NULL;
10731 ref = resolve_object (mb->module->image, obj, &handle_class, NULL);
10732 if (!ref)
10733 ex = mono_get_exception_type_load (NULL, NULL);
10734 else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
10735 ex = mono_security_core_clr_ensure_dynamic_method_resolved_object (ref, handle_class);
10737 if (ex) {
10738 g_free (rmb.refs);
10739 mono_raise_exception (ex);
10740 return;
10744 rmb.refs [i] = ref; /* FIXME: GC object stored in unmanaged memory (change also resolve_object() signature) */
10745 rmb.refs [i + 1] = handle_class;
10748 klass = mb->owner ? mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner)) : mono_defaults.object_class;
10750 mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
10752 /* Fix up refs entries pointing at us */
10753 for (l = mb->referenced_by; l; l = l->next) {
10754 MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)l->data;
10755 MonoMethodWrapper *wrapper = (MonoMethodWrapper*)method->mhandle;
10756 gpointer *data;
10758 g_assert (method->mhandle);
10760 data = (gpointer*)wrapper->method_data;
10761 for (i = 0; i < GPOINTER_TO_UINT (data [0]); i += 2) {
10762 if ((data [i + 1] == mb) && (data [i + 1 + 1] == mono_defaults.methodhandle_class))
10763 data [i + 1] = mb->mhandle;
10766 g_slist_free (mb->referenced_by);
10768 g_free (rmb.refs);
10770 /* ilgen is no longer needed */
10771 mb->ilgen = NULL;
10774 #endif /* DISABLE_REFLECTION_EMIT */
10776 void
10777 mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb)
10779 g_assert (mb);
10781 if (mb->mhandle)
10782 mono_runtime_free_method (
10783 mono_object_get_domain ((MonoObject*)mb), mb->mhandle);
10788 * mono_reflection_is_valid_dynamic_token:
10790 * Returns TRUE if token is valid.
10793 gboolean
10794 mono_reflection_is_valid_dynamic_token (MonoDynamicImage *image, guint32 token)
10796 return mono_g_hash_table_lookup (image->tokens, GUINT_TO_POINTER (token)) != NULL;
10799 #ifndef DISABLE_REFLECTION_EMIT
10802 * mono_reflection_lookup_dynamic_token:
10804 * Finish the Builder object pointed to by TOKEN and return the corresponding
10805 * runtime structure. If HANDLE_CLASS is not NULL, it is set to the class required by
10806 * mono_ldtoken. If valid_token is TRUE, assert if it is not found in the token->object
10807 * mapping table.
10809 * LOCKING: Take the loader lock
10811 gpointer
10812 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
10814 MonoDynamicImage *assembly = (MonoDynamicImage*)image;
10815 MonoObject *obj;
10816 MonoClass *klass;
10818 mono_loader_lock ();
10819 obj = mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
10820 mono_loader_unlock ();
10821 if (!obj) {
10822 if (valid_token)
10823 g_error ("Could not find required dynamic token 0x%08x", token);
10824 else
10825 return NULL;
10828 if (!handle_class)
10829 handle_class = &klass;
10830 return resolve_object (image, obj, handle_class, context);
10834 * ensure_complete_type:
10836 * Ensure that KLASS is completed if it is a dynamic type, or references
10837 * dynamic types.
10839 static void
10840 ensure_complete_type (MonoClass *klass)
10842 if (klass->image->dynamic && !klass->wastypebuilder) {
10843 MonoReflectionTypeBuilder *tb = klass->reflection_info;
10845 mono_domain_try_type_resolve (mono_domain_get (), NULL, (MonoObject*)tb);
10847 // Asserting here could break a lot of code
10848 //g_assert (klass->wastypebuilder);
10851 if (klass->generic_class) {
10852 MonoGenericInst *inst = klass->generic_class->context.class_inst;
10853 int i;
10855 for (i = 0; i < inst->type_argc; ++i) {
10856 ensure_complete_type (mono_class_from_mono_type (inst->type_argv [i]));
10861 static gpointer
10862 resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context)
10864 gpointer result = NULL;
10866 if (strcmp (obj->vtable->klass->name, "String") == 0) {
10867 result = mono_string_intern ((MonoString*)obj);
10868 *handle_class = NULL;
10869 g_assert (result);
10870 } else if (strcmp (obj->vtable->klass->name, "MonoType") == 0) {
10871 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj);
10872 if (context) {
10873 MonoType *inflated = mono_class_inflate_generic_type (type, context);
10874 result = mono_class_from_mono_type (inflated);
10875 mono_metadata_free_type (inflated);
10876 } else {
10877 result = mono_class_from_mono_type (type);
10879 *handle_class = mono_defaults.typehandle_class;
10880 g_assert (result);
10881 } else if (strcmp (obj->vtable->klass->name, "MonoMethod") == 0 ||
10882 strcmp (obj->vtable->klass->name, "MonoCMethod") == 0 ||
10883 strcmp (obj->vtable->klass->name, "MonoGenericCMethod") == 0 ||
10884 strcmp (obj->vtable->klass->name, "MonoGenericMethod") == 0) {
10885 result = ((MonoReflectionMethod*)obj)->method;
10886 if (context)
10887 result = mono_class_inflate_generic_method (result, context);
10888 *handle_class = mono_defaults.methodhandle_class;
10889 g_assert (result);
10890 } else if (strcmp (obj->vtable->klass->name, "MethodBuilder") == 0) {
10891 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder*)obj;
10892 result = mb->mhandle;
10893 if (!result) {
10894 /* Type is not yet created */
10895 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
10897 mono_domain_try_type_resolve (mono_domain_get (), NULL, (MonoObject*)tb);
10900 * Hopefully this has been filled in by calling CreateType() on the
10901 * TypeBuilder.
10904 * TODO: This won't work if the application finishes another
10905 * TypeBuilder instance instead of this one.
10907 result = mb->mhandle;
10909 if (context)
10910 result = mono_class_inflate_generic_method (result, context);
10911 *handle_class = mono_defaults.methodhandle_class;
10912 } else if (strcmp (obj->vtable->klass->name, "ConstructorBuilder") == 0) {
10913 MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder*)obj;
10915 result = cb->mhandle;
10916 if (!result) {
10917 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)cb->type;
10919 mono_domain_try_type_resolve (mono_domain_get (), NULL, (MonoObject*)tb);
10920 result = cb->mhandle;
10922 if (context)
10923 result = mono_class_inflate_generic_method (result, context);
10924 *handle_class = mono_defaults.methodhandle_class;
10925 } else if (strcmp (obj->vtable->klass->name, "MonoField") == 0) {
10926 MonoClassField *field = ((MonoReflectionField*)obj)->field;
10928 ensure_complete_type (field->parent);
10929 if (context) {
10930 MonoType *inflated = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
10931 MonoClass *class = mono_class_from_mono_type (inflated);
10932 MonoClassField *inflated_field;
10933 gpointer iter = NULL;
10934 mono_metadata_free_type (inflated);
10935 while ((inflated_field = mono_class_get_fields (class, &iter))) {
10936 if (!strcmp (field->name, inflated_field->name))
10937 break;
10939 g_assert (inflated_field && !strcmp (field->name, inflated_field->name));
10940 result = inflated_field;
10941 } else {
10942 result = field;
10944 *handle_class = mono_defaults.fieldhandle_class;
10945 g_assert (result);
10946 } else if (strcmp (obj->vtable->klass->name, "FieldBuilder") == 0) {
10947 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder*)obj;
10948 result = fb->handle;
10950 if (!result) {
10951 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)fb->typeb;
10953 mono_domain_try_type_resolve (mono_domain_get (), NULL, (MonoObject*)tb);
10954 result = fb->handle;
10957 if (fb->handle && fb->handle->parent->generic_container) {
10958 MonoClass *klass = fb->handle->parent;
10959 MonoType *type = mono_class_inflate_generic_type (&klass->byval_arg, context);
10960 MonoClass *inflated = mono_class_from_mono_type (type);
10962 result = mono_class_get_field_from_name (inflated, mono_field_get_name (fb->handle));
10963 g_assert (result);
10964 mono_metadata_free_type (type);
10966 *handle_class = mono_defaults.fieldhandle_class;
10967 } else if (strcmp (obj->vtable->klass->name, "TypeBuilder") == 0) {
10968 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
10969 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb);
10970 MonoClass *klass;
10972 klass = type->data.klass;
10973 if (klass->wastypebuilder) {
10974 /* Already created */
10975 result = klass;
10977 else {
10978 mono_domain_try_type_resolve (mono_domain_get (), NULL, (MonoObject*)tb);
10979 result = type->data.klass;
10980 g_assert (result);
10982 *handle_class = mono_defaults.typehandle_class;
10983 } else if (strcmp (obj->vtable->klass->name, "SignatureHelper") == 0) {
10984 MonoReflectionSigHelper *helper = (MonoReflectionSigHelper*)obj;
10985 MonoMethodSignature *sig;
10986 int nargs, i;
10988 if (helper->arguments)
10989 nargs = mono_array_length (helper->arguments);
10990 else
10991 nargs = 0;
10993 sig = mono_metadata_signature_alloc (image, nargs);
10994 sig->explicit_this = helper->call_conv & 64 ? 1 : 0;
10995 sig->hasthis = helper->call_conv & 32 ? 1 : 0;
10997 if (helper->call_conv == 0) /* unmanaged */
10998 sig->call_convention = helper->unmanaged_call_conv - 1;
10999 else
11000 if (helper->call_conv & 0x02)
11001 sig->call_convention = MONO_CALL_VARARG;
11002 else
11003 sig->call_convention = MONO_CALL_DEFAULT;
11005 sig->param_count = nargs;
11006 /* TODO: Copy type ? */
11007 sig->ret = helper->return_type->type;
11008 for (i = 0; i < nargs; ++i)
11009 sig->params [i] = mono_type_array_get_and_resolve (helper->arguments, i);
11011 result = sig;
11012 *handle_class = NULL;
11013 } else if (strcmp (obj->vtable->klass->name, "DynamicMethod") == 0) {
11014 MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)obj;
11015 /* Already created by the managed code */
11016 g_assert (method->mhandle);
11017 result = method->mhandle;
11018 *handle_class = mono_defaults.methodhandle_class;
11019 } else if (strcmp (obj->vtable->klass->name, "GenericTypeParameterBuilder") == 0) {
11020 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj);
11021 type = mono_class_inflate_generic_type (type, context);
11022 result = mono_class_from_mono_type (type);
11023 *handle_class = mono_defaults.typehandle_class;
11024 g_assert (result);
11025 mono_metadata_free_type (type);
11026 } else if (strcmp (obj->vtable->klass->name, "MonoGenericClass") == 0) {
11027 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj);
11028 type = mono_class_inflate_generic_type (type, context);
11029 result = mono_class_from_mono_type (type);
11030 *handle_class = mono_defaults.typehandle_class;
11031 g_assert (result);
11032 mono_metadata_free_type (type);
11033 } else if (strcmp (obj->vtable->klass->name, "FieldOnTypeBuilderInst") == 0) {
11034 MonoReflectionFieldOnTypeBuilderInst *f = (MonoReflectionFieldOnTypeBuilderInst*)obj;
11035 MonoClass *inflated;
11036 MonoType *type;
11038 type = mono_class_inflate_generic_type (mono_reflection_type_get_handle ((MonoReflectionType*)f->inst), context);
11039 inflated = mono_class_from_mono_type (type);
11041 g_assert (f->fb->handle);
11042 result = mono_class_get_field_from_name (inflated, mono_field_get_name (f->fb->handle));
11043 g_assert (result);
11044 mono_metadata_free_type (type);
11045 *handle_class = mono_defaults.fieldhandle_class;
11046 } else if (strcmp (obj->vtable->klass->name, "ConstructorOnTypeBuilderInst") == 0) {
11047 MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
11048 MonoType *type = mono_class_inflate_generic_type (mono_reflection_type_get_handle ((MonoReflectionType*)c->inst), context);
11049 MonoClass *inflated_klass = mono_class_from_mono_type (type);
11050 g_assert (c->cb->mhandle);
11051 result = inflate_mono_method (inflated_klass, c->cb->mhandle, (MonoObject*)c->cb);
11052 *handle_class = mono_defaults.methodhandle_class;
11053 mono_metadata_free_type (type);
11054 } else if (strcmp (obj->vtable->klass->name, "MethodOnTypeBuilderInst") == 0) {
11055 MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
11056 MonoType *type = mono_class_inflate_generic_type (mono_reflection_type_get_handle ((MonoReflectionType*)m->inst), context);
11057 MonoClass *inflated_klass = mono_class_from_mono_type (type);
11058 g_assert (m->mb->mhandle);
11059 result = inflate_mono_method (inflated_klass, m->mb->mhandle, (MonoObject*)m->mb);
11060 *handle_class = mono_defaults.methodhandle_class;
11061 mono_metadata_free_type (type);
11062 } else if (is_sre_array (mono_object_get_class(obj)) ||
11063 is_sre_byref (mono_object_get_class(obj)) ||
11064 is_sre_pointer (mono_object_get_class(obj))) {
11065 MonoReflectionType *ref_type = (MonoReflectionType *)obj;
11066 MonoType *type = mono_reflection_type_get_handle (ref_type);
11067 result = mono_class_from_mono_type (type);
11068 *handle_class = mono_defaults.typehandle_class;
11069 } else {
11070 g_print (obj->vtable->klass->name);
11071 g_assert_not_reached ();
11073 return result;
11076 #else /* DISABLE_REFLECTION_EMIT */
11078 MonoArray*
11079 mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
11081 g_assert_not_reached ();
11082 return NULL;
11085 void
11086 mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
11088 g_assert_not_reached ();
11091 void
11092 mono_reflection_setup_generic_class (MonoReflectionTypeBuilder *tb)
11094 g_assert_not_reached ();
11097 void
11098 mono_reflection_create_generic_class (MonoReflectionTypeBuilder *tb)
11100 g_assert_not_reached ();
11103 void
11104 mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
11106 g_assert_not_reached ();
11109 void
11110 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
11112 g_error ("This mono runtime was configured with --enable-minimal=reflection_emit, so System.Reflection.Emit is not supported.");
11115 void
11116 mono_image_module_basic_init (MonoReflectionModuleBuilder *moduleb)
11118 g_assert_not_reached ();
11121 void
11122 mono_image_set_wrappers_type (MonoReflectionModuleBuilder *moduleb, MonoReflectionType *type)
11124 g_assert_not_reached ();
11127 MonoReflectionModule *
11128 mono_image_load_module_dynamic (MonoReflectionAssemblyBuilder *ab, MonoString *fileName)
11130 g_assert_not_reached ();
11131 return NULL;
11134 guint32
11135 mono_image_insert_string (MonoReflectionModuleBuilder *module, MonoString *str)
11137 g_assert_not_reached ();
11138 return 0;
11141 guint32
11142 mono_image_create_method_token (MonoDynamicImage *assembly, MonoObject *obj, MonoArray *opt_param_types)
11144 g_assert_not_reached ();
11145 return 0;
11148 guint32
11149 mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
11150 gboolean create_methodspec, gboolean register_token)
11152 g_assert_not_reached ();
11153 return 0;
11156 void
11157 mono_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObject *obj)
11161 void
11162 mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *methods,
11163 MonoArray *ctors, MonoArray *fields, MonoArray *properties,
11164 MonoArray *events)
11166 g_assert_not_reached ();
11169 void
11170 mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
11172 *overrides = NULL;
11173 *num_overrides = 0;
11176 MonoReflectionEvent *
11177 mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
11179 g_assert_not_reached ();
11180 return NULL;
11183 MonoReflectionType*
11184 mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb)
11186 g_assert_not_reached ();
11187 return NULL;
11190 void
11191 mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
11193 g_assert_not_reached ();
11196 MonoArray *
11197 mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
11199 g_assert_not_reached ();
11200 return NULL;
11203 MonoArray *
11204 mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig)
11206 g_assert_not_reached ();
11207 return NULL;
11210 void
11211 mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
11215 gpointer
11216 mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
11218 return NULL;
11221 MonoType*
11222 mono_reflection_type_get_handle (MonoReflectionType* ref)
11224 if (!ref)
11225 return NULL;
11226 return ref->type;
11229 #endif /* DISABLE_REFLECTION_EMIT */
11231 /* SECURITY_ACTION_* are defined in mono/metadata/tabledefs.h */
11232 const static guint32 declsec_flags_map[] = {
11233 0x00000000, /* empty */
11234 MONO_DECLSEC_FLAG_REQUEST, /* SECURITY_ACTION_REQUEST (x01) */
11235 MONO_DECLSEC_FLAG_DEMAND, /* SECURITY_ACTION_DEMAND (x02) */
11236 MONO_DECLSEC_FLAG_ASSERT, /* SECURITY_ACTION_ASSERT (x03) */
11237 MONO_DECLSEC_FLAG_DENY, /* SECURITY_ACTION_DENY (x04) */
11238 MONO_DECLSEC_FLAG_PERMITONLY, /* SECURITY_ACTION_PERMITONLY (x05) */
11239 MONO_DECLSEC_FLAG_LINKDEMAND, /* SECURITY_ACTION_LINKDEMAND (x06) */
11240 MONO_DECLSEC_FLAG_INHERITANCEDEMAND, /* SECURITY_ACTION_INHERITANCEDEMAND (x07) */
11241 MONO_DECLSEC_FLAG_REQUEST_MINIMUM, /* SECURITY_ACTION_REQUEST_MINIMUM (x08) */
11242 MONO_DECLSEC_FLAG_REQUEST_OPTIONAL, /* SECURITY_ACTION_REQUEST_OPTIONAL (x09) */
11243 MONO_DECLSEC_FLAG_REQUEST_REFUSE, /* SECURITY_ACTION_REQUEST_REFUSE (x0A) */
11244 MONO_DECLSEC_FLAG_PREJIT_GRANT, /* SECURITY_ACTION_PREJIT_GRANT (x0B) */
11245 MONO_DECLSEC_FLAG_PREJIT_DENY, /* SECURITY_ACTION_PREJIT_DENY (x0C) */
11246 MONO_DECLSEC_FLAG_NONCAS_DEMAND, /* SECURITY_ACTION_NONCAS_DEMAND (x0D) */
11247 MONO_DECLSEC_FLAG_NONCAS_LINKDEMAND, /* SECURITY_ACTION_NONCAS_LINKDEMAND (x0E) */
11248 MONO_DECLSEC_FLAG_NONCAS_INHERITANCEDEMAND, /* SECURITY_ACTION_NONCAS_INHERITANCEDEMAND (x0F) */
11249 MONO_DECLSEC_FLAG_LINKDEMAND_CHOICE, /* SECURITY_ACTION_LINKDEMAND_CHOICE (x10) */
11250 MONO_DECLSEC_FLAG_INHERITANCEDEMAND_CHOICE, /* SECURITY_ACTION_INHERITANCEDEMAND_CHOICE (x11) */
11251 MONO_DECLSEC_FLAG_DEMAND_CHOICE, /* SECURITY_ACTION_DEMAND_CHOICE (x12) */
11255 * Returns flags that includes all available security action associated to the handle.
11256 * @token: metadata token (either for a class or a method)
11257 * @image: image where resides the metadata.
11259 static guint32
11260 mono_declsec_get_flags (MonoImage *image, guint32 token)
11262 int index = mono_metadata_declsec_from_index (image, token);
11263 MonoTableInfo *t = &image->tables [MONO_TABLE_DECLSECURITY];
11264 guint32 result = 0;
11265 guint32 action;
11266 int i;
11268 /* HasSecurity can be present for other, not specially encoded, attributes,
11269 e.g. SuppressUnmanagedCodeSecurityAttribute */
11270 if (index < 0)
11271 return 0;
11273 for (i = index; i < t->rows; i++) {
11274 guint32 cols [MONO_DECL_SECURITY_SIZE];
11276 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
11277 if (cols [MONO_DECL_SECURITY_PARENT] != token)
11278 break;
11280 action = cols [MONO_DECL_SECURITY_ACTION];
11281 if ((action >= MONO_DECLSEC_ACTION_MIN) && (action <= MONO_DECLSEC_ACTION_MAX)) {
11282 result |= declsec_flags_map [action];
11283 } else {
11284 g_assert_not_reached ();
11287 return result;
11291 * Get the security actions (in the form of flags) associated with the specified method.
11293 * @method: The method for which we want the declarative security flags.
11294 * Return the declarative security flags for the method (only).
11296 * Note: To keep MonoMethod size down we do not cache the declarative security flags
11297 * (except for the stack modifiers which are kept in the MonoJitInfo structure)
11299 guint32
11300 mono_declsec_flags_from_method (MonoMethod *method)
11302 if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) {
11303 /* FIXME: No cache (for the moment) */
11304 guint32 idx = mono_method_get_index (method);
11305 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11306 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
11307 return mono_declsec_get_flags (method->klass->image, idx);
11309 return 0;
11313 * Get the security actions (in the form of flags) associated with the specified class.
11315 * @klass: The class for which we want the declarative security flags.
11316 * Return the declarative security flags for the class.
11318 * Note: We cache the flags inside the MonoClass structure as this will get
11319 * called very often (at least for each method).
11321 guint32
11322 mono_declsec_flags_from_class (MonoClass *klass)
11324 if (klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) {
11325 if (!klass->ext || !klass->ext->declsec_flags) {
11326 guint32 idx;
11328 idx = mono_metadata_token_index (klass->type_token);
11329 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11330 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
11331 mono_loader_lock ();
11332 mono_class_alloc_ext (klass);
11333 mono_loader_unlock ();
11334 /* we cache the flags on classes */
11335 klass->ext->declsec_flags = mono_declsec_get_flags (klass->image, idx);
11337 return klass->ext->declsec_flags;
11339 return 0;
11343 * Get the security actions (in the form of flags) associated with the specified assembly.
11345 * @assembly: The assembly for which we want the declarative security flags.
11346 * Return the declarative security flags for the assembly.
11348 guint32
11349 mono_declsec_flags_from_assembly (MonoAssembly *assembly)
11351 guint32 idx = 1; /* there is only one assembly */
11352 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11353 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
11354 return mono_declsec_get_flags (assembly->image, idx);
11359 * Fill actions for the specific index (which may either be an encoded class token or
11360 * an encoded method token) from the metadata image.
11361 * Returns TRUE if some actions requiring code generation are present, FALSE otherwise.
11363 static MonoBoolean
11364 fill_actions_from_index (MonoImage *image, guint32 token, MonoDeclSecurityActions* actions,
11365 guint32 id_std, guint32 id_noncas, guint32 id_choice)
11367 MonoBoolean result = FALSE;
11368 MonoTableInfo *t;
11369 guint32 cols [MONO_DECL_SECURITY_SIZE];
11370 int index = mono_metadata_declsec_from_index (image, token);
11371 int i;
11373 t = &image->tables [MONO_TABLE_DECLSECURITY];
11374 for (i = index; i < t->rows; i++) {
11375 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
11377 if (cols [MONO_DECL_SECURITY_PARENT] != token)
11378 return result;
11380 /* if present only replace (class) permissions with method permissions */
11381 /* if empty accept either class or method permissions */
11382 if (cols [MONO_DECL_SECURITY_ACTION] == id_std) {
11383 if (!actions->demand.blob) {
11384 const char *blob = mono_metadata_blob_heap (image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
11385 actions->demand.index = cols [MONO_DECL_SECURITY_PERMISSIONSET];
11386 actions->demand.blob = (char*) (blob + 2);
11387 actions->demand.size = mono_metadata_decode_blob_size (blob, &blob);
11388 result = TRUE;
11390 } else if (cols [MONO_DECL_SECURITY_ACTION] == id_noncas) {
11391 if (!actions->noncasdemand.blob) {
11392 const char *blob = mono_metadata_blob_heap (image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
11393 actions->noncasdemand.index = cols [MONO_DECL_SECURITY_PERMISSIONSET];
11394 actions->noncasdemand.blob = (char*) (blob + 2);
11395 actions->noncasdemand.size = mono_metadata_decode_blob_size (blob, &blob);
11396 result = TRUE;
11398 } else if (cols [MONO_DECL_SECURITY_ACTION] == id_choice) {
11399 if (!actions->demandchoice.blob) {
11400 const char *blob = mono_metadata_blob_heap (image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
11401 actions->demandchoice.index = cols [MONO_DECL_SECURITY_PERMISSIONSET];
11402 actions->demandchoice.blob = (char*) (blob + 2);
11403 actions->demandchoice.size = mono_metadata_decode_blob_size (blob, &blob);
11404 result = TRUE;
11409 return result;
11412 static MonoBoolean
11413 mono_declsec_get_class_demands_params (MonoClass *klass, MonoDeclSecurityActions* demands,
11414 guint32 id_std, guint32 id_noncas, guint32 id_choice)
11416 guint32 idx = mono_metadata_token_index (klass->type_token);
11417 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11418 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
11419 return fill_actions_from_index (klass->image, idx, demands, id_std, id_noncas, id_choice);
11422 static MonoBoolean
11423 mono_declsec_get_method_demands_params (MonoMethod *method, MonoDeclSecurityActions* demands,
11424 guint32 id_std, guint32 id_noncas, guint32 id_choice)
11426 guint32 idx = mono_method_get_index (method);
11427 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11428 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
11429 return fill_actions_from_index (method->klass->image, idx, demands, id_std, id_noncas, id_choice);
11433 * Collect all actions (that requires to generate code in mini) assigned for
11434 * the specified method.
11435 * Note: Don't use the content of actions if the function return FALSE.
11437 MonoBoolean
11438 mono_declsec_get_demands (MonoMethod *method, MonoDeclSecurityActions* demands)
11440 guint32 mask = MONO_DECLSEC_FLAG_DEMAND | MONO_DECLSEC_FLAG_NONCAS_DEMAND |
11441 MONO_DECLSEC_FLAG_DEMAND_CHOICE;
11442 MonoBoolean result = FALSE;
11443 guint32 flags;
11445 /* quick exit if no declarative security is present in the metadata */
11446 if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows)
11447 return FALSE;
11449 /* we want the original as the wrapper is "free" of the security informations */
11450 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
11451 method = mono_marshal_method_from_wrapper (method);
11452 if (!method)
11453 return FALSE;
11456 /* First we look for method-level attributes */
11457 if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) {
11458 mono_class_init (method->klass);
11459 memset (demands, 0, sizeof (MonoDeclSecurityActions));
11461 result = mono_declsec_get_method_demands_params (method, demands,
11462 SECURITY_ACTION_DEMAND, SECURITY_ACTION_NONCASDEMAND, SECURITY_ACTION_DEMANDCHOICE);
11465 /* Here we use (or create) the class declarative cache to look for demands */
11466 flags = mono_declsec_flags_from_class (method->klass);
11467 if (flags & mask) {
11468 if (!result) {
11469 mono_class_init (method->klass);
11470 memset (demands, 0, sizeof (MonoDeclSecurityActions));
11472 result |= mono_declsec_get_class_demands_params (method->klass, demands,
11473 SECURITY_ACTION_DEMAND, SECURITY_ACTION_NONCASDEMAND, SECURITY_ACTION_DEMANDCHOICE);
11476 /* The boolean return value is used as a shortcut in case nothing needs to
11477 be generated (e.g. LinkDemand[Choice] and InheritanceDemand[Choice]) */
11478 return result;
11483 * Collect all Link actions: LinkDemand, NonCasLinkDemand and LinkDemandChoice (2.0).
11485 * Note: Don't use the content of actions if the function return FALSE.
11487 MonoBoolean
11488 mono_declsec_get_linkdemands (MonoMethod *method, MonoDeclSecurityActions* klass, MonoDeclSecurityActions *cmethod)
11490 MonoBoolean result = FALSE;
11491 guint32 flags;
11493 /* quick exit if no declarative security is present in the metadata */
11494 if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows)
11495 return FALSE;
11497 /* we want the original as the wrapper is "free" of the security informations */
11498 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
11499 method = mono_marshal_method_from_wrapper (method);
11500 if (!method)
11501 return FALSE;
11504 /* results are independant - zeroize both */
11505 memset (cmethod, 0, sizeof (MonoDeclSecurityActions));
11506 memset (klass, 0, sizeof (MonoDeclSecurityActions));
11508 /* First we look for method-level attributes */
11509 if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) {
11510 mono_class_init (method->klass);
11512 result = mono_declsec_get_method_demands_params (method, cmethod,
11513 SECURITY_ACTION_LINKDEMAND, SECURITY_ACTION_NONCASLINKDEMAND, SECURITY_ACTION_LINKDEMANDCHOICE);
11516 /* Here we use (or create) the class declarative cache to look for demands */
11517 flags = mono_declsec_flags_from_class (method->klass);
11518 if (flags & (MONO_DECLSEC_FLAG_LINKDEMAND | MONO_DECLSEC_FLAG_NONCAS_LINKDEMAND | MONO_DECLSEC_FLAG_LINKDEMAND_CHOICE)) {
11519 mono_class_init (method->klass);
11521 result |= mono_declsec_get_class_demands_params (method->klass, klass,
11522 SECURITY_ACTION_LINKDEMAND, SECURITY_ACTION_NONCASLINKDEMAND, SECURITY_ACTION_LINKDEMANDCHOICE);
11525 return result;
11529 * Collect all Inherit actions: InheritanceDemand, NonCasInheritanceDemand and InheritanceDemandChoice (2.0).
11531 * @klass The inherited class - this is the class that provides the security check (attributes)
11532 * @demans
11533 * return TRUE if inheritance demands (any kind) are present, FALSE otherwise.
11535 * Note: Don't use the content of actions if the function return FALSE.
11537 MonoBoolean
11538 mono_declsec_get_inheritdemands_class (MonoClass *klass, MonoDeclSecurityActions* demands)
11540 MonoBoolean result = FALSE;
11541 guint32 flags;
11543 /* quick exit if no declarative security is present in the metadata */
11544 if (!klass->image->tables [MONO_TABLE_DECLSECURITY].rows)
11545 return FALSE;
11547 /* Here we use (or create) the class declarative cache to look for demands */
11548 flags = mono_declsec_flags_from_class (klass);
11549 if (flags & (MONO_DECLSEC_FLAG_INHERITANCEDEMAND | MONO_DECLSEC_FLAG_NONCAS_INHERITANCEDEMAND | MONO_DECLSEC_FLAG_INHERITANCEDEMAND_CHOICE)) {
11550 mono_class_init (klass);
11551 memset (demands, 0, sizeof (MonoDeclSecurityActions));
11553 result |= mono_declsec_get_class_demands_params (klass, demands,
11554 SECURITY_ACTION_INHERITDEMAND, SECURITY_ACTION_NONCASINHERITANCE, SECURITY_ACTION_INHERITDEMANDCHOICE);
11557 return result;
11561 * Collect all Inherit actions: InheritanceDemand, NonCasInheritanceDemand and InheritanceDemandChoice (2.0).
11563 * Note: Don't use the content of actions if the function return FALSE.
11565 MonoBoolean
11566 mono_declsec_get_inheritdemands_method (MonoMethod *method, MonoDeclSecurityActions* demands)
11568 /* quick exit if no declarative security is present in the metadata */
11569 if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows)
11570 return FALSE;
11572 /* we want the original as the wrapper is "free" of the security informations */
11573 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
11574 method = mono_marshal_method_from_wrapper (method);
11575 if (!method)
11576 return FALSE;
11579 if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) {
11580 mono_class_init (method->klass);
11581 memset (demands, 0, sizeof (MonoDeclSecurityActions));
11583 return mono_declsec_get_method_demands_params (method, demands,
11584 SECURITY_ACTION_INHERITDEMAND, SECURITY_ACTION_NONCASINHERITANCE, SECURITY_ACTION_INHERITDEMANDCHOICE);
11586 return FALSE;
11590 static MonoBoolean
11591 get_declsec_action (MonoImage *image, guint32 token, guint32 action, MonoDeclSecurityEntry *entry)
11593 guint32 cols [MONO_DECL_SECURITY_SIZE];
11594 MonoTableInfo *t;
11595 int i;
11597 int index = mono_metadata_declsec_from_index (image, token);
11598 if (index == -1)
11599 return FALSE;
11601 t = &image->tables [MONO_TABLE_DECLSECURITY];
11602 for (i = index; i < t->rows; i++) {
11603 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
11605 /* shortcut - index are ordered */
11606 if (token != cols [MONO_DECL_SECURITY_PARENT])
11607 return FALSE;
11609 if (cols [MONO_DECL_SECURITY_ACTION] == action) {
11610 const char *metadata = mono_metadata_blob_heap (image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
11611 entry->blob = (char*) (metadata + 2);
11612 entry->size = mono_metadata_decode_blob_size (metadata, &metadata);
11613 return TRUE;
11617 return FALSE;
11620 MonoBoolean
11621 mono_declsec_get_method_action (MonoMethod *method, guint32 action, MonoDeclSecurityEntry *entry)
11623 if (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY) {
11624 guint32 idx = mono_method_get_index (method);
11625 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11626 idx |= MONO_HAS_DECL_SECURITY_METHODDEF;
11627 return get_declsec_action (method->klass->image, idx, action, entry);
11629 return FALSE;
11632 MonoBoolean
11633 mono_declsec_get_class_action (MonoClass *klass, guint32 action, MonoDeclSecurityEntry *entry)
11635 /* use cache */
11636 guint32 flags = mono_declsec_flags_from_class (klass);
11637 if (declsec_flags_map [action] & flags) {
11638 guint32 idx = mono_metadata_token_index (klass->type_token);
11639 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11640 idx |= MONO_HAS_DECL_SECURITY_TYPEDEF;
11641 return get_declsec_action (klass->image, idx, action, entry);
11643 return FALSE;
11646 MonoBoolean
11647 mono_declsec_get_assembly_action (MonoAssembly *assembly, guint32 action, MonoDeclSecurityEntry *entry)
11649 guint32 idx = 1; /* there is only one assembly */
11650 idx <<= MONO_HAS_DECL_SECURITY_BITS;
11651 idx |= MONO_HAS_DECL_SECURITY_ASSEMBLY;
11653 return get_declsec_action (assembly->image, idx, action, entry);
11656 gboolean
11657 mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass)
11659 MonoObject *res, *exc;
11660 void *params [1];
11661 static MonoClass *System_Reflection_Emit_TypeBuilder = NULL;
11662 static MonoMethod *method = NULL;
11664 if (!System_Reflection_Emit_TypeBuilder) {
11665 System_Reflection_Emit_TypeBuilder = mono_class_from_name (mono_defaults.corlib, "System.Reflection.Emit", "TypeBuilder");
11666 g_assert (System_Reflection_Emit_TypeBuilder);
11668 if (method == NULL) {
11669 method = mono_class_get_method_from_name (System_Reflection_Emit_TypeBuilder, "IsAssignableTo", 1);
11670 g_assert (method);
11674 * The result of mono_type_get_object () might be a System.MonoType but we
11675 * need a TypeBuilder so use klass->reflection_info.
11677 g_assert (klass->reflection_info);
11678 g_assert (!strcmp (((MonoObject*)(klass->reflection_info))->vtable->klass->name, "TypeBuilder"));
11680 params [0] = mono_type_get_object (mono_domain_get (), &oklass->byval_arg);
11682 res = mono_runtime_invoke (method, (MonoObject*)(klass->reflection_info), params, &exc);
11683 if (exc)
11684 return FALSE;
11685 else
11686 return *(MonoBoolean*)mono_object_unbox (res);