X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mono%2Fmetadata%2Freflection.c;h=e1b347a72dc8c5d3efe08746c94da6ee523cc428;hb=1d0ac15ee26bc43731acf7358ed0389793d47afa;hp=e9a0d3ad9b9aab1ef8e2662e62b172a6d6e77ff1;hpb=d37c178e86f876d36900ed00d0e49ff743bec4bc;p=mono.git diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index e9a0d3ad9b9..e1b347a72dc 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -12,6 +12,8 @@ #include "mono/metadata/reflection.h" #include "mono/metadata/tabledefs.h" #include "mono/metadata/tokentype.h" +#include "mono/metadata/appdomain.h" +#include "mono/metadata/opcodes.h" #include #include #include @@ -22,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 @@ -100,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; @@ -127,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; @@ -136,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) { @@ -205,6 +212,7 @@ encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endb case MONO_TYPE_TYPEDBYREF: mono_metadata_encode_value (type->type, p, &p); break; + case MONO_TYPE_PTR: case MONO_TYPE_SZARRAY: mono_metadata_encode_value (type->type, p, &p); encode_type (assembly, type->data.type, p, &p); @@ -214,6 +222,13 @@ encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endb mono_metadata_encode_value (type->type, p, &p); mono_metadata_encode_value (mono_image_typedef_or_ref (assembly, type), p, &p); break; + case MONO_TYPE_ARRAY: + mono_metadata_encode_value (type->type, p, &p); + encode_type (assembly, type->data.array->type, p, &p); + mono_metadata_encode_value (type->data.array->rank, p, &p); + mono_metadata_encode_value (0, p, &p); /* FIXME: set to 0 for now */ + mono_metadata_encode_value (0, p, &p); + break; default: g_error ("need to encode type %x", type->type); } @@ -223,9 +238,6 @@ encode_type (MonoDynamicAssembly *assembly, MonoType *type, char *p, char **endb static void encode_reflection_type (MonoDynamicAssembly *assembly, MonoReflectionType *type, char *p, char **endbuf) { - MonoReflectionTypeBuilder *tb; - guint32 token; - if (!type) { mono_metadata_encode_value (MONO_TYPE_VOID, p, endbuf); return; @@ -235,14 +247,8 @@ encode_reflection_type (MonoDynamicAssembly *assembly, MonoReflectionType *type, return; } - tb = (MonoReflectionTypeBuilder*) type; - token = TYPEDEFORREF_TYPEDEF | (tb->table_idx << TYPEDEFORREF_BITS); /* typedef */ + g_assert_not_reached (); - /* FIXME: handle other base types (need to have also some hacks to compile corlib) ... */ - /* FIXME: handle byref ... */ - mono_metadata_encode_value (MONO_TYPE_CLASS, p, &p); - mono_metadata_encode_value (token, p, endbuf); - /*g_print ("encoding type %s to 0x%08x\n", mono_string_to_utf8 (tb->name), token);*/ } static guint32 @@ -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); @@ -353,7 +363,6 @@ encode_locals (MonoDynamicAssembly *assembly, MonoReflectionILGen *ilgen) static guint32 method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb) { - /* we use only tiny formats now: need to implement ILGenerator */ char flags = 0; guint32 idx; guint32 code_size; @@ -409,6 +418,9 @@ method_encode_code (MonoDynamicAssembly *assembly, ReflectionMethodBuilder *mb) goto fat_header; } idx = mono_image_add_stream_data (&assembly->code, &flags, 1); + /* add to the fixup todo list */ + if (mb->ilgen && mb->ilgen->num_token_fixups) + 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; } @@ -431,6 +443,10 @@ fat_header: intp = (guint32*)(fat_header + 8); *intp = local_sig; 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) + 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) { unsigned char sheader [4]; @@ -452,20 +468,28 @@ fat_header: for (i = mono_array_length (mb->ilgen->ex_handlers) - 1; i >= 0; --i) { ex_info = (MonoILExceptionInfo *)mono_array_addr (mb->ilgen->ex_handlers, MonoILExceptionInfo, i); if (ex_info->handlers) { + int finally_start = 0; for (j = 0; j < mono_array_length (ex_info->handlers); ++j) { ex_block = (MonoILExceptionBlock*)mono_array_addr (ex_info->handlers, MonoILExceptionBlock, j); clause.flags = ex_block->type; clause.try_offset = ex_info->start; - clause.try_len = ex_info->len; + /* need fault, too, probably */ + if (clause.flags == MONO_EXCEPTION_CLAUSE_FINALLY) + clause.try_len = finally_start - ex_info->start; + else + clause.try_len = ex_info->len; clause.handler_offset = ex_block->start; clause.handler_len = ex_block->len; + finally_start = clause.handler_offset + clause.handler_len; clause.token_or_filter = ex_block->extype ? mono_metadata_token_from_dor ( mono_image_typedef_or_ref (assembly, ex_block->extype->type)): 0; + /*g_print ("out clause %d: from %d len=%d, handler at %d, %d\n", + clause.flags, clause.try_offset, clause.try_len, clause.handler_offset, clause.handler_len);*/ /* FIXME: ENOENDIAN */ 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); } } } @@ -473,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; @@ -485,12 +509,67 @@ 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; } +/* + * idx is the table index of the object + * type is one of CUSTOM_ATTR_* + */ +static void +mono_image_add_cattrs (MonoDynamicAssembly *assembly, guint32 idx, guint32 type, MonoArray *cattrs) +{ + MonoDynamicTable *table; + MonoReflectionCustomAttr *cattr; + guint32 *values; + guint32 count, i, token; + char blob_size [6]; + char *p = blob_size; + + /* it is legal to pass a NULL cattrs: we avoid to use the if in a lot of places */ + if (!cattrs) + return; + count = mono_array_length (cattrs); + table = &assembly->tables [MONO_TABLE_CUSTOMATTRIBUTE]; + table->rows += count; + alloc_table (table, table->rows); + values = table->values + table->next_idx * MONO_CUSTOM_ATTR_SIZE; + 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] = idx; + token = mono_image_create_token (assembly, (MonoObject*)cattr->ctor); + type = mono_metadata_token_index (token); + type <<= CUSTOM_ATTR_TYPE_BITS; + switch (mono_metadata_token_table (token)) { + case MONO_TABLE_METHOD: + type |= CUSTOM_ATTR_TYPE_METHODDEF; + break; + case MONO_TABLE_MEMBERREF: + type |= CUSTOM_ATTR_TYPE_MEMBERREF; + break; + default: + g_error ("got wrong token in custom attr"); + } + values [MONO_CUSTOM_ATTR_TYPE] = type; + p = blob_size; + mono_metadata_encode_value (mono_array_length (cattr->data), p, &p); + values [MONO_CUSTOM_ATTR_VALUE] = mono_image_add_stream_data (&assembly->blob, blob_size, p - blob_size); + mono_image_add_stream_data (&assembly->blob, + mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data)); + values += MONO_CUSTOM_ATTR_SIZE; + ++table->next_idx; + } +} + +/* + * 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) { @@ -537,6 +616,7 @@ mono_image_basic_method (ReflectionMethodBuilder *mb, MonoDynamicAssembly *assem g_free (name); values += MONO_PARAM_SIZE; table->next_idx++; + mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PARAMDEF, pb->cattrs); } } } @@ -601,6 +681,7 @@ mono_image_get_method_info (MonoReflectionMethodBuilder *mb, MonoDynamicAssembly values [MONO_MTHODIMPL_DECLARATION] = METHODDEFORREF_METHODDEF | (omb->table_idx << METHODDEFORREF_BITS); } } + mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_METHODDEF, mb->cattrs); } static void @@ -621,6 +702,7 @@ mono_image_get_ctor_info (MonoDomain *domain, MonoReflectionCtorBuilder *mb, Mon rmb.table_idx = &mb->table_idx; mono_image_basic_method (&rmb, assembly); + mono_image_add_cattrs (assembly, mb->table_idx, CUSTOM_ATTR_METHODDEF, mb->cattrs); } @@ -682,6 +764,7 @@ encode_constant (MonoDynamicAssembly *assembly, MonoObject *val, guint32 *ret_ty box_val = ((char*)val) + sizeof (MonoObject); *ret_type = val->vtable->klass->byval_arg.type; +handle_enum: switch (*ret_type) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_U1: @@ -703,7 +786,24 @@ encode_constant (MonoDynamicAssembly *assembly, MonoObject *val, guint32 *ret_ty case MONO_TYPE_R8: len = 8; break; - case MONO_TYPE_STRING: + case MONO_TYPE_VALUETYPE: + if (val->vtable->klass->enumtype) { + *ret_type = val->vtable->klass->enum_basetype->type; + goto handle_enum; + } else + g_error ("we can't encode valuetypes"); + 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); } @@ -725,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; @@ -766,6 +869,7 @@ mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicAssembly * rva_idx = mono_image_add_stream_data (&assembly->code, mono_array_addr (fb->rva_data, char, 0), mono_array_length (fb->rva_data)); values [MONO_FIELD_RVA_RVA] = rva_idx + assembly->text_rva + CLI_H_SIZE; } + mono_image_add_cattrs (assembly, fb->table_idx, CUSTOM_ATTR_FIELDDEF, fb->cattrs); } static guint32 @@ -776,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); @@ -794,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); @@ -819,7 +925,7 @@ mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAsse */ table = &assembly->tables [MONO_TABLE_PROPERTY]; pb->table_idx = table->next_idx ++; - values = table->values + pb->table_idx * MONO_FIELD_SIZE; + values = table->values + pb->table_idx * MONO_PROPERTY_SIZE; name = mono_string_to_utf8 (pb->name); values [MONO_PROPERTY_NAME] = string_heap_insert (&assembly->sheap, name); g_free (name); @@ -848,17 +954,147 @@ mono_image_get_property_info (MonoReflectionPropertyBuilder *pb, MonoDynamicAsse values [MONO_METHOD_SEMA_METHOD] = pb->set_method->table_idx; values [MONO_METHOD_SEMA_ASSOCIATION] = (pb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_PROPERTY; } + mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PROPERTY, pb->cattrs); +} + +static void +mono_image_get_event_info (MonoReflectionEventBuilder *eb, MonoDynamicAssembly *assembly) +{ + MonoDynamicTable *table; + guint32 *values; + char *name; + guint num_methods = 0; + guint32 semaidx; + + /* + * we need to set things in the following tables: + * EVENTMAP (info already filled in _get_type_info ()) + * EVENT (rows already preallocated in _get_type_info ()) + * METHOD (method info already done with the generic method code) + * METHODSEMANTICS + */ + table = &assembly->tables [MONO_TABLE_EVENT]; + eb->table_idx = table->next_idx ++; + values = table->values + eb->table_idx * MONO_EVENT_SIZE; + name = mono_string_to_utf8 (eb->name); + values [MONO_EVENT_NAME] = string_heap_insert (&assembly->sheap, name); + g_free (name); + values [MONO_EVENT_FLAGS] = eb->attrs; + values [MONO_EVENT_TYPE] = mono_image_typedef_or_ref (assembly, eb->type->type); + + /* + * FIXME: we still don't handle 'other' methods + */ + if (eb->add_method) num_methods ++; + if (eb->remove_method) num_methods ++; + if (eb->raise_method) num_methods ++; + + table = &assembly->tables [MONO_TABLE_METHODSEMANTICS]; + table->rows += num_methods; + alloc_table (table, table->rows); + + if (eb->add_method) { + semaidx = table->next_idx ++; + values = table->values + semaidx * MONO_METHOD_SEMA_SIZE; + values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_ADD_ON; + values [MONO_METHOD_SEMA_METHOD] = eb->add_method->table_idx; + values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT; + } + if (eb->remove_method) { + semaidx = table->next_idx ++; + values = table->values + semaidx * MONO_METHOD_SEMA_SIZE; + values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_REMOVE_ON; + values [MONO_METHOD_SEMA_METHOD] = eb->remove_method->table_idx; + values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT; + } + if (eb->raise_method) { + semaidx = table->next_idx ++; + values = table->values + semaidx * MONO_METHOD_SEMA_SIZE; + values [MONO_METHOD_SEMA_SEMANTICS] = METHOD_SEMANTIC_FIRE; + values [MONO_METHOD_SEMA_METHOD] = eb->raise_method->table_idx; + values [MONO_METHOD_SEMA_ASSOCIATION] = (eb->table_idx << HAS_SEMANTICS_BITS) | HAS_SEMANTICS_EVENT; + } + mono_image_add_cattrs (assembly, eb->table_idx, CUSTOM_ATTR_EVENT, eb->cattrs); } static guint32 resolution_scope_from_image (MonoDynamicAssembly *assembly, MonoImage *image) { - if (image != mono_defaults.corlib) - g_error ("multiple assemblyref not yet supported"); - /* first row in assemblyref */ - return (1 << RESOLTION_SCOPE_BITS) | RESOLTION_SCOPE_ASSEMBLYREF; + MonoDynamicTable *table; + guint32 token; + guint32 *values; + guint32 cols [MONO_ASSEMBLY_SIZE]; + + 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); + + table = &assembly->tables [MONO_TABLE_ASSEMBLYREF]; + token = table->next_idx ++; + table->rows ++; + alloc_table (table, table->rows); + values = table->values + token * MONO_ASSEMBLYREF_SIZE; + 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]; + values [MONO_ASSEMBLYREF_REV_NUMBER] = cols [MONO_ASSEMBLY_REV_NUMBER]; + values [MONO_ASSEMBLYREF_FLAGS] = 0; + values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0; + values [MONO_ASSEMBLYREF_CULTURE] = 0; + values [MONO_ASSEMBLYREF_HASH_VALUE] = 0; + + token <<= RESOLTION_SCOPE_BITS; + token |= RESOLTION_SCOPE_ASSEMBLYREF; + 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) { @@ -867,17 +1103,20 @@ mono_image_typedef_or_ref (MonoDynamicAssembly *assembly, MonoType *type) guint32 token; MonoClass *klass; - if (!assembly->typeref) - assembly->typeref = g_hash_table_new (g_direct_hash, g_direct_equal); - token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type)); if (token) return token; - klass = type->data.klass; + token = create_typespec (assembly, type); + if (token) + return token; + klass = mono_class_from_mono_type (type); /* * If it's in the same module: - * return TYPEDEFORREF_TYPEDEF | ((klass->token & 0xffffff) << TYPEDEFORREF_BITS) */ + if (klass->image == assembly->assembly.image) { + MonoReflectionTypeBuilder *tb = klass->reflection_info; + return TYPEDEFORREF_TYPEDEF | (tb->table_idx << TYPEDEFORREF_BITS); + } table = &assembly->tables [MONO_TABLE_TYPEREF]; alloc_table (table, table->rows + 1); @@ -891,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) { @@ -899,9 +1144,6 @@ mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoClass *klass, guint32 token, pclass; guint32 parent; - /* - * FIXME: we need to cache the token. - */ parent = mono_image_typedef_or_ref (assembly, &klass->byval_arg); switch (parent & TYPEDEFORREF_MASK) { case TYPEDEFORREF_TYPEREF: @@ -933,17 +1175,35 @@ mono_image_get_memberref_token (MonoDynamicAssembly *assembly, MonoClass *klass, static guint32 mono_image_get_methodref_token (MonoDynamicAssembly *assembly, MonoMethod *method) { - return mono_image_get_memberref_token (assembly, method->klass, + guint32 token; + + 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->handleref, method, GUINT_TO_POINTER(token)); + return token; } static guint32 mono_image_get_fieldref_token (MonoDynamicAssembly *assembly, MonoClassField *field, MonoClass *klass) { - return mono_image_get_memberref_token (assembly, klass, + guint32 token; + + 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->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) { @@ -956,12 +1216,7 @@ mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, Mon values = table->values + tb->table_idx * MONO_TYPEDEF_SIZE; values [MONO_TYPEDEF_FLAGS] = tb->attrs; if (tb->parent) { /* interfaces don't have a parent */ - if (tb->parent->type) - values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type); - else { - MonoReflectionTypeBuilder *ptb = (MonoReflectionTypeBuilder *)tb->parent; - values [MONO_TYPEDEF_EXTENDS] = TYPEDEFORREF_TYPEDEF | (ptb->table_idx << TYPEDEFORREF_BITS); - } + values [MONO_TYPEDEF_EXTENDS] = mono_image_typedef_or_ref (assembly, tb->parent->type); } else values [MONO_TYPEDEF_EXTENDS] = 0; n = mono_string_to_utf8 (tb->name); @@ -987,10 +1242,30 @@ mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, Mon values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size; } - /* - * FIXME: constructors and methods need to be output in the same order - * as they are defined (according to table_idx). - */ + /* handle interfaces */ + if (tb->interfaces) { + table = &assembly->tables [MONO_TABLE_INTERFACEIMPL]; + i = table->rows; + table->rows += mono_array_length (tb->interfaces); + alloc_table (table, table->rows); + values = table->values + (i + 1) * MONO_INTERFACEIMPL_SIZE; + for (i = 0; i < mono_array_length (tb->interfaces); ++i) { + MonoReflectionType* iface = (MonoReflectionType*) mono_array_get (tb->interfaces, gpointer, i); + values [MONO_INTERFACEIMPL_CLASS] = tb->table_idx; + values [MONO_INTERFACEIMPL_INTERFACE] = mono_image_typedef_or_ref (assembly, iface->type); + values += MONO_INTERFACEIMPL_SIZE; + } + } + + /* handle fields */ + if (tb->fields) { + table = &assembly->tables [MONO_TABLE_FIELD]; + table->rows += mono_array_length (tb->fields); + alloc_table (table, table->rows); + for (i = 0; i < mono_array_length (tb->fields); ++i) + mono_image_get_field_info ( + mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly); + } /* handle constructors */ if (tb->ctors) { @@ -1012,17 +1287,25 @@ mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, Mon mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i), assembly); } - /* handle fields */ - if (tb->fields) { - table = &assembly->tables [MONO_TABLE_FIELD]; - table->rows += mono_array_length (tb->fields); + /* Do the same with properties etc.. */ + /* + * FIXME: note that the methodsemantics table needs to be sorted, so events + * go before properties; not sure if this is enough... + */ + if (tb->events && mono_array_length (tb->events)) { + table = &assembly->tables [MONO_TABLE_EVENT]; + table->rows += mono_array_length (tb->events); alloc_table (table, table->rows); - for (i = 0; i < mono_array_length (tb->fields); ++i) - mono_image_get_field_info ( - mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i), assembly); + table = &assembly->tables [MONO_TABLE_EVENTMAP]; + table->rows ++; + alloc_table (table, table->rows); + values = table->values + table->rows * MONO_EVENT_MAP_SIZE; + values [MONO_EVENT_MAP_PARENT] = tb->table_idx; + values [MONO_EVENT_MAP_EVENTLIST] = assembly->tables [MONO_TABLE_EVENT].next_idx; + for (i = 0; i < mono_array_length (tb->events); ++i) + mono_image_get_event_info ( + mono_array_get (tb->events, MonoReflectionEventBuilder*, i), assembly); } - - /* Do the same with properties etc.. */ if (tb->properties && mono_array_length (tb->properties)) { table = &assembly->tables [MONO_TABLE_PROPERTY]; table->rows += mono_array_length (tb->properties); @@ -1063,6 +1346,7 @@ mono_image_get_type_info (MonoDomain *domain, MonoReflectionTypeBuilder *tb, Mon ntable->next_idx++; } } + mono_image_add_cattrs (assembly, tb->table_idx, CUSTOM_ATTR_TYPEDEF, tb->cattrs); } static void @@ -1077,8 +1361,14 @@ 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); /* * fill-in info in other tables as well. */ @@ -1111,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; @@ -1125,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; @@ -1181,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. */ @@ -1252,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++){ @@ -1293,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); @@ -1305,6 +1583,63 @@ 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); + MonoReflectionILTokenInfo *iltoken; + MonoReflectionFieldBuilder *field; + MonoReflectionCtorBuilder *ctor; + MonoReflectionMethodBuilder *method; + guint32 i, idx; + unsigned char *target; + + for (i = 0; i < ilgen->num_token_fixups; ++i) { + iltoken = (MonoReflectionILTokenInfo *)mono_array_addr_with_size (ilgen->token_fixups, sizeof (MonoReflectionILTokenInfo), i); + target = assembly->code.data + code_idx + iltoken->code_pos; + switch (target [3]) { + case MONO_TABLE_FIELD: + if (strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) + g_assert_not_reached (); + field = (MonoReflectionFieldBuilder *)iltoken->member; + idx = field->table_idx; + break; + case MONO_TABLE_METHOD: + if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) { + method = (MonoReflectionMethodBuilder *)iltoken->member; + idx = method->table_idx; + } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) { + ctor = (MonoReflectionCtorBuilder *)iltoken->member; + idx = ctor->table_idx; + } else { + g_assert_not_reached (); + } + break; + default: + g_error ("got unexpected table 0x%02x in fixup", target [3]); + } + 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) { @@ -1331,15 +1666,26 @@ 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); assembly->tables [MONO_TABLE_TYPEDEF].rows = 1; /* . */ assembly->tables [MONO_TABLE_TYPEDEF].next_idx++; - len = mono_array_length (assemblyb->modules); - table = &assembly->tables [MONO_TABLE_MODULE]; - alloc_table (table, len); - for (i = 0; i < len; ++i) - mono_image_fill_module_table (domain, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly); + if (assemblyb->modules) { + len = mono_array_length (assemblyb->modules); + table = &assembly->tables [MONO_TABLE_MODULE]; + alloc_table (table, len); + for (i = 0; i < len; ++i) + mono_image_fill_module_table (domain, mono_array_get (assemblyb->modules, MonoReflectionModuleBuilder*, i), assembly); + } else { + table = &assembly->tables [MONO_TABLE_MODULE]; + table->rows++; + alloc_table (table, table->rows); + table->values [table->next_idx * MONO_MODULE_SIZE + MONO_MODULE_NAME] = string_heap_insert (&assembly->sheap, "RefEmit_YouForgotToDefineAModule"); + table->next_idx ++; + } table = &assembly->tables [MONO_TABLE_TYPEDEF]; /* @@ -1357,43 +1703,43 @@ mono_image_build_metadata (MonoReflectionAssemblyBuilder *assemblyb) values [MONO_TYPEDEF_FIELD_LIST] = 1; values [MONO_TYPEDEF_METHOD_LIST] = 1; - /* later include all the assemblies referenced */ - table = &assembly->tables [MONO_TABLE_ASSEMBLYREF]; - alloc_table (table, 1); - values = table->values + table->columns; - values [MONO_ASSEMBLYREF_NAME] = string_heap_insert (&assembly->sheap, "corlib"); - values [MONO_ASSEMBLYREF_MAJOR_VERSION] = 0; - values [MONO_ASSEMBLYREF_MINOR_VERSION] = 0; - values [MONO_ASSEMBLYREF_BUILD_NUMBER] = 0; - values [MONO_ASSEMBLYREF_REV_NUMBER] = 0; - values [MONO_ASSEMBLYREF_FLAGS] = 0; - values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0; - values [MONO_ASSEMBLYREF_CULTURE] = 0; - values [MONO_ASSEMBLYREF_HASH_VALUE] = 0; - + /* fixup tokens */ + 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 @@ -1404,13 +1750,15 @@ mono_image_insert_string (MonoReflectionAssemblyBuilder *assembly, MonoString *s * TypeBuilder */ guint32 -mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *obj) +mono_image_create_token (MonoDynamicAssembly *assembly, MonoObject *obj) { - MonoClass *klass = obj->vtable->klass; + MonoClass *klass; guint32 token; - mono_image_basic_init (assembly); - + 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; @@ -1434,18 +1782,18 @@ mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *ob if (strcmp (klass->name, "MonoType") == 0) { MonoReflectionType *tb = (MonoReflectionType *)obj; return mono_metadata_token_from_dor ( - mono_image_typedef_or_ref (assembly->dynamic_assembly, tb->type)); + mono_image_typedef_or_ref (assembly, tb->type)); } if (strcmp (klass->name, "MonoCMethod") == 0 || strcmp (klass->name, "MonoMethod") == 0) { MonoReflectionMethod *m = (MonoReflectionMethod *)obj; - token = mono_image_get_methodref_token (assembly->dynamic_assembly, m->method); + token = mono_image_get_methodref_token (assembly, m->method); /*g_print ("got token 0x%08x for %s\n", token, m->method->name);*/ return token; } if (strcmp (klass->name, "MonoField") == 0) { MonoReflectionField *f = (MonoReflectionField *)obj; - token = mono_image_get_fieldref_token (assembly->dynamic_assembly, f->field, f->klass); + token = mono_image_get_fieldref_token (assembly, f->field, f->klass); /*g_print ("got token 0x%08x for %s\n", token, f->field->name);*/ return token; } @@ -1453,16 +1801,32 @@ mono_image_create_token (MonoReflectionAssemblyBuilder *assembly, MonoObject *ob 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) { MonoDynamicAssembly *assembly; + MonoImage *image; int i; 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 = 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); @@ -1472,9 +1836,34 @@ mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb) assembly->tables [i].next_idx = 1; assembly->tables [i].columns = table_sizes [i]; } + + image = g_new0 (MonoImage, 1); + + /* keep in sync with image.c */ + image->name = mono_string_to_utf8 (assemblyb->name); + image->assembly_name = image->name; /* they may be different */ + + image->method_cache = g_hash_table_new (g_direct_hash, g_direct_equal); + image->class_cache = g_hash_table_new (g_direct_hash, g_direct_equal); + image->name_cache = g_hash_table_new (g_str_hash, g_str_equal); + image->array_cache = g_hash_table_new (g_direct_hash, g_direct_equal); + + assembly->assembly.image = image; } +/* + * 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) { @@ -1538,12 +1927,14 @@ 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; header->nt.pe_heap_reserve = 0x00100000; header->nt.pe_heap_commit = 0x00001000; - header->nt.pe_loader_flags = 1; + header->nt.pe_loader_flags = 0; header->nt.pe_data_dir_count = 16; #if 0 @@ -1553,14 +1944,15 @@ 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 */ strcpy (section->st_name, ".text"); - section->st_virtual_size = 1024; /* FIXME */ section->st_virtual_address = START_TEXT_RVA; - section->st_raw_data_size = 1024; /* FIXME */ + section->st_virtual_size = assembly->meta_size + assembly->code.index; + section->st_raw_data_size = section->st_virtual_size + (FILE_ALIGN - 1); + section->st_raw_data_size &= ~(FILE_ALIGN - 1); section->st_raw_data_ptr = TEXT_OFFSET; section->st_flags = SECT_FLAGS_HAS_CODE | SECT_FLAGS_MEM_EXECUTE | SECT_FLAGS_MEM_READ; @@ -1576,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) @@ -1590,24 +1982,33 @@ mono_image_get_header (MonoReflectionAssemblyBuilder *assemblyb, char *buffer, i } /* - * We need to return always the same object for Type, MethodInfo, FieldInfo etc.. + * 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 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) { @@ -1624,41 +2025,115 @@ mono_assembly_get_object (MonoDomain *domain, MonoAssembly *assembly) return res; } -MonoReflectionType* -mono_type_get_object (MonoDomain *domain, MonoType *type) +static gboolean +mymono_metadata_type_equal (MonoType *t1, MonoType *t2) { - MonoReflectionType *res; - MonoClass *klass; - - /* - * FIXME: type may come from the cache in metadata.c, we hand out only - * the types from a MonoClass structure: the long term fix is to just - * load corlib always and remove the cache in metadata.c altogether. - * Or we may still handle it this way so we can store in MonoType additional info - * as we do now. - */ - klass = mono_class_from_mono_type (type); - if ((type != &klass->byval_arg) && (type != &klass->this_arg)) { - if (type->byref) - type = &klass->this_arg; - else - type = &klass->byval_arg; - } - CHECK_OBJECT (MonoReflectionType *, type); - res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class); - res->type = type; - CACHE_OBJECT (type, res); - return res; -} + if ((t1->type != t2->type) || + (t1->byref != t2->byref)) + return FALSE; -MonoReflectionMethod* + switch (t1->type) { + case MONO_TYPE_VOID: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_STRING: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_OBJECT: + return TRUE; + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_CLASS: + return t1->data.klass == t2->data.klass; + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + return mymono_metadata_type_equal (t1->data.type, t2->data.type); + case MONO_TYPE_ARRAY: + if (t1->data.array->rank != t2->data.array->rank) + return FALSE; + return mymono_metadata_type_equal (t1->data.array->type, t2->data.array->type); + default: + g_error ("implement type compare for %0x!", t1->type); + return FALSE; + } + + return FALSE; +} + +static guint +mymono_metadata_type_hash (MonoType *t1) +{ + guint hash; + + hash = t1->type; + + hash |= t1->byref << 6; /* do not collide with t1->type values */ + switch (t1->type) { + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_CLASS: + /* check if the distribution is good enough */ + return hash << 7 | g_str_hash (t1->data.klass->name); + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + return hash << 7 | mymono_metadata_type_hash (t1->data.type); + } + 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) +{ + MonoReflectionType *res; + MonoClass *klass = mono_class_from_mono_type (type); + + if (!type_cache) + type_cache = mono_g_hash_table_new ((GHashFunc)mymono_metadata_type_hash, + (GCompareFunc)mymono_metadata_type_equal); + if ((res = mono_g_hash_table_lookup (type_cache, type))) + return res; + if (klass->reflection_info) { + /* should this be considered an error condition? */ + if (!type->byref) + return klass->reflection_info; + } + mono_class_init (klass); + res = (MonoReflectionType *)mono_object_new (domain, mono_defaults.monotype_class); + res->type = type; + 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) { /* * 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; @@ -1671,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) { @@ -1690,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) { @@ -1705,6 +2199,38 @@ 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) +{ + MonoReflectionEvent *res; + MonoClass *oklass; + + CHECK_OBJECT (MonoReflectionEvent *, event); + oklass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "MonoEvent"); + res = (MonoReflectionEvent *)mono_object_new (domain, oklass); + res->klass = klass; + res->event = event; + CACHE_OBJECT (event, res); + 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) { @@ -1726,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]); @@ -1742,23 +2272,28 @@ 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) { char *start, *p, *w, *last_point; int in_modifiers = 0; + int isbyref = 0, rank; start = p = w = name; info->name = info->name_space = info->assembly = NULL; info->nest_name = info->nest_name_space = NULL; - info->rank = info->isbyref = info->ispointer = 0; + info->modifiers = NULL; last_point = NULL; @@ -1771,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 */ @@ -1803,32 +2338,37 @@ 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; } - /* FIXME: we don't mainatin an order for byref, pointer and array... */ while (*p) { switch (*p) { case '&': - info->isbyref = 1; + if (isbyref) /* only one level allowed by the spec */ + return 0; + isbyref = 1; + info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (0)); *p++ = 0; break; case '*': - info->ispointer = 1; + info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-1)); *p++ = 0; break; case '[': - info->rank = 1; + rank = 1; *p++ = 0; while (*p) { - if (*p == ',') - info->rank++; if (*p == ']') break; + if (*p == ',') + rank++; + else if (*p != '*') /* '*' means unknown lower bound */ + return 0; ++p; } if (*p++ != ']') return 0; + info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank)); break; case ',': *p++ = 0; @@ -1856,3 +2396,647 @@ 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) +{ + MonoClass *klass; + GList *mod; + int modval; + + if (ignorecase) { + g_warning ("Ignore case not yet supported in GetType()"); + return NULL; + } + + if (!image) + image = mono_defaults.corlib; + + if (info->nest_name) { + klass = mono_class_from_name (image, info->nest_name_space, info->nest_name); + if (klass) { + GList *nested; + mono_class_init (klass); + nested = klass->nested_classes; + klass = NULL; + while (nested) { + klass = nested->data; + if (strcmp (klass->name, info->nest_name) == 0 && + strcmp (klass->name_space, info->nest_name_space) == 0) + break; + klass = NULL; + nested = nested->next; + } + } + } else { + klass = mono_class_from_name (image, info->name_space, info->name); + } + if (!klass) + return NULL; + mono_class_init (klass); + for (mod = info->modifiers; mod; mod = mod->next) { + modval = GPOINTER_TO_UINT (mod->data); + if (!modval) { /* byref: must be last modifier */ + return &klass->this_arg; + } else if (modval == -1) { + klass = mono_ptr_class_get (&klass->byval_arg); + } else { /* array rank */ + klass = mono_array_class_get (&klass->byval_arg, modval); + } + mono_class_init (klass); + } + return &klass->byval_arg; +} + +/* + * Optimization we could avoid mallocing() an little-endian archs that + * don't crash with unaligned accesses. + */ +static void +fill_param_data (MonoImage *image, MonoMethodSignature *sig, guint32 blobidx, void **params) { + int len, i, slen, type; + const char *p = mono_metadata_blob_heap (image, blobidx); + + len = mono_metadata_decode_value (p, &p); + if (len < 2 || read16 (p) != 0x0001) /* Prolog */ + return; + + /* skip prolog */ + p += 2; + for (i = 0; i < sig->param_count; ++i) { + type = sig->params [i]->type; +handle_enum: + switch (type) { + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: { + MonoBoolean *bval = params [i] = g_malloc (sizeof (MonoBoolean)); + *bval = *p; + ++p; + break; + } + case MONO_TYPE_CHAR: + case MONO_TYPE_U2: + case MONO_TYPE_I2: { + guint16 *val = params [i] = g_malloc (sizeof (guint16)); + *val = read16 (p); + p += 2; + break; + } +#if SIZEOF_VOID_P == 4 + case MONO_TYPE_U: + case MONO_TYPE_I: +#endif + case MONO_TYPE_R4: + case MONO_TYPE_U4: + case MONO_TYPE_I4: { + guint32 *val = params [i] = g_malloc (sizeof (guint32)); + *val = read32 (p); + p += 4; + break; + } +#if SIZEOF_VOID_P == 8 + case MONO_TYPE_U: /* error out instead? this should probably not happen */ + case MONO_TYPE_I: +#endif + case MONO_TYPE_R8: + case MONO_TYPE_U8: + case MONO_TYPE_I8: { + guint64 *val = params [i] = g_malloc (sizeof (guint64)); + *val = read64 (p); + p += 8; + break; + } + case MONO_TYPE_VALUETYPE: + if (sig->params [i]->data.klass->enumtype) { + type = sig->params [i]->data.klass->enum_basetype->type; + goto handle_enum; + } else { + g_warning ("generic valutype %s not handled in custom attr value decoding", sig->params [i]->data.klass->name); + } + break; + case MONO_TYPE_STRING: { + slen = mono_metadata_decode_value (p, &p); + params [i] = mono_string_new_len (mono_domain_get (), p, slen); + p += slen; + break; + } + default: + g_warning ("Type %02x not handled in custom attr value decoding", sig->params [i]->type); + break; + } + } +} + +static void +free_param_data (MonoMethodSignature *sig, void **params) { + int i; + for (i = 0; i < sig->param_count; ++i) { + switch (sig->params [i]->type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_U: + case MONO_TYPE_I: + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_U2: + case MONO_TYPE_I2: + case MONO_TYPE_U4: + case MONO_TYPE_I4: + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_R8: + case MONO_TYPE_R4: + case MONO_TYPE_VALUETYPE: + g_free (params [i]); + break; + default: + break; + } + } +} + +/* + * Find the method index in the metadata methodDef table. + * Later put these three helper methods in metadata and export them. + */ +static guint32 +find_method_index (MonoMethod *method) { + MonoClass *klass = method->klass; + int i; + + for (i = 0; i < klass->method.count; ++i) { + if (method == klass->methods [i]) + return klass->method.first + 1 + i; + } + return 0; +} + +/* + * Find the field index in the metadata FieldDef table. + */ +static guint32 +find_field_index (MonoClass *klass, MonoClassField *field) { + int i; + + for (i = 0; i < klass->field.count; ++i) { + if (field == &klass->fields [i]) + return klass->field.first + 1 + i; + } + return 0; +} + +/* + * Find the property index in the metadata Property table. + */ +static guint32 +find_property_index (MonoClass *klass, MonoProperty *property) { + int i; + + for (i = 0; i < klass->property.count; ++i) { + if (property == &klass->properties [i]) + return klass->property.first + 1 + i; + } + return 0; +} + +/* + * Find the event index in the metadata Event table. + */ +static guint32 +find_event_index (MonoClass *klass, MonoEvent *event) { + int i; + + for (i = 0; i < klass->event.count; ++i) { + if (event == &klass->events [i]) + return klass->event.first + 1 + i; + } + 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 idx, mtoken, i, len; + guint32 cols [MONO_CUSTOM_ATTR_SIZE]; + MonoClass *klass; + MonoImage *image; + MonoTableInfo *ca; + MonoMethod *method; + MonoObject *attr; + MonoArray *result; + GList *list = NULL; + void **params; + + klass = obj->vtable->klass; + /* FIXME: need to handle: Module */ + if (klass == mono_defaults.monotype_class) { + MonoReflectionType *rtype = (MonoReflectionType*)obj; + klass = mono_class_from_mono_type (rtype->type); + 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; + 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; + 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; + 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; + 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; + 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; + MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl; + guint32 method_index = find_method_index (rmethod->method); + guint32 param_list, param_last, param_pos, found; + + image = rmethod->method->klass->image; + ca = &image->tables [MONO_TABLE_METHOD]; + + param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST); + if (method_index == ca->rows) { + ca = &image->tables [MONO_TABLE_PARAM]; + param_last = ca->rows + 1; + } else { + param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST); + ca = &image->tables [MONO_TABLE_PARAM]; + } + found = 0; + for (i = param_list; i < param_last; ++i) { + param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE); + if (param_pos == param->PositionImpl) { + found = 1; + break; + } + } + if (!found) + return mono_array_new (mono_domain_get (), mono_defaults.object_class, 0); + 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); + } + + /* at this point image and index are set correctly for searching the custom attr */ + ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE]; + /* 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] != idx) + continue; + mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> CUSTOM_ATTR_TYPE_BITS; + switch (cols [MONO_CUSTOM_ATTR_TYPE] & CUSTOM_ATTR_TYPE_MASK) { + case CUSTOM_ATTR_TYPE_METHODDEF: + mtoken |= MONO_TOKEN_METHOD_DEF; + break; + case CUSTOM_ATTR_TYPE_MEMBERREF: + mtoken |= MONO_TOKEN_MEMBER_REF; + break; + default: + g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]); + break; + } + method = mono_get_method (image, mtoken, NULL); + if (!method) + g_error ("Can't find custom attr constructor"); + mono_class_init (method->klass); + /*g_print ("got attr %s\n", method->klass->name);*/ + params = g_new (void*, method->signature->param_count); + fill_param_data (image, method->signature, cols [MONO_CUSTOM_ATTR_VALUE], params); + attr = mono_object_new (mono_domain_get (), method->klass); + mono_runtime_invoke (method, attr, params); + list = g_list_prepend (list, attr); + free_param_data (method->signature, params); + g_free (params); + } + + 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, len); + for (i = 0; i < len; ++i) { + mono_array_set (result, gpointer, i, list->data); + list = list->next; + } + g_list_free (g_list_first (list)); + + 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 *propValues, MonoArray *fields, MonoArray* fieldValues) { + MonoArray *result; + MonoMethodSignature *sig; + MonoObject *arg; + char *buffer, *p, *argval; + guint32 buflen, i, type; + + if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) { + g_warning ("ConstructorBuilder Custom attribute not yet supported"); + /* + * maybe we should have a param array to method signature function and + * continue with the normal codepath. + */ + result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, 4); + mono_array_set (result, char, 0, 1); + return result; + } + buflen = 256; + p = buffer = g_malloc (buflen); + /* write the prolog */ + *p++ = 1; + *p++ = 0; + sig = ((MonoReflectionMethod*)ctor)->method->signature; + /* FIXME: ENOENDIAN */ + for (i = 0; i < sig->param_count; ++i) { + if ((p-buffer) + 10 >= buflen) { + char *newbuf; + buflen *= 2; + newbuf = g_realloc (buffer, buflen); + p = newbuf + (p-buffer); + buffer = newbuf; + } + arg = (MonoObject*)mono_array_get (ctorArgs, gpointer, i); + argval = ((char*)arg + sizeof (MonoObject)); + type = sig->params [i]->type; +handle_enum: + switch (type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_U1: + case MONO_TYPE_I1: + *p++ = *argval; + break; + case MONO_TYPE_CHAR: + case MONO_TYPE_U2: + case MONO_TYPE_I2: { + guint16 *val = (guint16*)p; + *val = *(guint16*)argval; + p += 2; + break; + } + case MONO_TYPE_U4: + case MONO_TYPE_I4: + case MONO_TYPE_R4: { + guint32 *val = (guint32*)p; + *val = *(guint32*)argval; + p += 4; + break; + } + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_R8: { + guint64 *val = (guint64*)p; + *val = *(guint64*)argval; + p += 8; + break; + } + case MONO_TYPE_VALUETYPE: + if (sig->params [i]->data.klass->enumtype) { + type = sig->params [i]->data.klass->enum_basetype->type; + goto handle_enum; + } else { + g_warning ("generic valutype %s not handled in custom attr value decoding", sig->params [i]->data.klass->name); + } + break; + case MONO_TYPE_STRING: { + char *str = mono_string_to_utf8 ((MonoString*)arg); + guint32 slen = strlen (str); + if ((p-buffer) + 10 + slen >= buflen) { + char *newbuf; + buflen *= 2; + buflen += slen; + newbuf = g_realloc (buffer, buflen); + p = newbuf + (p-buffer); + buffer = newbuf; + } + mono_metadata_encode_value (slen, p, &p); + memcpy (p, str, slen); + p += slen; + g_free (str); + break; + } + default: + g_error ("type 0x%02x not yet supported in custom attr encoder", type); + } + } + /* + * we don't support properties and fields, yet, set to 0. + */ + *p++ = 0; + *p++ = 0; + buflen = p - buffer; + result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen); + p = mono_array_addr (result, char, 0); + memcpy (p, buffer, buflen); + g_free (buffer); + 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) +{ + MonoClass *klass, *parent; + + klass = g_new0 (MonoClass, 1); + + klass->image = tb->module->assemblyb->dynamic_assembly->assembly.image; + + if (tb->parent) + parent = mono_class_from_mono_type (tb->parent->type); + + klass->inited = 1; /* we lie to the runtime */ + klass->name = mono_string_to_utf8 (tb->name); + klass->name_space = mono_string_to_utf8 (tb->nspace); + klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx; + klass->flags = tb->attrs; + + klass->element_class = klass; + klass->reflection_info = tb; /* need to pin. */ + + mono_class_setup_parent (klass, parent); + mono_class_setup_mono_type (klass); + + /* + * FIXME: handle interfaces. + */ + + tb->type.type = &klass->byval_arg; + + /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/ +} + +MonoArray * +mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig) +{ + MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly; + guint32 na = mono_array_length (sig->arguments); + guint32 buflen, i; + MonoArray *result; + char *buf, *p; + + p = buf = g_malloc (10 + na * 10); + + mono_metadata_encode_value (0x07, p, &p); + mono_metadata_encode_value (na, p, &p); + for (i = 0; i < na; ++i) { + MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i); + encode_reflection_type (assembly, type, p, &p); + } + + buflen = p - buf; + result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen); + p = mono_array_addr (result, char, 0); + memcpy (p, buf, buflen); + g_free (buf); + + return result; +} + +MonoArray * +mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig) +{ + MonoDynamicAssembly *assembly = sig->module->assemblyb->dynamic_assembly; + guint32 na = mono_array_length (sig->arguments); + guint32 buflen, i; + MonoArray *result; + char *buf, *p; + + p = buf = g_malloc (10 + na * 10); + + mono_metadata_encode_value (0x06, p, &p); + for (i = 0; i < na; ++i) { + MonoReflectionType *type = mono_array_get (sig->arguments, MonoReflectionType *, i); + encode_reflection_type (assembly, type, p, &p); + } + + buflen = p - buf; + result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen); + p = mono_array_addr (result, char, 0); + memcpy (p, buf, buflen); + g_free (buf); + + return result; +} +