3 * reflection.c: Routines for creating an image at runtime.
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001 Ximian, Inc. http://www.ximian.com
12 #include "mono/metadata/reflection.h"
13 #include "mono/metadata/tabledefs.h"
14 #include "mono/metadata/tokentype.h"
22 #include "rawbuffer.h"
23 #include "mono-endian.h"
26 #define TEXT_OFFSET 512
27 #define CLI_H_SIZE 136
28 #define FILE_ALIGN 512
31 MonoReflectionILGen *ilgen;
32 MonoReflectionType *rtype;
33 MonoArray *parameters;
37 guint32 *table_idx; /* note: it's a pointer */
41 } ReflectionMethodBuilder;
43 const unsigned char table_sizes [64] = {
53 MONO_INTERFACEIMPL_SIZE,
54 MONO_MEMBERREF_SIZE, /* 0x0A */
56 MONO_CUSTOM_ATTR_SIZE,
57 MONO_FIELD_MARSHAL_SIZE,
58 MONO_DECL_SECURITY_SIZE,
59 MONO_CLASS_LAYOUT_SIZE,
60 MONO_FIELD_LAYOUT_SIZE, /* 0x10 */
61 MONO_STAND_ALONE_SIGNATURE_SIZE,
65 MONO_PROPERTY_MAP_SIZE,
68 MONO_METHOD_SEMA_SIZE,
70 MONO_MODULEREF_SIZE, /* 0x1A */
76 MONO_ASSEMBLY_SIZE, /* 0x20 */
77 MONO_ASSEMBLY_PROCESSOR_SIZE,
79 MONO_ASSEMBLYREF_SIZE,
80 MONO_ASSEMBLYREFPROC_SIZE,
81 MONO_ASSEMBLYREFOS_SIZE,
85 MONO_NESTED_CLASS_SIZE,
90 alloc_table (MonoDynamicTable *table, guint nrows)
93 g_assert (table->columns);
94 table->values = g_realloc (table->values, (1 + table->rows) * table->columns * sizeof (guint32));
98 string_heap_insert (MonoStringHeap *sh, const char *str)
102 gpointer oldkey, oldval;
104 if (g_hash_table_lookup_extended (sh->hash, str, &oldkey, &oldval))
105 return GPOINTER_TO_UINT (oldval);
107 len = strlen (str) + 1;
109 if (idx + len > sh->alloc_size) {
110 sh->alloc_size += len + 4096;
111 sh->data = g_realloc (sh->data, sh->alloc_size);
114 * We strdup the string even if we already copy them in sh->data
115 * so that the string pointers in the hash remain valid even if
116 * we need to realloc sh->data. We may want to avoid that later.
118 g_hash_table_insert (sh->hash, g_strdup (str), GUINT_TO_POINTER (idx));
119 memcpy (sh->data + idx, str, len);
125 string_heap_init (MonoStringHeap *sh)
128 sh->alloc_size = 4096;
129 sh->data = g_malloc (4096);
130 sh->hash = g_hash_table_new (g_str_hash, g_str_equal);
131 string_heap_insert (sh, "");
135 string_heap_free (MonoStringHeap *sh)
138 g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL);
139 g_hash_table_destroy (sh->hash);
143 mono_image_add_stream_data (MonoDynamicStream *stream, char *data, guint32 len)
146 if (stream->alloc_size < stream->index + len) {
147 stream->alloc_size += len + 4096;
148 stream->data = g_realloc (stream->data, stream->alloc_size);
150 memcpy (stream->data + stream->index, data, len);
152 stream->index += len;
154 * align index? Not without adding an additional param that controls it since
155 * we may store a blob value in pieces.
161 encode_type (MonoType *type, char *p, char **endbuf)
164 mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf);
170 case MONO_TYPE_BOOLEAN:
184 case MONO_TYPE_STRING:
185 case MONO_TYPE_OBJECT:
186 case MONO_TYPE_TYPEDBYREF:
187 mono_metadata_encode_value (type->type, p, endbuf);
189 case MONO_TYPE_SZARRAY:
190 mono_metadata_encode_value (type->type, p, endbuf);
191 encode_type (type->data.type, p, endbuf);
193 case MONO_TYPE_CLASS:
194 mono_metadata_encode_value (type->type, p, endbuf);
195 g_warning ("need to encode class %s", type->data.klass->name);
198 g_error ("need to encode type %x", type->type);
203 method_encode_signature (MonoDynamicAssembly *assembly, MonoMethodSignature *sig)
208 guint32 nparams = sig->param_count;
209 guint32 size = 10 + nparams * 10;
214 p = buf = g_malloc (size);
216 * FIXME: vararg, explicit_this, differenc call_conv values...
218 *p = sig->call_convention;
220 *p |= 0x20; /* hasthis */
222 mono_metadata_encode_value (nparams, p, &p);
223 encode_type (sig->ret, p, &p);
224 for (i = 0; i < nparams; ++i)
225 encode_type (sig->params [i], p, &p);
227 mono_metadata_encode_value (p-buf, b, &b);
228 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
229 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
235 method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
238 * FIXME: reuse code from method_encode_signature().
243 guint32 nparams = mb->parameters ? mono_array_length (mb->parameters): 0;
244 guint32 size = 10 + nparams * 10;
249 p = buf = g_malloc (size);
250 /* LAMESPEC: all the call conv spec is foobared */
251 *p = mb->call_conv & 0x60; /* has-this, explicit-this */
252 if (mb->call_conv & 2)
253 *p |= 0x5; /* vararg */
254 if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
255 *p |= 0x20; /* hasthis */
257 mono_metadata_encode_value (nparams, p, &p);
258 encode_type (mb->rtype->type, p, &p);
259 for (i = 0; i < nparams; ++i) {
260 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
261 encode_type (pt->type, p, &p);
264 mono_metadata_encode_value (p-buf, b, &b);
265 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
266 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
272 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
274 MonoDynamicTable *table;
277 guint32 idx, sig_idx;
278 guint nl = mono_array_length (ilgen->locals);
284 p = buf = g_malloc (10 + nl * 10);
285 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
286 idx = table->next_idx ++;
288 alloc_table (table, table->rows);
289 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
291 mono_metadata_encode_value (0x07, p, &p);
292 mono_metadata_encode_value (nl, p, &p);
293 for (i = 0; i < nl; ++i) {
294 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
295 encode_type (lb->type->type, p, &p);
297 mono_metadata_encode_value (p-buf, b, &b);
298 sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
299 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
302 values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
308 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
310 /* we use only tiny formats now: need to implement ILGenerator */
315 gint32 num_locals = 0;
316 gint32 num_exception = 0;
319 char fat_header [12];
322 guint32 local_sig = 0;
326 code = mb->ilgen->code;
327 code_size = mb->ilgen->code_len;
328 max_stack = mb->ilgen->max_stack;
329 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
332 code_size = mono_array_length (code);
333 max_stack = 8; /* we probably need to run a verifier on the code... */
336 /* check for exceptions, maxstack, locals */
337 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
339 if (code_size < 64 && !(code_size & 1)) {
340 flags = (code_size << 2) | 0x2;
341 } else if (code_size < 32 && (code_size & 1)) {
342 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
346 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
347 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
348 return assembly->text_rva + idx + CLI_H_SIZE;
352 local_sig = encode_locals (assembly, mb->ilgen);
354 * FIXME: need to set also the header size in fat_flags.
355 * (and more sects and init locals flags)
358 shortp = (guint16*)(fat_header);
360 shortp = (guint16*)(fat_header + 2);
362 intp = (guint32*)(fat_header + 4);
364 intp = (guint32*)(fat_header + 8);
366 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
367 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
368 return assembly->text_rva + idx + CLI_H_SIZE;
372 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index)
375 MonoDynamicTable *table;
378 table = &assembly->tables [table_idx];
380 g_assert (col < table->columns);
382 values = table->values + table->columns;
383 for (i = 1; i <= table->rows; ++i) {
384 if (values [col] == index)
391 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
393 MonoDynamicTable *table;
397 table = &assembly->tables [MONO_TABLE_METHOD];
398 *mb->table_idx = table->next_idx ++;
399 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
401 name = mono_string_to_utf8 (mb->name);
402 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
404 } else { /* a constructor */
405 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
407 values [MONO_METHOD_FLAGS] = mb->attrs;
408 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
409 values [MONO_METHOD_SIGNATURE] = method_builder_encode_signature (assembly, mb);
410 values [MONO_METHOD_PARAMLIST] = 0; /* FIXME: add support later */
411 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
415 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
417 MonoDynamicTable *table;
420 ReflectionMethodBuilder rmb;
422 rmb.ilgen = mb->ilgen;
423 rmb.rtype = mb->rtype;
424 rmb.parameters = mb->parameters;
425 rmb.attrs = mb->attrs;
426 rmb.iattrs = mb->iattrs;
427 rmb.call_conv = mb->call_conv;
431 rmb.table_idx = &mb->table_idx;
433 mono_image_basic_method (&rmb, assembly);
435 if (mb->dll) { /* It's a P/Invoke method */
437 table = &assembly->tables [MONO_TABLE_IMPLMAP];
439 alloc_table (table, table->rows);
440 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
441 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
442 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
443 name = mono_string_to_utf8 (mb->dllentry);
444 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
446 name = mono_string_to_utf8 (mb->dll);
447 moduleref = string_heap_insert (&assembly->sheap, name);
449 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
450 table = &assembly->tables [MONO_TABLE_MODULEREF];
452 alloc_table (table, table->rows);
453 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
454 values [MONO_IMPLMAP_SCOPE] = table->rows;
460 mono_image_get_ctor_info (MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
462 ReflectionMethodBuilder rmb;
464 rmb.ilgen = mb->ilgen;
465 rmb.rtype = mono_type_get_object (&mono_defaults.void_class->byval_arg);
466 rmb.parameters = mb->parameters;
467 rmb.attrs = mb->attrs;
468 rmb.iattrs = mb->iattrs;
469 rmb.call_conv = mb->call_conv;
473 rmb.table_idx = &mb->table_idx;
475 mono_image_basic_method (&rmb, assembly);
480 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
488 p = buf = g_malloc (64);
490 mono_metadata_encode_value (0x06, p, &p);
491 /* encode custom attributes before the type */
492 encode_type (fb->type->type, p, &p);
493 g_assert (p-buf < 64);
494 mono_metadata_encode_value (p-buf, b, &b);
495 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
496 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
502 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
504 MonoDynamicTable *table;
508 table = &assembly->tables [MONO_TABLE_FIELD];
509 fb->table_idx = table->next_idx ++;
510 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
511 name = mono_string_to_utf8 (fb->name);
512 values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
514 values [MONO_FIELD_FLAGS] = fb->attrs;
515 values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
517 if (fb->offset != -1) {
518 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
520 alloc_table (table, table->rows);
521 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
522 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
523 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
528 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
534 MonoReflectionMethodBuilder *mb = fb->get_method;
537 if (mb && mb->parameters)
538 nparams = mono_array_length (mb->parameters);
539 buf = p = g_malloc (24 + nparams * 10);
542 mono_metadata_encode_value (nparams, p, &p);
544 encode_type (mb->rtype->type, p, &p);
545 for (i = 0; i < nparams; ++i) {
546 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
547 encode_type (pt->type, p, &p);
550 *p++ = 1; /* void: a property should probably not be allowed without a getter */
553 mono_metadata_encode_value (p-buf, b, &b);
554 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
555 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
561 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
563 MonoDynamicTable *table;
566 guint num_methods = 0;
570 * we need to set things in the following tables:
571 * PROPERTYMAP (info already filled in _get_type_info ())
572 * PROPERTY (rows already preallocated in _get_type_info ())
573 * METHOD (method info already done with the generic method code)
576 table = &assembly->tables [MONO_TABLE_PROPERTY];
577 pb->table_idx = table->next_idx ++;
578 values = table->values + pb->table_idx * MONO_FIELD_SIZE;
579 name = mono_string_to_utf8 (pb->name);
580 values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
582 values [MONO_PROPERTY_FLAGS] = pb->attrs;
583 values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
585 /* FIXME: we still don't handle 'other' methods */
586 if (pb->get_method) num_methods ++;
587 if (pb->set_method) num_methods ++;
589 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
590 table->rows += num_methods;
591 alloc_table (table, table->rows);
593 if (pb->get_method) {
594 semaidx = table->next_idx ++;
595 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
596 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
597 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
598 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 1;
600 if (pb->set_method) {
601 semaidx = table->next_idx ++;
602 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
603 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
604 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
605 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 0;
610 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
612 if (image != mono_defaults.corlib)
613 g_error ("multiple assemblyref not yet supported");
614 /* first row in assemblyref */
615 return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF;
619 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
621 MonoDynamicTable *table;
626 if (!assembly->typeref)
627 assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal);
629 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
632 klass = type->data.klass;
634 * If it's in the same module:
635 * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS)
638 table = &assembly->tables [MONO_TABLE_TYPEREF];
639 alloc_table (table, table->rows + 1);
640 values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
641 values [MONO_TYPEREF_SCOPE] = resolution_scope_from_image (assembly, klass->image);
642 values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
643 values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
644 token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
645 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
651 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method)
653 MonoDynamicTable *table;
655 guint32 token, pclass;
659 * FIXME: we need to cache the token.
661 parent = mono_image_typedef_or_ref (assembly, &method->klass->byval_arg);
662 switch (parent & TYPEDEFORREF_MASK) {
663 case TYPEDEFORREF_TYPEREF:
664 pclass = MEMBERREF_PARENT_TYPEREF;
666 case TYPEDEFORREF_TYPESPEC:
667 pclass = MEMBERREF_PARENT_TYPESPEC;
669 case TYPEDEFORREF_TYPEDEF:
670 /* should never get here */
672 g_error ("unknow typeref or def token");
674 /* extract the index */
675 parent >>= TYPEDEFORREF_BITS;
677 table = &assembly->tables [MONO_TABLE_MEMBERREF];
678 alloc_table (table, table->rows + 1);
679 values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
680 values [MONO_MEMBERREF_CLASS] = pclass | (parent << MEMBERREF_PARENT_BITS);
681 values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, method->name);
682 values [MONO_MEMBERREF_SIGNATURE] = method_encode_signature (assembly, method->signature);
683 token = MONO_TOKEN_MEMBER_REF | table->next_idx;
690 mono_image_get_type_info (MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
692 MonoDynamicTable *table;
697 table = &assembly->tables [MONO_TABLE_TYPEDEF];
698 tb->table_idx = table->next_idx ++;
699 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
700 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
701 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
702 n = mono_string_to_utf8 (tb->name);
703 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
705 n = mono_string_to_utf8 (tb->nspace);
706 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
708 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
709 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
712 * FIXME: constructors and methods need to be output in the same order
713 * as they are defined (according to table_idx).
716 /* handle constructors */
718 table = &assembly->tables [MONO_TABLE_METHOD];
719 table->rows += mono_array_length (tb->ctors);
720 alloc_table (table, table->rows);
721 for (i = 0; i < mono_array_length (tb->ctors); ++i)
722 mono_image_get_ctor_info (
723 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
728 table = &assembly->tables [MONO_TABLE_METHOD];
729 table->rows += mono_array_length (tb->methods);
730 alloc_table (table, table->rows);
731 for (i = 0; i < mono_array_length (tb->methods); ++i)
732 mono_image_get_method_info (
733 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
738 table = &assembly->tables [MONO_TABLE_FIELD];
739 table->rows += mono_array_length (tb->fields);
740 alloc_table (table, table->rows);
741 for (i = 0; i < mono_array_length (tb->fields); ++i)
742 mono_image_get_field_info (
743 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
746 /* Do the same with properties etc.. */
747 if (tb->properties && mono_array_length (tb->properties)) {
748 table = &assembly->tables [MONO_TABLE_PROPERTY];
749 table->rows += mono_array_length (tb->properties);
750 alloc_table (table, table->rows);
751 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
753 alloc_table (table, table->rows);
754 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
755 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
756 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
757 for (i = 0; i < mono_array_length (tb->properties); ++i)
758 mono_image_get_property_info (
759 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
764 mono_image_fill_module_table (MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
766 MonoDynamicTable *table;
770 table = &assembly->tables [MONO_TABLE_MODULE];
771 mb->table_idx = table->next_idx ++;
772 name = mono_string_to_utf8 (mb->module.name);
773 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
775 /* need to set mvid? */
778 * fill-in info in other tables as well.
780 table = &assembly->tables [MONO_TABLE_TYPEDEF];
781 table->rows += mono_array_length (mb->types);
782 alloc_table (table, table->rows);
783 for (i = 0; i < mono_array_length (mb->types); ++i)
784 mono_image_get_type_info (mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
787 #define align_pointer(base,p)\
789 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
791 (p) += 4 - (__diff & 3);\
795 build_compressed_metadata (MonoDynamicAssembly *assembly)
798 guint64 valid_mask = 0;
799 guint32 heapt_size = 0;
800 guint32 meta_size = 256; /* allow for header and other stuff */
801 guint32 table_offset;
808 char *version = "mono" VERSION;
810 /* Compute table sizes */
811 meta = assembly->assembly.image = g_new0 (MonoImage, 1);
813 /* Setup the info used by compute_sizes () */
814 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
815 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
816 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
818 meta_size += assembly->blob.index;
819 meta_size += assembly->guid.index;
820 meta_size += assembly->sheap.index;
821 meta_size += assembly->us.index;
823 for (i=0; i < 64; ++i)
824 meta->tables [i].rows = assembly->tables [i].rows;
826 for (i = 0; i < 64; i++){
827 if (meta->tables [i].rows == 0)
829 valid_mask |= (guint64)1 << i;
831 meta->tables [i].row_size = mono_metadata_compute_size (
832 meta, i, &meta->tables [i].size_bitfield);
833 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
835 heapt_size += 24; /* #~ header size */
836 heapt_size += ntables * 4;
837 meta_size += heapt_size;
838 meta->raw_metadata = g_malloc0 (meta_size);
839 p = meta->raw_metadata;
840 /* the metadata signature */
841 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
842 /* version numbers and 4 bytes reserved */
843 int16val = (guint16*)p;
848 int32val = (guint32*)p;
849 *int32val = strlen (version);
851 memcpy (p, version, *int32val);
853 align_pointer (meta->raw_metadata, p);
854 int16val = (guint16*)p;
855 *int16val++ = 0; /* flags must be 0 */
856 *int16val = 5; /* number of streams */
860 * write the stream info.
862 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
864 int32val = (guint32*)p;
865 *int32val++ = assembly->tstream.offset = table_offset;
866 *int32val = heapt_size;
867 table_offset += *int32val;
871 align_pointer (meta->raw_metadata, p);
873 int32val = (guint32*)p;
874 *int32val++ = assembly->sheap.offset = table_offset;
875 *int32val = assembly->sheap.index;
876 table_offset += *int32val;
878 strcpy (p, "#Strings");
880 align_pointer (meta->raw_metadata, p);
882 int32val = (guint32*)p;
883 *int32val++ = assembly->us.offset = table_offset;
884 *int32val = assembly->us.index;
885 table_offset += *int32val;
889 align_pointer (meta->raw_metadata, p);
891 int32val = (guint32*)p;
892 *int32val++ = assembly->blob.offset = table_offset;
893 *int32val = assembly->blob.index;
894 table_offset += *int32val;
898 align_pointer (meta->raw_metadata, p);
900 int32val = (guint32*)p;
901 *int32val++ = assembly->guid.offset = table_offset;
902 *int32val = assembly->guid.index;
903 table_offset += *int32val;
907 align_pointer (meta->raw_metadata, p);
910 * now copy the data, the table stream header and contents goes first.
912 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
913 p = meta->raw_metadata + assembly->tstream.offset;
914 int32val = (guint32*)p;
915 *int32val = 0; /* reserved */
917 *p++ = 1; /* version */
919 if (meta->idx_string_wide)
921 if (meta->idx_guid_wide)
923 if (meta->idx_blob_wide)
926 *p++ = 0; /* reserved */
927 int64val = (guint64*)p;
928 *int64val++ = valid_mask;
929 *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now */
931 int32val = (guint32*)p;
932 for (i = 0; i < 64; i++){
933 if (meta->tables [i].rows == 0)
935 *int32val++ = meta->tables [i].rows;
937 p = (unsigned char*)int32val;
938 /* compress the tables */
939 for (i = 0; i < 64; i++){
942 guint32 bitfield = meta->tables [i].size_bitfield;
943 if (!meta->tables [i].rows)
945 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
946 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
947 meta->tables [i].base = p;
948 for (row = 1; row <= meta->tables [i].rows; ++row) {
949 values = assembly->tables [i].values + row * assembly->tables [i].columns;
950 for (col = 0; col < assembly->tables [i].columns; ++col) {
951 switch (mono_metadata_table_size (bitfield, col)) {
956 int16val = (guint16*)p;
957 *int16val = values [col];
961 int32val = (guint32*)p;
962 *int32val = values [col];
966 g_assert_not_reached ();
970 g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
973 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
974 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
975 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
976 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
977 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
979 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
983 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
985 MonoDynamicTable *table;
986 MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
992 assembly->text_rva = 0x00002000;
994 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
995 alloc_table (table, 1);
996 values = table->values + MONO_ASSEMBLY_SIZE;
997 values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
998 name = mono_string_to_utf8 (assemblyb->name);
999 values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
1001 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
1002 values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
1003 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
1004 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
1005 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
1006 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
1008 assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
1009 assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
1011 len = mono_array_length (assemblyb->modules);
1012 table = &assembly->tables [MONO_TABLE_MODULE];
1013 alloc_table (table, len);
1014 for (i = 0; i < len; ++i)
1015 mono_image_fill_module_table (mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
1017 table = &assembly->tables [MONO_TABLE_TYPEDEF];
1019 * table->rows is already set above and in mono_image_fill_module_table.
1021 alloc_table (table, table->rows);
1023 * Set the first entry.
1025 values = table->values + table->columns;
1026 values [MONO_TYPEDEF_FLAGS] = 0;
1027 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
1028 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
1029 values [MONO_TYPEDEF_EXTENDS] = 0;
1030 values [MONO_TYPEDEF_FIELD_LIST] = 1;
1031 values [MONO_TYPEDEF_METHOD_LIST] = 1;
1033 /* later include all the assemblies referenced */
1034 table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
1035 alloc_table (table, 1);
1036 values = table->values + table->columns;
1037 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib");
1039 build_compressed_metadata (assembly);
1043 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
1049 if (!assembly->dynamic_assembly)
1050 mono_image_basic_init (assembly);
1051 mono_metadata_encode_value (str->length, b, &b);
1052 index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
1053 /* FIXME: ENOENDIAN */
1054 mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2);
1059 * Get a token to insert in the IL code stream for the given MemberInfo.
1061 * ConstructorBuilder
1069 mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj)
1071 MonoClass *klass = obj->klass;
1074 mono_image_basic_init (assembly);
1076 if (strcmp (klass->name, "MethodBuilder") == 0) {
1077 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
1078 token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
1079 /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
1082 if (strcmp (klass->name, "FieldBuilder") == 0) {
1083 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
1084 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
1086 if (strcmp (klass->name, "MonoCMethod") == 0) {
1087 MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
1088 token = mono_image_get_methodref_token (assembly->dynamic_assembly, m->method);
1089 /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/
1092 g_print ("requested token for %s\n", klass->name);
1097 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
1099 MonoDynamicAssembly *assembly;
1102 if (assemblyb->dynamic_assembly)
1105 assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
1107 string_heap_init (&assembly->sheap);
1108 mono_image_add_stream_data (&assembly->us, "", 1);
1109 mono_image_add_stream_data (&assembly->blob, "", 1);
1111 for (i=0; i < 64; ++i) {
1112 assembly->tables [i].next_idx = 1;
1113 assembly->tables [i].columns = table_sizes [i];
1119 mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize)
1121 MonoMSDOSHeader *msdos;
1122 MonoDotNetHeader *header;
1123 MonoSectionTable *section;
1124 MonoCLIHeader *cli_header;
1125 guint32 header_size = TEXT_OFFSET + CLI_H_SIZE;
1126 MonoDynamicAssembly *assembly;
1128 static const unsigned char msheader[] = {
1129 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1130 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
1133 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
1134 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
1135 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
1136 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1139 if (maxsize < header_size)
1142 mono_image_basic_init (assemblyb);
1143 assembly = assemblyb->dynamic_assembly;
1145 mono_image_build_metadata (assemblyb);
1147 memset (buffer, 0, header_size);
1148 memcpy (buffer, msheader, sizeof (MonoMSDOSHeader));
1150 msdos = (MonoMSDOSHeader *)buffer;
1151 header = (MonoDotNetHeader *)(buffer + sizeof (MonoMSDOSHeader));
1152 section = (MonoSectionTable*) (buffer + sizeof (MonoMSDOSHeader) + sizeof (MonoDotNetHeader));
1154 /* FIXME: ENDIAN problem: byteswap as needed */
1155 msdos->pe_offset = sizeof (MonoMSDOSHeader);
1157 header->pesig [0] = 'P';
1158 header->pesig [1] = 'E';
1159 header->pesig [2] = header->pesig [3] = 0;
1161 header->coff.coff_machine = 0x14c;
1162 header->coff.coff_sections = 1; /* only .text supported now */
1163 header->coff.coff_time = time (NULL);
1164 header->coff.coff_opt_header_size = sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4;
1166 header->coff.coff_attributes = 0x010e;
1168 //header->coff.coff_attributes = 0x210e;
1169 header->pe.pe_magic = 0x10B;
1170 header->pe.pe_major = 6;
1171 header->pe.pe_minor = 0;
1172 /* need to set: pe_code_size pe_data_size pe_rva_entry_point pe_rva_code_base pe_rva_data_base */
1174 header->nt.pe_image_base = 0x400000;
1175 header->nt.pe_section_align = 8192;
1176 header->nt.pe_file_alignment = FILE_ALIGN;
1177 header->nt.pe_os_major = 4;
1178 header->nt.pe_os_minor = 0;
1179 header->nt.pe_subsys_major = 4;
1180 /* need to set pe_image_size, pe_header_size */
1181 header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */
1182 header->nt.pe_stack_reserve = 0x00100000;
1183 header->nt.pe_stack_commit = 0x00001000;
1184 header->nt.pe_heap_reserve = 0x00100000;
1185 header->nt.pe_heap_commit = 0x00001000;
1186 header->nt.pe_loader_flags = 1;
1187 header->nt.pe_data_dir_count = 16;
1191 header->datadir.pe_import_table
1196 header->datadir.pe_cli_header.size = CLI_H_SIZE;
1197 header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */
1199 /* Write section tables */
1200 strcpy (section->st_name, ".text");
1201 section->st_virtual_size = 1024; /* FIXME */
1202 section->st_virtual_address = assembly->text_rva;
1203 section->st_raw_data_size = 1024; /* FIXME */
1204 section->st_raw_data_ptr = TEXT_OFFSET;
1205 section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
1208 * align: build_compressed_metadata () assumes metadata is aligned
1210 * cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1212 assembly->code.index += 3;
1213 assembly->code.index &= ~3;
1216 * Write the MonoCLIHeader header
1218 cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET);
1219 cli_header->ch_size = CLI_H_SIZE;
1220 cli_header->ch_runtime_major = 2;
1221 cli_header->ch_flags = CLI_FLAGS_ILONLY;
1222 if (assemblyb->entry_point)
1223 cli_header->ch_entry_point = assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF;
1225 cli_header->ch_entry_point = 0;
1226 cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1227 cli_header->ch_metadata.size = assembly->meta_size;
1233 * We need to return always the same object for Type, MethodInfo, FieldInfo etc..
1235 static GHashTable *object_cache = NULL;
1237 #define CHECK_OBJECT(t,p) \
1240 if (!object_cache) \
1241 object_cache = g_hash_table_new (g_direct_hash, g_direct_equal); \
1242 if ((_obj = g_hash_table_lookup (object_cache, (p)))) \
1246 #define CACHE_OBJECT(p,o) \
1248 g_hash_table_insert (object_cache, p,o); \
1251 MonoReflectionAssembly*
1252 mono_assembly_get_object (MonoAssembly *assembly)
1255 MonoReflectionAssembly *res;
1257 CHECK_OBJECT (MonoReflectionAssembly *, assembly);
1258 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "Assembly");
1259 res = (MonoReflectionAssembly *)mono_object_new (klass);
1260 res->assembly = assembly;
1261 CACHE_OBJECT (assembly, res);
1266 mono_type_get_object (MonoType *type)
1268 MonoReflectionType *res;
1270 CHECK_OBJECT (MonoReflectionType *, type);
1271 res = (MonoReflectionType *)mono_object_new (mono_defaults.monotype_class);
1273 CACHE_OBJECT (type, res);
1277 MonoReflectionMethod*
1278 mono_method_get_object (MonoMethod *method)
1281 * We use the same C representation for methods and constructors, but the type
1282 * name in C# is different.
1286 MonoReflectionMethod *ret;
1288 CHECK_OBJECT (MonoReflectionMethod *, method);
1289 if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
1290 cname = "MonoCMethod";
1292 cname = "MonoMethod";
1293 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
1295 ret = (MonoReflectionMethod*)mono_object_new (klass);
1296 ret->method = method;
1297 CACHE_OBJECT (method, ret);
1301 MonoReflectionField*
1302 mono_field_get_object (MonoClass *klass, MonoClassField *field)
1304 MonoReflectionField *res;
1307 CHECK_OBJECT (MonoReflectionField *, field);
1308 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
1309 res = (MonoReflectionField *)mono_object_new (oklass);
1312 CACHE_OBJECT (field, res);
1316 MonoReflectionProperty*
1317 mono_property_get_object (MonoClass *klass, MonoProperty *property)
1319 MonoReflectionProperty *res;
1322 CHECK_OBJECT (MonoReflectionProperty *, property);
1323 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
1324 res = (MonoReflectionProperty *)mono_object_new (oklass);
1326 res->property = property;
1327 CACHE_OBJECT (property, res);
1331 MonoReflectionParameter**
1332 mono_param_get_objects (MonoMethod *method)
1334 MonoReflectionParameter **res;
1335 MonoReflectionMethod *member;
1340 if (!method->signature->param_count)
1343 member = mono_method_get_object (method);
1344 names = g_new (char*, method->signature->param_count);
1345 mono_method_get_param_names (method, names);
1347 /* Note: the cache is based on the address of the signature into the method
1348 * since we already cache MethodInfos with the method as keys.
1350 CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
1351 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
1352 res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
1353 for (i = 0; i < method->signature->param_count; ++i) {
1354 res [i] = (MonoReflectionParameter *)mono_object_new (oklass);
1355 res [i]->ClassImpl = mono_type_get_object (method->signature->params [i]);
1356 res [i]->DefaultValueImpl = NULL; /* FIXME */
1357 res [i]->MemberImpl = (MonoObject*)member;
1358 res [i]->NameImpl = mono_string_new (names [i]);
1359 res [i]->PositionImpl = i + 1;
1360 res [i]->AttrsImpl = method->signature->params [i]->attrs;
1363 CACHE_OBJECT (&(method->signature), res);