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, ReflectionMethodBuilder *mb)
208 guint32 nparams = mb->parameters ? mono_array_length (mb->parameters): 0;
209 guint32 size = 10 + nparams * 10;
214 p = buf = g_malloc (size);
215 /* LAMESPEC: all the call conv spec is foobared */
216 *p = mb->call_conv & 0x60; /* has-this, explicit-this */
217 if (mb->call_conv & 2)
218 *p |= 0x5; /* vararg */
219 if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
220 *p |= 0x20; /* hasthis */
222 mono_metadata_encode_value (nparams, p, &p);
223 encode_type (mb->rtype->type, p, &p);
224 for (i = 0; i < nparams; ++i) {
225 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
226 encode_type (pt->type, p, &p);
229 mono_metadata_encode_value (p-buf, b, &b);
230 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
231 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
237 encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen)
239 MonoDynamicTable *table;
242 guint32 idx, sig_idx;
243 guint nl = mono_array_length (ilgen->locals);
249 p = buf = g_malloc (10 + nl * 10);
250 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
251 idx = table->next_idx ++;
253 alloc_table (table, table->rows);
254 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
256 mono_metadata_encode_value (0x07, p, &p);
257 mono_metadata_encode_value (nl, p, &p);
258 for (i = 0; i < nl; ++i) {
259 MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i);
260 encode_type (lb->type->type, p, &p);
262 mono_metadata_encode_value (p-buf, b, &b);
263 sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
264 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
267 values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
273 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb)
275 /* we use only tiny formats now: need to implement ILGenerator */
280 gint32 num_locals = 0;
281 gint32 num_exception = 0;
284 char fat_header [12];
287 guint32 local_sig = 0;
291 code = mb->ilgen->code;
292 code_size = mb->ilgen->code_len;
293 max_stack = mb->ilgen->max_stack;
294 num_locals = mb->ilgen->locals ? mono_array_length (mb->ilgen->locals) : 0;
297 code_size = mono_array_length (code);
298 max_stack = 8; /* we probably need to run a verifier on the code... */
301 /* check for exceptions, maxstack, locals */
302 maybe_small = (max_stack <= 8) && (!num_locals) && (!num_exception);
304 if (code_size < 64 && !(code_size & 1)) {
305 flags = (code_size << 2) | 0x2;
306 } else if (code_size < 32 && (code_size & 1)) {
307 flags = (code_size << 2) | 0x6; /* LAMESPEC: see metadata.c */
311 idx = mono_image_add_stream_data (&assembly->code, &flags, 1);
312 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
313 return assembly->text_rva + idx + CLI_H_SIZE;
317 local_sig = encode_locals (assembly, mb->ilgen);
319 * FIXME: need to set also the header size in fat_flags.
320 * (and more sects and init locals flags)
323 shortp = (guint16*)(fat_header);
325 shortp = (guint16*)(fat_header + 2);
327 intp = (guint32*)(fat_header + 4);
329 intp = (guint32*)(fat_header + 8);
331 idx = mono_image_add_stream_data (&assembly->code, fat_header, 12);
332 mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size);
333 return assembly->text_rva + idx + CLI_H_SIZE;
337 find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index)
340 MonoDynamicTable *table;
343 table = &assembly->tables [table_idx];
345 g_assert (col < table->columns);
347 values = table->values + table->columns;
348 for (i = 1; i <= table->rows; ++i) {
349 if (values [col] == index)
356 mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
358 MonoDynamicTable *table;
362 table = &assembly->tables [MONO_TABLE_METHOD];
363 *mb->table_idx = table->next_idx ++;
364 values = table->values + *mb->table_idx * MONO_METHOD_SIZE;
366 name = mono_string_to_utf8 (mb->name);
367 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, name);
369 } else { /* a constructor */
370 values [MONO_METHOD_NAME] = string_heap_insert (&assembly->sheap, mb->attrs & METHOD_ATTRIBUTE_STATIC? ".cctor": ".ctor");
372 values [MONO_METHOD_FLAGS] = mb->attrs;
373 values [MONO_METHOD_IMPLFLAGS] = mb->iattrs;
374 values [MONO_METHOD_SIGNATURE] = method_encode_signature (assembly, mb);
375 values [MONO_METHOD_PARAMLIST] = 0; /* FIXME: add support later */
376 values [MONO_METHOD_RVA] = method_encode_code (assembly, mb);
380 mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly)
382 MonoDynamicTable *table;
385 ReflectionMethodBuilder rmb;
387 rmb.ilgen = mb->ilgen;
388 rmb.rtype = mb->rtype;
389 rmb.parameters = mb->parameters;
390 rmb.attrs = mb->attrs;
391 rmb.iattrs = mb->iattrs;
392 rmb.call_conv = mb->call_conv;
396 rmb.table_idx = &mb->table_idx;
398 mono_image_basic_method (&rmb, assembly);
400 if (mb->dll) { /* It's a P/Invoke method */
402 table = &assembly->tables [MONO_TABLE_IMPLMAP];
404 alloc_table (table, table->rows);
405 values = table->values + table->rows * MONO_IMPLMAP_SIZE;
406 values [MONO_IMPLMAP_FLAGS] = (mb->native_cc << 8) | mb->charset;
407 values [MONO_IMPLMAP_MEMBER] = (mb->table_idx << 1) | 1; /* memberforwarded: method */
408 name = mono_string_to_utf8 (mb->dllentry);
409 values [MONO_IMPLMAP_NAME] = string_heap_insert (&assembly->sheap, name);
411 name = mono_string_to_utf8 (mb->dll);
412 moduleref = string_heap_insert (&assembly->sheap, name);
414 if (!(values [MONO_IMPLMAP_SCOPE] = find_index_in_table (assembly, MONO_TABLE_MODULEREF, MONO_MODULEREF_NAME, moduleref))) {
415 table = &assembly->tables [MONO_TABLE_MODULEREF];
417 alloc_table (table, table->rows);
418 table->values [table->rows * MONO_MODULEREF_SIZE + MONO_MODULEREF_NAME] = moduleref;
419 values [MONO_IMPLMAP_SCOPE] = table->rows;
425 mono_image_get_ctor_info (MonoReflectionCtorBuilder *mb, MonoDynamicAssembly *assembly)
427 ReflectionMethodBuilder rmb;
429 rmb.ilgen = mb->ilgen;
431 rmb.parameters = mb->parameters;
432 rmb.attrs = mb->attrs;
433 rmb.iattrs = mb->iattrs;
434 rmb.call_conv = mb->call_conv;
438 rmb.table_idx = &mb->table_idx;
440 mono_image_basic_method (&rmb, assembly);
445 field_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionFieldBuilder *fb)
453 p = buf = g_malloc (64);
455 mono_metadata_encode_value (0x06, p, &p);
456 /* encode custom attributes before the type */
457 encode_type (fb->type->type, p, &p);
458 g_assert (p-buf < 64);
459 mono_metadata_encode_value (p-buf, b, &b);
460 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
461 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
467 mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly *assembly)
469 MonoDynamicTable *table;
473 table = &assembly->tables [MONO_TABLE_FIELD];
474 fb->table_idx = table->next_idx ++;
475 values = table->values + fb->table_idx * MONO_FIELD_SIZE;
476 name = mono_string_to_utf8 (fb->name);
477 values [MONO_FIELD_NAME] = string_heap_insert (&assembly->sheap, name);
479 values [MONO_FIELD_FLAGS] = fb->attrs;
480 values [MONO_FIELD_SIGNATURE] = field_encode_signature (assembly, fb);
482 if (fb->offset != -1) {
483 table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
485 alloc_table (table, table->rows);
486 values = table->values + table->rows * MONO_FIELD_LAYOUT_SIZE;
487 values [MONO_FIELD_LAYOUT_FIELD] = fb->table_idx;
488 values [MONO_FIELD_LAYOUT_OFFSET] = fb->offset;
493 property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionPropertyBuilder *fb)
499 MonoReflectionMethodBuilder *mb = fb->get_method;
502 if (mb && mb->parameters)
503 nparams = mono_array_length (mb->parameters);
504 buf = p = g_malloc (24 + nparams * 10);
507 mono_metadata_encode_value (nparams, p, &p);
509 encode_type (mb->rtype->type, p, &p);
510 for (i = 0; i < nparams; ++i) {
511 MonoReflectionType *pt = mono_array_get (mb->parameters, MonoReflectionType*, i);
512 encode_type (pt->type, p, &p);
515 *p++ = 1; /* void: a property should probably not be allowed without a getter */
518 mono_metadata_encode_value (p-buf, b, &b);
519 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
520 mono_image_add_stream_data (&assembly->blob, buf, p-buf);
526 mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAssembly *assembly)
528 MonoDynamicTable *table;
531 guint num_methods = 0;
535 * we need to set things in the following tables:
536 * PROPERTYMAP (info already filled in _get_type_info ())
537 * PROPERTY (rows already preallocated in _get_type_info ())
538 * METHOD (method info already done with the generic method code)
541 table = &assembly->tables [MONO_TABLE_PROPERTY];
542 pb->table_idx = table->next_idx ++;
543 values = table->values + pb->table_idx * MONO_FIELD_SIZE;
544 name = mono_string_to_utf8 (pb->name);
545 values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name);
547 values [MONO_PROPERTY_FLAGS] = pb->attrs;
548 values [MONO_PROPERTY_TYPE] = property_encode_signature (assembly, pb);
550 /* FIXME: we still don't handle 'other' methods */
551 if (pb->get_method) num_methods ++;
552 if (pb->set_method) num_methods ++;
554 table = &assembly->tables [MONO_TABLE_METHODSEMANTICS];
555 table->rows += num_methods;
556 alloc_table (table, table->rows);
558 if (pb->get_method) {
559 semaidx = table->next_idx ++;
560 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
561 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_GETTER;
562 values [MONO_METHOD_SEMA_METHOD] = pb->get_method->table_idx;
563 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 1;
565 if (pb->set_method) {
566 semaidx = table->next_idx ++;
567 values = table->values + semaidx * MONO_METHOD_SEMA_SIZE;
568 values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_SETTER;
569 values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx;
570 values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << 1) | 0;
575 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image)
577 if (image != mono_defaults.corlib)
578 g_error ("multiple assemblyref not yet supported");
579 /* first row in assemblyref */
580 return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF;
584 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type)
586 MonoDynamicTable *table;
591 if (!assembly->typeref)
592 assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal);
594 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
597 klass = type->data.klass;
599 * If it's in the same module:
600 * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS)
603 table = &assembly->tables [MONO_TABLE_TYPEREF];
604 alloc_table (table, table->rows + 1);
605 values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
606 values [MONO_TYPEREF_SCOPE] = resolution_scope_from_image (assembly, klass->image);
607 values [MONO_TYPEREF_NAME] = string_heap_insert (&assembly->sheap, klass->name);
608 values [MONO_TYPEREF_NAMESPACE] = string_heap_insert (&assembly->sheap, klass->name_space);
609 token = TYPEDEFORREF_TYPEREF | (table->next_idx << TYPEDEFORREF_BITS); /* typeref */
610 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
616 mono_image_get_type_info (MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly)
618 MonoDynamicTable *table;
623 table = &assembly->tables [MONO_TABLE_TYPEDEF];
624 tb->table_idx = table->next_idx ++;
625 values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE;
626 values [MONO_TYPEDEF_FLAGS] = tb->attrs;
627 values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type);
628 n = mono_string_to_utf8 (tb->name);
629 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, n);
631 n = mono_string_to_utf8 (tb->nspace);
632 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, n);
634 values [MONO_TYPEDEF_FIELD_LIST] = assembly->tables [MONO_TABLE_FIELD].next_idx;
635 values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
639 table = &assembly->tables [MONO_TABLE_METHOD];
640 table->rows += mono_array_length (tb->methods);
641 alloc_table (table, table->rows);
642 for (i = 0; i < mono_array_length (tb->methods); ++i)
643 mono_image_get_method_info (
644 mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly);
647 /* handle constructors */
649 table = &assembly->tables [MONO_TABLE_METHOD];
650 table->rows += mono_array_length (tb->ctors);
651 alloc_table (table, table->rows);
652 for (i = 0; i < mono_array_length (tb->ctors); ++i)
653 mono_image_get_ctor_info (
654 mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i), assembly);
659 table = &assembly->tables [MONO_TABLE_FIELD];
660 table->rows += mono_array_length (tb->fields);
661 alloc_table (table, table->rows);
662 for (i = 0; i < mono_array_length (tb->fields); ++i)
663 mono_image_get_field_info (
664 mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly);
667 /* Do the same with properties etc.. */
668 if (tb->properties && mono_array_length (tb->properties)) {
669 table = &assembly->tables [MONO_TABLE_PROPERTY];
670 table->rows += mono_array_length (tb->properties);
671 alloc_table (table, table->rows);
672 table = &assembly->tables [MONO_TABLE_PROPERTYMAP];
674 alloc_table (table, table->rows);
675 values = table->values + table->rows * MONO_PROPERTY_MAP_SIZE;
676 values [MONO_PROPERTY_MAP_PARENT] = tb->table_idx;
677 values [MONO_PROPERTY_MAP_PROPERTY_LIST] = assembly->tables [MONO_TABLE_PROPERTY].next_idx;
678 for (i = 0; i < mono_array_length (tb->properties); ++i)
679 mono_image_get_property_info (
680 mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i), assembly);
685 mono_image_fill_module_table (MonoReflectionModuleBuilder *mb, MonoDynamicAssembly *assembly)
687 MonoDynamicTable *table;
691 table = &assembly->tables [MONO_TABLE_MODULE];
692 mb->table_idx = table->next_idx ++;
693 name = mono_string_to_utf8 (mb->module.name);
694 table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name);
696 /* need to set mvid? */
699 * fill-in info in other tables as well.
701 table = &assembly->tables [MONO_TABLE_TYPEDEF];
702 table->rows += mono_array_length (mb->types);
703 alloc_table (table, table->rows);
704 for (i = 0; i < mono_array_length (mb->types); ++i)
705 mono_image_get_type_info (mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
708 #define align_pointer(base,p)\
710 guint32 __diff = (unsigned char*)(p)-(unsigned char*)(base);\
712 (p) += 4 - (__diff & 3);\
716 build_compressed_metadata (MonoDynamicAssembly *assembly)
719 guint64 valid_mask = 0;
720 guint32 heapt_size = 0;
721 guint32 meta_size = 256; /* allow for header and other stuff */
722 guint32 table_offset;
729 char *version = "mono" VERSION;
731 /* Compute table sizes */
732 meta = assembly->assembly.image = g_new0 (MonoImage, 1);
734 /* Setup the info used by compute_sizes () */
735 meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0;
736 meta->idx_guid_wide = assembly->guid.index >= 65536 ? 1 : 0;
737 meta->idx_string_wide = assembly->sheap.index >= 65536 ? 1 : 0;
739 meta_size += assembly->blob.index;
740 meta_size += assembly->guid.index;
741 meta_size += assembly->sheap.index;
742 meta_size += assembly->us.index;
744 for (i=0; i < 64; ++i)
745 meta->tables [i].rows = assembly->tables [i].rows;
747 for (i = 0; i < 64; i++){
748 if (meta->tables [i].rows == 0)
750 valid_mask |= (guint64)1 << i;
752 meta->tables [i].row_size = mono_metadata_compute_size (
753 meta, i, &meta->tables [i].size_bitfield);
754 heapt_size += meta->tables [i].row_size * meta->tables [i].rows;
756 heapt_size += 24; /* #~ header size */
757 heapt_size += ntables * 4;
758 meta_size += heapt_size;
759 meta->raw_metadata = g_malloc0 (meta_size);
760 p = meta->raw_metadata;
761 /* the metadata signature */
762 *p++ = 'B'; *p++ = 'S'; *p++ = 'J'; *p++ = 'B';
763 /* version numbers and 4 bytes reserved */
764 int16val = (guint16*)p;
769 int32val = (guint32*)p;
770 *int32val = strlen (version);
772 memcpy (p, version, *int32val);
774 align_pointer (meta->raw_metadata, p);
775 int16val = (guint16*)p;
776 *int16val++ = 0; /* flags must be 0 */
777 *int16val = 5; /* number of streams */
781 * write the stream info.
783 table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */
785 int32val = (guint32*)p;
786 *int32val++ = assembly->tstream.offset = table_offset;
787 *int32val = heapt_size;
788 table_offset += *int32val;
792 align_pointer (meta->raw_metadata, p);
794 int32val = (guint32*)p;
795 *int32val++ = assembly->sheap.offset = table_offset;
796 *int32val = assembly->sheap.index;
797 table_offset += *int32val;
799 strcpy (p, "#Strings");
801 align_pointer (meta->raw_metadata, p);
803 int32val = (guint32*)p;
804 *int32val++ = assembly->us.offset = table_offset;
805 *int32val = assembly->us.index;
806 table_offset += *int32val;
810 align_pointer (meta->raw_metadata, p);
812 int32val = (guint32*)p;
813 *int32val++ = assembly->blob.offset = table_offset;
814 *int32val = assembly->blob.index;
815 table_offset += *int32val;
819 align_pointer (meta->raw_metadata, p);
821 int32val = (guint32*)p;
822 *int32val++ = assembly->guid.offset = table_offset;
823 *int32val = assembly->guid.index;
824 table_offset += *int32val;
828 align_pointer (meta->raw_metadata, p);
831 * now copy the data, the table stream header and contents goes first.
833 g_assert ((p - (unsigned char*)meta->raw_metadata) < assembly->tstream.offset);
834 p = meta->raw_metadata + assembly->tstream.offset;
835 int32val = (guint32*)p;
836 *int32val = 0; /* reserved */
838 *p++ = 1; /* version */
840 if (meta->idx_string_wide)
842 if (meta->idx_guid_wide)
844 if (meta->idx_blob_wide)
847 *p++ = 0; /* reserved */
848 int64val = (guint64*)p;
849 *int64val++ = valid_mask;
850 *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now */
852 int32val = (guint32*)p;
853 for (i = 0; i < 64; i++){
854 if (meta->tables [i].rows == 0)
856 *int32val++ = meta->tables [i].rows;
858 p = (unsigned char*)int32val;
859 /* compress the tables */
860 for (i = 0; i < 64; i++){
863 guint32 bitfield = meta->tables [i].size_bitfield;
864 if (!meta->tables [i].rows)
866 if (assembly->tables [i].columns != mono_metadata_table_count (bitfield))
867 g_error ("col count mismatch in %d: %d %d", i, assembly->tables [i].columns, mono_metadata_table_count (bitfield));
868 meta->tables [i].base = p;
869 for (row = 1; row <= meta->tables [i].rows; ++row) {
870 values = assembly->tables [i].values + row * assembly->tables [i].columns;
871 for (col = 0; col < assembly->tables [i].columns; ++col) {
872 switch (mono_metadata_table_size (bitfield, col)) {
877 int16val = (guint16*)p;
878 *int16val = values [col];
882 int32val = (guint32*)p;
883 *int32val = values [col];
887 g_assert_not_reached ();
891 g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size));
894 g_assert (assembly->guid.offset + assembly->guid.index < meta_size);
895 memcpy (meta->raw_metadata + assembly->sheap.offset, assembly->sheap.data, assembly->sheap.index);
896 memcpy (meta->raw_metadata + assembly->us.offset, assembly->us.data, assembly->us.index);
897 memcpy (meta->raw_metadata + assembly->blob.offset, assembly->blob.data, assembly->blob.index);
898 memcpy (meta->raw_metadata + assembly->guid.offset, assembly->guid.data, assembly->guid.index);
900 assembly->meta_size = assembly->guid.offset + assembly->guid.index;
904 mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb)
906 MonoDynamicTable *table;
907 MonoDynamicAssembly *assembly = assemblyb->dynamic_assembly;
913 assembly->text_rva = 0x00002000;
915 table = &assembly->tables [MONO_TABLE_ASSEMBLY];
916 alloc_table (table, 1);
917 values = table->values + MONO_ASSEMBLY_SIZE;
918 values [MONO_ASSEMBLY_HASH_ALG] = 0x8004;
919 name = mono_string_to_utf8 (assemblyb->name);
920 values [MONO_ASSEMBLY_NAME] = string_heap_insert (&assembly->sheap, name);
922 values [MONO_ASSEMBLY_CULTURE] = string_heap_insert (&assembly->sheap, "");
923 values [MONO_ASSEMBLY_PUBLIC_KEY] = 0;
924 values [MONO_ASSEMBLY_MAJOR_VERSION] = 0;
925 values [MONO_ASSEMBLY_MINOR_VERSION] = 0;
926 values [MONO_ASSEMBLY_REV_NUMBER] = 0;
927 values [MONO_ASSEMBLY_BUILD_NUMBER] = 0;
929 assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* .<Module> */
930 assembly->tables [MONO_TABLE_TYPEDEF].next_idx++;
932 len = mono_array_length (assemblyb->modules);
933 table = &assembly->tables [MONO_TABLE_MODULE];
934 alloc_table (table, len);
935 for (i = 0; i < len; ++i)
936 mono_image_fill_module_table (mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly);
938 table = &assembly->tables [MONO_TABLE_TYPEDEF];
940 * table->rows is already set above and in mono_image_fill_module_table.
942 alloc_table (table, table->rows);
944 * Set the first entry.
946 values = table->values + table->columns;
947 values [MONO_TYPEDEF_FLAGS] = 0;
948 values [MONO_TYPEDEF_NAME] = string_heap_insert (&assembly->sheap, "<Module>") ;
949 values [MONO_TYPEDEF_NAMESPACE] = string_heap_insert (&assembly->sheap, "") ;
950 values [MONO_TYPEDEF_EXTENDS] = 0;
951 values [MONO_TYPEDEF_FIELD_LIST] = 1;
952 values [MONO_TYPEDEF_METHOD_LIST] = 1;
954 /* later include all the assemblies referenced */
955 table = &assembly->tables [MONO_TABLE_ASSEMBLYREF];
956 alloc_table (table, 1);
957 values = table->values + table->columns;
958 values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib");
960 build_compressed_metadata (assembly);
964 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str)
970 if (!assembly->dynamic_assembly)
971 mono_image_basic_init (assembly);
972 mono_metadata_encode_value (str->length, b, &b);
973 index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf);
974 /* FIXME: ENOENDIAN */
975 mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2);
980 * Get a token to insert in the IL code stream for the given MemberInfo.
990 mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj)
992 MonoClass *klass = obj->klass;
994 g_print ("requested token for %s\n", klass->name);
996 if (strcmp (klass->name, "MethodBuilder") == 0) {
997 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
998 return mb->table_idx | MONO_TOKEN_METHOD_DEF;
1000 if (strcmp (klass->name, "FieldBuilder") == 0) {
1001 MonoReflectionFieldBuilder *mb = (MonoReflectionFieldBuilder *)obj;
1002 return mb->table_idx | MONO_TOKEN_FIELD_DEF;
1008 mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
1010 MonoDynamicAssembly *assembly;
1013 if (assemblyb->dynamic_assembly)
1016 assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
1018 string_heap_init (&assembly->sheap);
1019 mono_image_add_stream_data (&assembly->us, "", 1);
1020 mono_image_add_stream_data (&assembly->blob, "", 1);
1022 for (i=0; i < 64; ++i) {
1023 assembly->tables [i].next_idx = 1;
1024 assembly->tables [i].columns = table_sizes [i];
1030 mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize)
1032 MonoMSDOSHeader *msdos;
1033 MonoDotNetHeader *header;
1034 MonoSectionTable *section;
1035 MonoCLIHeader *cli_header;
1036 guint32 header_size = TEXT_OFFSET + CLI_H_SIZE;
1037 MonoDynamicAssembly *assembly;
1039 static const unsigned char msheader[] = {
1040 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
1041 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
1044 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
1045 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
1046 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
1047 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1050 if (maxsize < header_size)
1053 mono_image_basic_init (assemblyb);
1054 assembly = assemblyb->dynamic_assembly;
1056 mono_image_build_metadata (assemblyb);
1058 memset (buffer, 0, header_size);
1059 memcpy (buffer, msheader, sizeof (MonoMSDOSHeader));
1061 msdos = (MonoMSDOSHeader *)buffer;
1062 header = (MonoDotNetHeader *)(buffer + sizeof (MonoMSDOSHeader));
1063 section = (MonoSectionTable*) (buffer + sizeof (MonoMSDOSHeader) + sizeof (MonoDotNetHeader));
1065 /* FIXME: ENDIAN problem: byteswap as needed */
1066 msdos->pe_offset = sizeof (MonoMSDOSHeader);
1068 header->pesig [0] = 'P';
1069 header->pesig [1] = 'E';
1070 header->pesig [2] = header->pesig [3] = 0;
1072 header->coff.coff_machine = 0x14c;
1073 header->coff.coff_sections = 1; /* only .text supported now */
1074 header->coff.coff_time = time (NULL);
1075 header->coff.coff_opt_header_size = sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4;
1077 header->coff.coff_attributes = 0x010e;
1079 //header->coff.coff_attributes = 0x210e;
1080 header->pe.pe_magic = 0x10B;
1081 header->pe.pe_major = 6;
1082 header->pe.pe_minor = 0;
1083 /* need to set: pe_code_size pe_data_size pe_rva_entry_point pe_rva_code_base pe_rva_data_base */
1085 header->nt.pe_image_base = 0x400000;
1086 header->nt.pe_section_align = 8192;
1087 header->nt.pe_file_alignment = FILE_ALIGN;
1088 header->nt.pe_os_major = 4;
1089 header->nt.pe_os_minor = 0;
1090 header->nt.pe_subsys_major = 4;
1091 /* need to set pe_image_size, pe_header_size */
1092 header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */
1093 header->nt.pe_stack_reserve = 0x00100000;
1094 header->nt.pe_stack_commit = 0x00001000;
1095 header->nt.pe_heap_reserve = 0x00100000;
1096 header->nt.pe_heap_commit = 0x00001000;
1097 header->nt.pe_loader_flags = 1;
1098 header->nt.pe_data_dir_count = 16;
1102 header->datadir.pe_import_table
1107 header->datadir.pe_cli_header.size = CLI_H_SIZE;
1108 header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */
1110 /* Write section tables */
1111 strcpy (section->st_name, ".text");
1112 section->st_virtual_size = 1024; /* FIXME */
1113 section->st_virtual_address = assembly->text_rva;
1114 section->st_raw_data_size = 1024; /* FIXME */
1115 section->st_raw_data_ptr = TEXT_OFFSET;
1116 section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ;
1119 * align: build_compressed_metadata () assumes metadata is aligned
1121 * cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1123 assembly->code.index += 3;
1124 assembly->code.index &= ~3;
1127 * Write the MonoCLIHeader header
1129 cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET);
1130 cli_header->ch_size = CLI_H_SIZE;
1131 cli_header->ch_runtime_major = 2;
1132 cli_header->ch_flags = CLI_FLAGS_ILONLY;
1133 if (assemblyb->entry_point)
1134 cli_header->ch_entry_point = assemblyb->entry_point->table_idx | MONO_TOKEN_METHOD_DEF;
1136 cli_header->ch_entry_point = 0;
1137 cli_header->ch_metadata.rva = assembly->text_rva + assembly->code.index + CLI_H_SIZE;
1138 cli_header->ch_metadata.size = assembly->meta_size;
1144 * We need to return always the same object for Type, MethodInfo, FieldInfo etc..
1146 static GHashTable *object_cache = NULL;
1148 #define CHECK_OBJECT(t,p) \
1151 if (!object_cache) \
1152 object_cache = g_hash_table_new (g_direct_hash, g_direct_equal); \
1153 if ((_obj = g_hash_table_lookup (object_cache, (p)))) \
1157 #define CACHE_OBJECT(p,o) \
1159 g_hash_table_insert (object_cache, p,o); \
1162 MonoReflectionAssembly*
1163 mono_assembly_get_object (MonoAssembly *assembly)
1166 MonoReflectionAssembly *res;
1168 CHECK_OBJECT (MonoReflectionAssembly *, assembly);
1169 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "Assembly");
1170 res = (MonoReflectionAssembly *)mono_object_new (klass);
1171 res->assembly = assembly;
1172 CACHE_OBJECT (assembly, res);
1177 mono_type_get_object (MonoType *type)
1179 MonoReflectionType *res;
1181 CHECK_OBJECT (MonoReflectionType *, type);
1182 res = (MonoReflectionType *)mono_object_new (mono_defaults.monotype_class);
1184 CACHE_OBJECT (type, res);
1188 MonoReflectionMethod*
1189 mono_method_get_object (MonoMethod *method)
1192 * We use the same C representation for methods and constructors, but the type
1193 * name in C# is different.
1197 MonoReflectionMethod *ret;
1199 CHECK_OBJECT (MonoReflectionMethod *, method);
1200 if (*method->name == '.' && (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0))
1201 cname = "MonoCMethod";
1203 cname = "MonoMethod";
1204 klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", cname);
1206 ret = (MonoReflectionMethod*)mono_object_new (klass);
1207 ret->method = method;
1208 CACHE_OBJECT (method, ret);
1212 MonoReflectionField*
1213 mono_field_get_object (MonoClass *klass, MonoClassField *field)
1215 MonoReflectionField *res;
1218 CHECK_OBJECT (MonoReflectionField *, field);
1219 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoField");
1220 res = (MonoReflectionField *)mono_object_new (oklass);
1223 CACHE_OBJECT (field, res);
1227 MonoReflectionProperty*
1228 mono_property_get_object (MonoClass *klass, MonoProperty *property)
1230 MonoReflectionProperty *res;
1233 CHECK_OBJECT (MonoReflectionProperty *, property);
1234 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoProperty");
1235 res = (MonoReflectionProperty *)mono_object_new (oklass);
1237 res->property = property;
1238 CACHE_OBJECT (property, res);
1242 MonoReflectionParameter**
1243 mono_param_get_objects (MonoMethod *method)
1245 MonoReflectionParameter **res;
1246 MonoReflectionMethod *member;
1251 if (!method->signature->param_count)
1254 member = mono_method_get_object (method);
1255 names = g_new (char*, method->signature->param_count);
1257 /* Note: the cache is based on the address of the signature into the method
1258 * since we already cache MethodInfos with the method as keys.
1260 CHECK_OBJECT (MonoReflectionParameter**, &(method->signature));
1261 oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
1262 res = g_new0 (MonoReflectionParameter*, method->signature->param_count);
1263 for (i = 0; i < method->signature->param_count; ++i) {
1264 res [i] = (MonoReflectionParameter *)mono_object_new (oklass);
1265 res [i]->ClassImpl = mono_type_get_object (method->signature->params [i]);
1266 res [i]->DefaultValueImpl = NULL; /* FIXME */
1267 res [i]->MemberImpl = (MonoObject*)member;
1268 res [i]->NameImpl = mono_string_new (names [i]);
1269 res [i]->PositionImpl = i + 1;
1270 res [i]->AttrsImpl = method->signature->params [i]->attrs;
1273 CACHE_OBJECT (&(method->signature), res);