X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Freflection.c;h=e1b347a72dc8c5d3efe08746c94da6ee523cc428;hb=6a48219059a82e4c4af4b3a22ed7725cdf610aaa;hp=e12361c1ea57714985812f8484319ead6ae15b82;hpb=cb72b6c9ccf7b667a6dc06c6d63656396b711b2a;p=mono.git diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index e12361c1ea5..e1b347a72dc 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -13,6 +13,7 @@ #include "mono/metadata/tabledefs.h" #include "mono/metadata/tokentype.h" #include "mono/metadata/appdomain.h" +#include "mono/metadata/opcodes.h" #include #include #include @@ -23,6 +24,9 @@ #include "rawbuffer.h" #include "mono-endian.h" #include "private.h" +#if HAVE_BOEHM_GC +#include +#endif #define TEXT_OFFSET 512 #define CLI_H_SIZE 136 @@ -101,7 +105,7 @@ alloc_table (MonoDynamicTable *table, guint nrows) } static guint32 -string_heap_insert (MonoStringHeap *sh, const char *str) +string_heap_insert (MonoDynamicStream *sh, const char *str) { guint32 idx; guint32 len; @@ -128,7 +132,7 @@ string_heap_insert (MonoStringHeap *sh, const char *str) } static void -string_heap_init (MonoStringHeap *sh) +string_heap_init (MonoDynamicStream *sh) { sh->index = 0; sh->alloc_size = 4096; @@ -137,16 +141,18 @@ string_heap_init (MonoStringHeap *sh) string_heap_insert (sh, ""); } +#if 0 /* never used */ static void -string_heap_free (MonoStringHeap *sh) +string_heap_free (MonoDynamicStream *sh) { g_free (sh->data); g_hash_table_foreach (sh->hash, (GHFunc)g_free, NULL); g_hash_table_destroy (sh->hash); } +#endif static guint32 -mono_image_add_stream_data (MonoDynamicStream *stream, char *data, guint32 len) +mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len) { guint32 idx; if (stream->alloc_size < stream->index + len) { @@ -270,6 +276,7 @@ method_encode_signature (MonoDynamicAssembly *assembly, MonoMethodSignature *sig for (i = 0; i < nparams; ++i) encode_type (assembly, sig->params [i], p, &p); /* store length */ + g_assert (p - buf < size); mono_metadata_encode_value (p-buf, b, &b); idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); mono_image_add_stream_data (&assembly->blob, buf, p-buf); @@ -307,6 +314,7 @@ method_builder_encode_signature (MonoDynamicAssembly *assembly, ReflectionMethod encode_reflection_type (assembly, pt, p, &p); } /* store length */ + g_assert (p - buf < size); mono_metadata_encode_value (p-buf, b, &b); idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); mono_image_add_stream_data (&assembly->blob, buf, p-buf); @@ -320,14 +328,15 @@ encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen) MonoDynamicTable *table; guint32 *values; char *p; - guint32 idx, sig_idx; + guint32 idx, sig_idx, size; guint nl = mono_array_length (ilgen->locals); char *buf; char blob_size [6]; char *b = blob_size; int i; - p = buf = g_malloc (10 + nl * 10); + size = 10 + nl * 10; + p = buf = g_malloc (size); table = &assembly->tables [MONO_TABLE_STANDALONESIG]; idx = table->next_idx ++; table->rows ++; @@ -340,6 +349,7 @@ encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen) MonoReflectionLocalBuilder *lb = mono_array_get (ilgen->locals, MonoReflectionLocalBuilder*, i); encode_reflection_type (assembly, lb->type, p, &p); } + g_assert (p - buf < size); mono_metadata_encode_value (p-buf, b, &b); sig_idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); mono_image_add_stream_data (&assembly->blob, buf, p-buf); @@ -410,7 +420,7 @@ method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb) idx = mono_image_add_stream_data (&assembly->code, &flags, 1); /* add to the fixup todo list */ if (mb->ilgen && mb->ilgen->num_token_fixups) - g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1)); + mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 1)); mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size); return assembly->text_rva + idx + CLI_H_SIZE; } @@ -435,7 +445,7 @@ fat_header: idx = mono_image_add_stream_data (&assembly->code, fat_header, 12); /* add to the fixup todo list */ if (mb->ilgen && mb->ilgen->num_token_fixups) - g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12)); + mono_g_hash_table_insert (assembly->token_fixups, mb->ilgen, GUINT_TO_POINTER (idx + 12)); mono_image_add_stream_data (&assembly->code, mono_array_addr (code, char, 0), code_size); if (num_exception) { @@ -479,7 +489,7 @@ fat_header: mono_image_add_stream_data (&assembly->code, (char*)&clause, sizeof (clause)); } } else { - g_error ("No clauses"); + g_error ("No clauses for ex info block %d", i); } } } @@ -487,7 +497,7 @@ fat_header: } static guint32 -find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 index) +find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guint32 token) { int i; MonoDynamicTable *table; @@ -499,18 +509,18 @@ find_index_in_table (MonoDynamicAssembly *assembly, int table_idx, int col, guin values = table->values + table->columns; for (i = 1; i <= table->rows; ++i) { - if (values [col] == index) + if (values [col] == token) return i; } return 0; } /* - * index is the table index of the object + * idx is the table index of the object * type is one of CUSTOM_ATTR_* */ static void -mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 index, guint32 type, MonoArray *cattrs) +mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 idx, guint32 type, MonoArray *cattrs) { MonoDynamicTable *table; MonoReflectionCustomAttr *cattr; @@ -527,11 +537,11 @@ mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 index, guint32 typ table->rows += count; alloc_table (table, table->rows); values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE; - index <<= CUSTOM_ATTR_BITS; - index |= type; + idx <<= CUSTOM_ATTR_BITS; + idx |= type; for (i = 0; i < count; ++i) { cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i); - values [MONO_CUSTOM_ATTR_PARENT] = index; + values [MONO_CUSTOM_ATTR_PARENT] = idx; token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor); type = mono_metadata_token_index (token); type <<= CUSTOM_ATTR_TYPE_BITS; @@ -556,6 +566,10 @@ mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 index, guint32 typ } } +/* + * Fill in the MethodDef and ParamDef tables for a method. + * This is used for both normal methods and constructors. + */ static void mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assembly) { @@ -778,7 +792,18 @@ handle_enum: goto handle_enum; } else g_error ("we can't encode valuetypes"); - case MONO_TYPE_STRING: + case MONO_TYPE_STRING: { + MonoString *str = (MonoString*)val; + /* there is no signature */ + len = str->length * 2; + mono_metadata_encode_value (len, b, &b); + idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); + /* FIXME: ENOENDIAN */ + mono_image_add_stream_data (&assembly->blob, (const char*)mono_string_chars (str), len); + + g_free (buf); + return idx; + } default: g_error ("we don't encode constant type 0x%02x yet", *ret_type); } @@ -800,6 +825,9 @@ mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly * guint32 *values; char *name; + /* maybe this fixup should be done in the C# code */ + if (fb->attrs & FIELD_ATTRIBUTE_LITERAL) + fb->attrs |= FIELD_ATTRIBUTE_HAS_DEFAULT; table = &assembly->tables [MONO_TABLE_FIELD]; fb->table_idx = table->next_idx ++; values = table->values + fb->table_idx * MONO_FIELD_SIZE; @@ -852,11 +880,12 @@ property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionProperty char *b = blob_size; guint32 nparams = 0; MonoReflectionMethodBuilder *mb = fb->get_method; - guint32 idx, i; + guint32 idx, i, size; if (mb && mb->parameters) nparams = mono_array_length (mb->parameters); - buf = p = g_malloc (24 + nparams * 10); + size = 24 + nparams * 10; + buf = p = g_malloc (size); *p = 0x08; p++; mono_metadata_encode_value (nparams, p, &p); @@ -870,6 +899,7 @@ property_encode_signature (MonoDynamicAssembly *assembly, MonoReflectionProperty *p++ = 1; /* void: a property should probably not be allowed without a getter */ } /* store length */ + g_assert (p - buf < size); mono_metadata_encode_value (p-buf, b, &b); idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); mono_image_add_stream_data (&assembly->blob, buf, p-buf); @@ -995,7 +1025,7 @@ resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image) guint32 *values; guint32 cols [MONO_ASSEMBLY_SIZE]; - if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, image)))) + if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, image)))) return token; mono_metadata_decode_row (&image->tables [MONO_TABLE_ASSEMBLY], 0, cols, MONO_ASSEMBLY_SIZE); @@ -1005,7 +1035,10 @@ resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image) table->rows ++; alloc_table (table, table->rows); values = table->values + token * MONO_ASSEMBLYREF_SIZE; - values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, image->assembly_name); + if (strcmp ("corlib", image->assembly_name) == 0) + values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "mscorlib"); + else + values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, image->assembly_name); values [MONO_ASSEMBLYREF_MAJOR_VERSION] = cols [MONO_ASSEMBLY_MAJOR_VERSION]; values [MONO_ASSEMBLYREF_MINOR_VERSION] = cols [MONO_ASSEMBLY_MINOR_VERSION]; values [MONO_ASSEMBLYREF_BUILD_NUMBER] = cols [MONO_ASSEMBLY_BUILD_NUMBER]; @@ -1017,10 +1050,51 @@ resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image) token <<= RESOLTION_SCOPE_BITS; token |= RESOLTION_SCOPE_ASSEMBLYREF; - g_hash_table_insert (assembly->typeref, image, GUINT_TO_POINTER (token)); + g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token)); + return token; +} + +static guint32 +create_typespec (MonoDynamicAssembly *assembly, MonoType *type) +{ + MonoDynamicTable *table; + guint32 *values; + guint32 token; + char sig [128]; + char *p = sig; + char blob_size [6]; + char *b = blob_size; + + switch (type->type) { + case MONO_TYPE_FNPTR: + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: + encode_type (assembly, type, p, &p); + break; + default: + return 0; + } + + g_assert (p-sig < 128); + mono_metadata_encode_value (p-sig, b, &b); + token = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size); + mono_image_add_stream_data (&assembly->blob, sig, p-sig); + + table = &assembly->tables [MONO_TABLE_TYPESPEC]; + alloc_table (table, table->rows + 1); + values = table->values + table->next_idx * MONO_TYPESPEC_SIZE; + values [MONO_TYPESPEC_SIGNATURE] = token; + + token = TYPEDEFORREF_TYPESPEC | (table->next_idx << TYPEDEFORREF_BITS); + g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token)); + table->next_idx ++; return token; } +/* + * Despite the name, we handle also TypeSpec (with the above helper). + */ static guint32 mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type) { @@ -1030,6 +1104,9 @@ mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type) MonoClass *klass; token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type)); + if (token) + return token; + token = create_typespec (assembly, type); if (token) return token; klass = mono_class_from_mono_type (type); @@ -1053,6 +1130,12 @@ mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type) return token; } +/* + * Insert a memberef row into the metadata: the token that point to the memberref + * is returned. Caching is done in the caller (mono_image_get_methodref_token() or + * mono_image_get_fieldref_token()). + * The sig param is an index to an already built signature. + */ static guint32 mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoClass *klass, const char *name, guint32 sig) { @@ -1094,12 +1177,12 @@ mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *metho { guint32 token; - token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, method)); + token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method)); if (token) return token; token = mono_image_get_memberref_token (assembly, method->klass, method->name, method_encode_signature (assembly, method->signature)); - g_hash_table_insert (assembly->typeref, method, GUINT_TO_POINTER(token)); + g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token)); return token; } @@ -1108,15 +1191,19 @@ mono_image_get_fieldref_token (MonoDynamicAssembly *assembly, MonoClassField *fi { guint32 token; - token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, field)); + token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, field)); if (token) return token; token = mono_image_get_memberref_token (assembly, klass, field->name, fieldref_encode_signature (assembly, field)); - g_hash_table_insert (assembly->typeref, field, GUINT_TO_POINTER(token)); + g_hash_table_insert (assembly->handleref, field, GUINT_TO_POINTER(token)); return token; } +/* + * Insert into the metadata tables all the info about the TypeBuilder tb. + * Data in the tables is inserted in a predefined order, since some tables need to be sorted. + */ static void mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, MonoDynamicAssembly *assembly) { @@ -1274,7 +1361,12 @@ mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *m name = mono_string_to_utf8 (mb->module.name); table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, name); g_free (name); - /* need to set mvid? */ + i = mono_image_add_stream_data (&assembly->guid, mono_array_addr (mb->guid, char, 0), 16); + i /= 16; + ++i; + table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_MVID] = i; + table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENC] = 0; + table->values [mb->table_idx * MONO_MODULE_SIZE + MONO_MODULE_ENCBASE] = 0; mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_MODULE, mb->cattrs); /* @@ -1309,11 +1401,18 @@ mono_image_fill_module_table (MonoDomain *domain, MonoReflectionModuleBuilder *m (p) += 4 - (__diff & 3);\ } while (0) +/* + * build_compressed_metadata() fills in the blob of data that represents the + * raw metadata as it will be saved in the PE file. The five streams are output + * and the metadata tables are comnpressed from the guint32 array representation, + * to the compressed on-disk format. + */ static void build_compressed_metadata (MonoDynamicAssembly *assembly) { int i; guint64 valid_mask = 0; + guint64 sorted_mask; guint32 heapt_size = 0; guint32 meta_size = 256; /* allow for header and other stuff */ guint32 table_offset; @@ -1323,10 +1422,29 @@ build_compressed_metadata (MonoDynamicAssembly *assembly) guint16 *int16val; MonoImage *meta; unsigned char *p; - char *version = "mono" VERSION; + const char *version = "mono" VERSION; + struct StreamDesc { + const char *name; + MonoDynamicStream *stream; + } stream_desc [] = { + {"#~", &assembly->tstream}, + {"#Strings", &assembly->sheap}, + {"#US", &assembly->us}, + {"#Blob", &assembly->blob}, + {"#GUID", &assembly->guid}, + }; + + /* tables that are sorted */ + sorted_mask = ((guint64)1 << MONO_TABLE_CONSTANT) | ((guint64)1 << MONO_TABLE_FIELDMARSHAL) + | ((guint64)1 << MONO_TABLE_METHODSEMANTICS) | ((guint64)1 << MONO_TABLE_CLASSLAYOUT) + | ((guint64)1 << MONO_TABLE_FIELDLAYOUT) | ((guint64)1 << MONO_TABLE_FIELDRVA) + | ((guint64)1 << MONO_TABLE_IMPLMAP) | ((guint64)1 << MONO_TABLE_NESTEDCLASS) + | ((guint64)1 << MONO_TABLE_METHODIMPL) | ((guint64)1 << MONO_TABLE_CUSTOMATTRIBUTE) + | ((guint64)1 << MONO_TABLE_DECLSECURITY); /* Compute table sizes */ - meta = assembly->assembly.image = g_new0 (MonoImage, 1); + /* the MonoImage has already been created in mono_image_basic_init() */ + meta = assembly->assembly.image; /* Setup the info used by compute_sizes () */ meta->idx_blob_wide = assembly->blob.index >= 65536 ? 1 : 0; @@ -1379,57 +1497,19 @@ build_compressed_metadata (MonoDynamicAssembly *assembly) */ table_offset = (p - (unsigned char*)meta->raw_metadata) + 5 * 8 + 40; /* room needed for stream headers */ table_offset += 3; table_offset &= ~3; - - int32val = (guint32*)p; - *int32val++ = assembly->tstream.offset = table_offset; - *int32val = heapt_size; - table_offset += *int32val; - table_offset += 3; table_offset &= ~3; - p += 8; - strcpy (p, "#~"); - p += 3; - align_pointer (meta->raw_metadata, p); - - int32val = (guint32*)p; - *int32val++ = assembly->sheap.offset = table_offset; - *int32val = assembly->sheap.index; - table_offset += *int32val; - table_offset += 3; table_offset &= ~3; - p += 8; - strcpy (p, "#Strings"); - p += 9; - align_pointer (meta->raw_metadata, p); - - int32val = (guint32*)p; - *int32val++ = assembly->us.offset = table_offset; - *int32val = assembly->us.index; - table_offset += *int32val; - table_offset += 3; table_offset &= ~3; - p += 8; - strcpy (p, "#US"); - p += 4; - align_pointer (meta->raw_metadata, p); - - int32val = (guint32*)p; - *int32val++ = assembly->blob.offset = table_offset; - *int32val = assembly->blob.index; - table_offset += *int32val; - table_offset += 3; table_offset &= ~3; - p += 8; - strcpy (p, "#Blob"); - p += 6; - align_pointer (meta->raw_metadata, p); - - int32val = (guint32*)p; - *int32val++ = assembly->guid.offset = table_offset; - *int32val = assembly->guid.index; - table_offset += *int32val; - table_offset += 3; table_offset &= ~3; - p += 8; - strcpy (p, "#GUID"); - p += 6; - align_pointer (meta->raw_metadata, p); + assembly->tstream.index = heapt_size; + for (i = 0; i < 5; ++i) { + int32val = (guint32*)p; + *int32val++ = stream_desc [i].stream->offset = table_offset; + *int32val = stream_desc [i].stream->index; + table_offset += *int32val; + table_offset += 3; table_offset &= ~3; + p += 8; + strcpy (p, stream_desc [i].name); + p += strlen (stream_desc [i].name) + 1; + align_pointer (meta->raw_metadata, p); + } /* * now copy the data, the table stream header and contents goes first. */ @@ -1450,7 +1530,7 @@ build_compressed_metadata (MonoDynamicAssembly *assembly) *p++ = 0; /* reserved */ int64val = (guint64*)p; *int64val++ = valid_mask; - *int64val++ = 0; /* bitvector of sorted tables, set to 0 for now */ + *int64val++ = valid_mask & sorted_mask; /* bitvector of sorted tables */ p += 16; int32val = (guint32*)p; for (i = 0; i < 64; i++){ @@ -1491,7 +1571,7 @@ build_compressed_metadata (MonoDynamicAssembly *assembly) } } } - g_assert ((p - (unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size)); + g_assert ((p - (const unsigned char*)meta->tables [i].base) == (meta->tables [i].rows * meta->tables [i].row_size)); } g_assert (assembly->guid.offset + assembly->guid.index < meta_size); @@ -1503,6 +1583,15 @@ build_compressed_metadata (MonoDynamicAssembly *assembly) assembly->meta_size = assembly->guid.offset + assembly->guid.index; } +/* + * Some tables in metadata need to be sorted according to some criteria, but + * when methods and fields are first created with reflection, they may be assigned a token + * that doesn't correspond to the final token they will get assigned after the sorting. + * ILGenerator.cs keeps a fixup table that maps the position of tokens in the IL code stream + * with the reflection objects that represent them. Once all the tables are set up, the + * reflection objects will contains the correct table index. fixup_method() will fixup the + * tokens for the method with ILGenerator @ilgen. + */ static void fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *assembly) { guint32 code_idx = GPOINTER_TO_UINT (value); @@ -1510,7 +1599,7 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *a MonoReflectionFieldBuilder *field; MonoReflectionCtorBuilder *ctor; MonoReflectionMethodBuilder *method; - guint32 i, index; + guint32 i, idx; unsigned char *target; for (i = 0; i < ilgen->num_token_fixups; ++i) { @@ -1521,15 +1610,15 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *a if (strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) g_assert_not_reached (); field = (MonoReflectionFieldBuilder *)iltoken->member; - index = field->table_idx; + idx = field->table_idx; break; case MONO_TABLE_METHOD: if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) { method = (MonoReflectionMethodBuilder *)iltoken->member; - index = method->table_idx; + idx = method->table_idx; } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) { ctor = (MonoReflectionCtorBuilder *)iltoken->member; - index = ctor->table_idx; + idx = ctor->table_idx; } else { g_assert_not_reached (); } @@ -1537,12 +1626,20 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicAssembly *a default: g_error ("got unexpected table 0x%02x in fixup", target [3]); } - target [0] = index & 0xff; - target [1] = (index >> 8) & 0xff; - target [2] = (index >> 16) & 0xff; + target [0] = idx & 0xff; + target [1] = (idx >> 8) & 0xff; + target [2] = (idx >> 16) & 0xff; } } +/* + * mono_image_build_metadata() will fill the info in all the needed metadata tables + * for the AssemblyBuilder @assemblyb: it iterates over the assembly modules + * and recursively outputs the info for a module. Each module will output all the info + * about it's types etc. + * At the end of the process, method and field tokens are fixed up and the on-disk + * compressed metadata representation is created. + */ static void mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb) { @@ -1569,6 +1666,7 @@ mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb) values [MONO_ASSEMBLY_MINOR_VERSION] = 0; values [MONO_ASSEMBLY_REV_NUMBER] = 0; values [MONO_ASSEMBLY_BUILD_NUMBER] = 0; + values [MONO_ASSEMBLY_FLAGS] = 0; mono_image_add_cattrs (assembly, 1, CUSTOM_ATTR_ASSEMBLY, assemblyb->cattrs); @@ -1606,31 +1704,42 @@ mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb) values [MONO_TYPEDEF_METHOD_LIST] = 1; /* fixup tokens */ - g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly); + mono_g_hash_table_foreach (assembly->token_fixups, (GHFunc)fixup_method, assembly); build_compressed_metadata (assembly); } +/* + * mono_image_insert_string: + * @assembly: assembly builder object + * @str: a string + * + * Insert @str into the user string stream of @assembly. + */ guint32 mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *str) { - guint32 index; + guint32 idx; char buf [16]; char *b = buf; if (!assembly->dynamic_assembly) mono_image_basic_init (assembly); mono_metadata_encode_value (1 | (str->length * 2), b, &b); - index = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf); + idx = mono_image_add_stream_data (&assembly->dynamic_assembly->us, buf, b-buf); /* FIXME: ENOENDIAN */ - mono_image_add_stream_data (&assembly->dynamic_assembly->us, (char*)mono_string_chars (str), str->length * 2); + mono_image_add_stream_data (&assembly->dynamic_assembly->us, (const char*)mono_string_chars (str), str->length * 2); mono_image_add_stream_data (&assembly->dynamic_assembly->us, "", 1); - return MONO_TOKEN_STRING | index; + return MONO_TOKEN_STRING | idx; } /* + * mono_image_create_token: + * @assembly: a dynamic assembly + * @obj: + * * Get a token to insert in the IL code stream for the given MemberInfo. - * obj can be: + * @obj can be one of: * ConstructorBuilder * MethodBuilder * FieldBuilder @@ -1643,9 +1752,13 @@ mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *s guint32 mono_image_create_token (MonoDynamicAssembly *assembly, MonoObject *obj) { - MonoClass *klass = obj->vtable->klass; + MonoClass *klass; guint32 token; + if (!obj) + g_error ("System.Array methods not yet supported"); + + klass = obj->vtable->klass; if (strcmp (klass->name, "MethodBuilder") == 0) { MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj; token = mb->table_idx | MONO_TOKEN_METHOD_DEF; @@ -1688,6 +1801,13 @@ mono_image_create_token (MonoDynamicAssembly *assembly, MonoObject *obj) return 0; } +/* + * mono_image_basic_ini: + * @assembly: an assembly builder object + * + * Create the MonoImage that represents the assembly builder and setup some + * of the helper hash table and the basic metadata streams. + */ void mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb) { @@ -1698,10 +1818,15 @@ mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb) if (assemblyb->dynamic_assembly) return; +#if HAVE_BOEHM_GC + assembly = assemblyb->dynamic_assembly = GC_malloc (sizeof (MonoDynamicAssembly)); +#else assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1); +#endif - assembly->token_fixups = g_hash_table_new (g_direct_hash, g_direct_equal); - assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal); + assembly->token_fixups = mono_g_hash_table_new (g_direct_hash, g_direct_equal); + assembly->handleref = g_hash_table_new (g_direct_hash, g_direct_equal); + assembly->typeref = g_hash_table_new (mono_metadata_type_hash, mono_metadata_type_equal); string_heap_init (&assembly->sheap); mono_image_add_stream_data (&assembly->us, "", 1); @@ -1727,6 +1852,18 @@ mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb) } +/* + * mono_image_get_heade: + * @assemblyb: an assembly builder object + * @buffer: + * @maxsize + * + * When we need to save an assembly, we first call this function that ensures the metadata + * tables are built for all the modules in the assembly. This function creates the PE-COFF + * header, the image sections, the CLI header etc. The header is written in @buffer + * and the length of the data written is returned. + * If @buffer is not big enough (@maxsize), -1 is returned. + */ int mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, int maxsize) { @@ -1790,6 +1927,8 @@ mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, i header->nt.pe_os_minor = 0; header->nt.pe_subsys_major = 4; /* need to set pe_image_size, pe_header_size */ + header->nt.pe_header_size = 0x200; + header->nt.pe_image_size = 0x00008000; header->nt.pe_subsys_required = 3; /* 3 -> cmdline app, 2 -> GUI app */ header->nt.pe_stack_reserve = 0x00100000; header->nt.pe_stack_commit = 0x00001000; @@ -1805,7 +1944,7 @@ mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, i pe_reloc_table pe_iat #endif - header->datadir.pe_cli_header.size = CLI_H_SIZE; + header->datadir.pe_cli_header.size = 72; header->datadir.pe_cli_header.rva = assembly->text_rva; /* we put it always at the beginning */ /* Write section tables */ @@ -1829,7 +1968,7 @@ mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, i * Write the MonoCLIHeader header */ cli_header = (MonoCLIHeader*)(buffer + TEXT_OFFSET); - cli_header->ch_size = CLI_H_SIZE; + cli_header->ch_size = 72; cli_header->ch_runtime_major = 2; cli_header->ch_flags = CLI_FLAGS_ILONLY; if (assemblyb->entry_point) @@ -1846,23 +1985,30 @@ mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, i * We need to return always the same object for MethodInfo, FieldInfo etc.. * type uses a different hash, since it uses custom hash/equal functions. */ -static GHashTable *object_cache = NULL; -static GHashTable *type_cache = NULL; +static MonoGHashTable *object_cache = NULL; +static MonoGHashTable *type_cache = NULL; #define CHECK_OBJECT(t,p) \ do { \ t _obj; \ if (!object_cache) \ - object_cache = g_hash_table_new (g_direct_hash, g_direct_equal); \ - if ((_obj = g_hash_table_lookup (object_cache, (p)))) \ + object_cache = mono_g_hash_table_new (g_direct_hash, g_direct_equal); \ + if ((_obj = mono_g_hash_table_lookup (object_cache, (p)))) \ return _obj; \ } while (0) #define CACHE_OBJECT(p,o) \ do { \ - g_hash_table_insert (object_cache, p,o); \ + mono_g_hash_table_insert (object_cache, p,o); \ } while (0) - + +/* + * mono_assembly_get_object: + * @domain: an app domain + * @assembly: an assembly + * + * Return an System.Reflection.Assembly object representing the MonoAssembly @assembly. + */ MonoReflectionAssembly* mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly) { @@ -1943,6 +2089,13 @@ mymono_metadata_type_hash (MonoType *t1) return hash; } +/* + * mono_type_get_object: + * @domain: an app domain + * @type: a type + * + * Return an System.MonoType object representing the type @type. + */ MonoReflectionType* mono_type_get_object (MonoDomain *domain, MonoType *type) { @@ -1950,9 +2103,9 @@ mono_type_get_object (MonoDomain *domain, MonoType *type) MonoClass *klass = mono_class_from_mono_type (type); if (!type_cache) - type_cache = g_hash_table_new ((GHashFunc)mymono_metadata_type_hash, + type_cache = mono_g_hash_table_new ((GHashFunc)mymono_metadata_type_hash, (GCompareFunc)mymono_metadata_type_equal); - if ((res = g_hash_table_lookup (type_cache, type))) + if ((res = mono_g_hash_table_lookup (type_cache, type))) return res; if (klass->reflection_info) { /* should this be considered an error condition? */ @@ -1962,10 +2115,17 @@ mono_type_get_object (MonoDomain *domain, MonoType *type) mono_class_init (klass); res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class); res->type = type; - g_hash_table_insert (type_cache, type, res); + mono_g_hash_table_insert (type_cache, type, res); return res; } +/* + * mono_method_get_object: + * @domain: an app domain + * @method: a method + * + * Return an System.Reflection.MonoMethod object representing the method @method. + */ MonoReflectionMethod* mono_method_get_object (MonoDomain *domain, MonoMethod *method) { @@ -1973,7 +2133,7 @@ mono_method_get_object (MonoDomain *domain, MonoMethod *method) * We use the same C representation for methods and constructors, but the type * name in C# is different. */ - char *cname; + const char *cname; MonoClass *klass; MonoReflectionMethod *ret; @@ -1986,10 +2146,20 @@ mono_method_get_object (MonoDomain *domain, MonoMethod *method) ret = (MonoReflectionMethod*)mono_object_new (domain, klass); ret->method = method; + ret->name = mono_string_new (domain, method->name); CACHE_OBJECT (method, ret); return ret; } +/* + * mono_field_get_object: + * @domain: an app domain + * @klass: a type + * @field: a field + * + * Return an System.Reflection.MonoField object representing the field @field + * in class @klass. + */ MonoReflectionField* mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *field) { @@ -2005,6 +2175,15 @@ mono_field_get_object (MonoDomain *domain, MonoClass *klass, MonoClassField *fie return res; } +/* + * mono_property_get_object: + * @domain: an app domain + * @klass: a type + * @property: a property + * + * Return an System.Reflection.MonoProperty object representing the property @property + * in class @klass. + */ MonoReflectionProperty* mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *property) { @@ -2020,6 +2199,15 @@ mono_property_get_object (MonoDomain *domain, MonoClass *klass, MonoProperty *pr return res; } +/* + * mono_event_get_object: + * @domain: an app domain + * @klass: a type + * @event: a event + * + * Return an System.Reflection.MonoEvent object representing the event @event + * in class @klass. + */ MonoReflectionEvent* mono_event_get_object (MonoDomain *domain, MonoClass *klass, MonoEvent *event) { @@ -2035,6 +2223,14 @@ mono_event_get_object (MonoDomain *domain, MonoClass *klass, MonoEvent *event) return res; } +/* + * mono_param_get_objects: + * @domain: an app domain + * @method: a method + * + * Return an System.Reflection.ParameterInfo array object representing the parameters + * in the method @method. + */ MonoReflectionParameter** mono_param_get_objects (MonoDomain *domain, MonoMethod *method) { @@ -2056,7 +2252,11 @@ mono_param_get_objects (MonoDomain *domain, MonoMethod *method) */ CHECK_OBJECT (MonoReflectionParameter**, &(method->signature)); oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo"); +#if HAVE_BOEHM_GC + res = GC_malloc (sizeof (MonoReflectionParameter*) * method->signature->param_count); +#else res = g_new0 (MonoReflectionParameter*, method->signature->param_count); +#endif for (i = 0; i < method->signature->param_count; ++i) { res [i] = (MonoReflectionParameter *)mono_object_new (domain, oklass); res [i]->ClassImpl = mono_type_get_object (domain, method->signature->params [i]); @@ -2072,11 +2272,15 @@ mono_param_get_objects (MonoDomain *domain, MonoMethod *method) } /* + * mono_reflection_parse_type: + * @name: type name + * * Parse a type name as accepted by the GetType () method and output the info * extracted in the info structure. * the name param will be mangled, so, make a copy before passing it to this function. * The fields in info will be valid until the memory pointed to by name is valid. * Returns 0 on parse error. + * See also mono_type_get_name () below. */ int mono_reflection_parse_type (char *name, MonoTypeNameParse *info) { @@ -2102,7 +2306,7 @@ mono_reflection_parse_type (char *name, MonoTypeNameParse *info) { *last_point = 0; info->nest_name = last_point + 1; } else { - info->nest_name_space = ""; + info->nest_name_space = (char *)""; info->nest_name = start; } *p = 0; /* NULL terminate */ @@ -2134,7 +2338,7 @@ mono_reflection_parse_type (char *name, MonoTypeNameParse *info) { *last_point = 0; info->name = last_point + 1; } else { - info->name_space = ""; + info->name_space = (char *)""; info->name = start; } while (*p) { @@ -2192,6 +2396,73 @@ mono_reflection_parse_type (char *name, MonoTypeNameParse *info) { return 1; } +static void +mono_type_get_name_recurse (MonoType *type, GString *str) +{ + MonoClass *klass; + + switch (type->type) { + case MONO_TYPE_ARRAY: { + int i, rank = type->data.array->rank; + + mono_type_get_name_recurse (type->data.array->type, str); + g_string_append_c (str, '['); + for (i = 1; i < rank; i++) + g_string_append_c (str, ','); + g_string_append_c (str, ']'); + break; + } + case MONO_TYPE_SZARRAY: + mono_type_get_name_recurse (type->data.type, str); + g_string_append (str, "[]"); + break; + case MONO_TYPE_PTR: + mono_type_get_name_recurse (type->data.type, str); + g_string_append_c (str, '*'); + break; + default: + klass = mono_class_from_mono_type (type); + if (klass->nested_in) { + mono_type_get_name_recurse (&klass->nested_in->byval_arg, str); + g_string_append_c (str, '+'); + } + if (*klass->name_space) { + g_string_append (str, klass->name_space); + g_string_append_c (str, '.'); + } + g_string_append (str, klass->name); + break; + } +} + +/* + * mono_type_get_name: + * @type: a type + * + * Returns the string representation for type as required by System.Reflection. + * The inverse of mono_reflection_parse_type (). + */ +char* +mono_type_get_name (MonoType *type) +{ + GString* result = g_string_new (""); + mono_type_get_name_recurse (type, result); + + if (type->byref) + g_string_append_c (result, '&'); + + return g_string_free (result, FALSE); +} + +/* + * mono_reflection_get_type: + * @image: a metadata context + * @info: type description structure + * @ignorecase: flag for case-insensitive string compares + * + * Build a MonoType from the type description in @info. + * + */ MonoType* mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase) { @@ -2243,29 +2514,6 @@ mono_reflection_get_type (MonoImage* image, MonoTypeNameParse *info, gboolean ig return &klass->byval_arg; } -static MonoObject* -dummy_runtime_invoke (MonoMethod *method, void *obj, void **params) -{ - g_error ("runtime invoke called on uninitialized runtime"); - return NULL; -} - -MonoInvokeFunc mono_default_runtime_invoke = dummy_runtime_invoke; - -void -mono_install_runtime_invoke (MonoInvokeFunc func) { - if (func) - mono_default_runtime_invoke = func; - else - mono_default_runtime_invoke = dummy_runtime_invoke; -} - -MonoObject* -mono_runtime_invoke (MonoMethod *method, void *obj, void **params) -{ - return mono_default_runtime_invoke (method, obj, params);; -} - /* * Optimization we could avoid mallocing() an little-endian archs that * don't crash with unaligned accesses. @@ -2432,10 +2680,17 @@ find_event_index (MonoClass *klass, MonoEvent *event) { return 0; } +/* + * mono_reflection_get_custom_attrs: + * @obj: a reflection object handle + * + * Return an array with all the custom attributes defined of the + * reflection handle @obj. The objects are fully build. + */ MonoArray* mono_reflection_get_custom_attrs (MonoObject *obj) { - guint32 index, mtoken, i; + guint32 idx, mtoken, i, len; guint32 cols [MONO_CUSTOM_ATTR_SIZE]; MonoClass *klass; MonoImage *image; @@ -2451,39 +2706,39 @@ mono_reflection_get_custom_attrs (MonoObject *obj) if (klass == mono_defaults.monotype_class) { MonoReflectionType *rtype = (MonoReflectionType*)obj; klass = mono_class_from_mono_type (rtype->type); - index = mono_metadata_token_index (klass->type_token); - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_TYPEDEF; + idx = mono_metadata_token_index (klass->type_token); + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_TYPEDEF; image = klass->image; } else if (strcmp ("Assembly", klass->name) == 0) { MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj; - index = 1; /* there is only one assembly */ - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_ASSEMBLY; + idx = 1; /* there is only one assembly */ + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_ASSEMBLY; image = rassembly->assembly->image; } else if (strcmp ("MonoProperty", klass->name) == 0) { MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj; - index = find_property_index (rprop->klass, rprop->property); - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_PROPERTY; + idx = find_property_index (rprop->klass, rprop->property); + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_PROPERTY; image = rprop->klass->image; } else if (strcmp ("MonoEvent", klass->name) == 0) { MonoReflectionEvent *revent = (MonoReflectionEvent*)obj; - index = find_event_index (revent->klass, revent->event); - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_EVENT; + idx = find_event_index (revent->klass, revent->event); + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_EVENT; image = revent->klass->image; } else if (strcmp ("MonoField", klass->name) == 0) { MonoReflectionField *rfield = (MonoReflectionField*)obj; - index = find_field_index (rfield->klass, rfield->field); - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_FIELDDEF; + idx = find_field_index (rfield->klass, rfield->field); + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_FIELDDEF; image = rfield->klass->image; } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) { MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj; - index = find_method_index (rmethod->method); - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_METHODDEF; + idx = find_method_index (rmethod->method); + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_METHODDEF; image = method->klass->image; } else if (strcmp ("ParameterInfo", klass->name) == 0) { MonoReflectionParameter *param = (MonoReflectionParameter*)obj; @@ -2512,9 +2767,9 @@ mono_reflection_get_custom_attrs (MonoObject *obj) } if (!found) return mono_array_new (mono_domain_get (), mono_defaults.object_class, 0); - index = i; - index <<= CUSTOM_ATTR_BITS; - index |= CUSTOM_ATTR_PARAMDEF; + idx = i; + idx <<= CUSTOM_ATTR_BITS; + idx |= CUSTOM_ATTR_PARAMDEF; } else { /* handle other types here... */ g_error ("get custom attrs not yet supported for %s", klass->name); } @@ -2524,7 +2779,7 @@ mono_reflection_get_custom_attrs (MonoObject *obj) /* the table is not sorted */ for (i = 0; i < ca->rows; ++i) { mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE); - if (cols [MONO_CUSTOM_ATTR_PARENT] != index) + if (cols [MONO_CUSTOM_ATTR_PARENT] != idx) continue; mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> CUSTOM_ATTR_TYPE_BITS; switch (cols [MONO_CUSTOM_ATTR_TYPE] & CUSTOM_ATTR_TYPE_MASK) { @@ -2552,15 +2807,15 @@ mono_reflection_get_custom_attrs (MonoObject *obj) g_free (params); } - index = g_list_length (list); + len = g_list_length (list); /* * The return type is really object[], but System/Attribute.cs does a cast * to (Attribute []) and that is not allowed: I'm lazy for now, but we should * probably fix that. */ klass = mono_class_from_name (mono_defaults.corlib, "System", "Attribute"); - result = mono_array_new (mono_domain_get (), klass, index); - for (i = 0; i < index; ++i) { + result = mono_array_new (mono_domain_get (), klass, len); + for (i = 0; i < len; ++i) { mono_array_set (result, gpointer, i, list->data); list = list->next; } @@ -2569,8 +2824,21 @@ mono_reflection_get_custom_attrs (MonoObject *obj) return result; } +/* + * mono_reflection_get_custom_attrs_blob: + * @ctor: custom attribute constructor + * @ctorArgs: arguments o the constructor + * @properties: + * @propValues: + * @fields: + * @fieldValues: + * + * Creates the blob of data that needs to be saved in the metadata and that represents + * the custom attributed described by @ctor, @ctorArgs etc. + * Returns: a Byte array representing the blob of data. + */ MonoArray* -mono_reflection_get_custom_attrs_blob (MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *porpValues, MonoArray *fields, MonoArray* fieldValues) { +mono_reflection_get_custom_attrs_blob (MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues) { MonoArray *result; MonoMethodSignature *sig; MonoObject *arg; @@ -2678,6 +2946,14 @@ handle_enum: return result; } +/* + * mono_reflection_setup_internal_class: + * @tb: a TypeBuilder object + * + * Creates a MonoClass that represents the TypeBuilder. + * This is a trick that lets us simplify a lot of reflection code + * (and will allow us to support Build and Run assemblies easier). + */ void mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb) { @@ -2763,3 +3039,4 @@ mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig) return result; } +