#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 <stdio.h>
#include <glib.h>
#include <errno.h>
#include "rawbuffer.h"
#include "mono-endian.h"
#include "private.h"
+#if HAVE_BOEHM_GC
+#include <gc/gc.h>
+#endif
#define TEXT_OFFSET 512
#define CLI_H_SIZE 136
#define FILE_ALIGN 512
+#define START_TEXT_RVA 0x00002000
typedef struct {
MonoReflectionILGen *ilgen;
}
static guint32
-string_heap_insert (MonoStringHeap *sh, const char *str)
+string_heap_insert (MonoDynamicStream *sh, const char *str)
{
guint32 idx;
guint32 len;
}
static void
-string_heap_init (MonoStringHeap *sh)
+string_heap_init (MonoDynamicStream *sh)
{
sh->index = 0;
sh->alloc_size = 4096;
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) {
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);
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);
}
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;
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
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);
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);
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 ++;
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);
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;
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;
}
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];
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);
}
}
}
}
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;
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)
{
g_free (name);
values += MONO_PARAM_SIZE;
table->next_idx++;
+ mono_image_add_cattrs (assembly, pb->table_idx, CUSTOM_ATTR_PARAMDEF, pb->cattrs);
}
}
}
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
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);
}
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:
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);
}
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;
values [MONO_CONSTANT_TYPE] = field_type;
values [MONO_CONSTANT_PADDING] = 0;
}
+ if (fb->rva_data) {
+ guint32 rva_idx;
+ table = &assembly->tables [MONO_TABLE_FIELDRVA];
+ table->rows ++;
+ alloc_table (table, table->rows);
+ values = table->values + table->rows * MONO_FIELD_RVA_SIZE;
+ values [MONO_FIELD_RVA_FIELD] = fb->table_idx;
+ /*
+ * We store it in the code section because it's simpler for now.
+ */
+ 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
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);
*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);
*/
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);
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)
{
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);
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)
{
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:
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)
{
char *n;
table = &assembly->tables [MONO_TABLE_TYPEDEF];
- tb->table_idx = table->next_idx ++;
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);
values [MONO_TYPEDEF_METHOD_LIST] = assembly->tables [MONO_TABLE_METHOD].next_idx;
/*
- * FIXME: constructors and methods need to be output in the same order
- * as they are defined (according to table_idx).
+ * if we have explicitlayout or sequentiallayouts, output data in the
+ * ClassLayout table.
*/
+ if ((tb->attrs & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ table = &assembly->tables [MONO_TABLE_CLASSLAYOUT];
+ table->rows++;
+ alloc_table (table, table->rows);
+ values = table->values + table->rows * MONO_CLASS_LAYOUT_SIZE;
+ values [MONO_CLASS_LAYOUT_PARENT] = tb->table_idx;
+ values [MONO_CLASS_LAYOUT_CLASS_SIZE] = tb->class_size;
+ values [MONO_CLASS_LAYOUT_PACKING_SIZE] = tb->packing_size;
+ }
+
+ /* 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) {
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);
ntable->next_idx++;
}
}
+ mono_image_add_cattrs (assembly, tb->table_idx, CUSTOM_ATTR_TYPEDEF, tb->cattrs);
}
static void
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.
*/
table = &assembly->tables [MONO_TABLE_TYPEDEF];
table->rows += mono_array_length (mb->types);
alloc_table (table, table->rows);
+ /*
+ * We assign here the typedef indexes to avoid mismatches if a type that
+ * has not yet been stored in the tables is referenced by another type.
+ */
+ for (i = 0; i < mono_array_length (mb->types); ++i) {
+ int j;
+ MonoReflectionTypeBuilder *type = mono_array_get (mb->types, MonoReflectionTypeBuilder*, i);
+ type->table_idx = table->next_idx ++;
+ if (!type->subtypes)
+ continue;
+ for (j = 0; j < mono_array_length (type->subtypes); ++j) {
+ MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, j);
+ subtype->table_idx = table->next_idx ++;
+ }
+ }
for (i = 0; i < mono_array_length (mb->types); ++i)
mono_image_get_type_info (domain, mono_array_get (mb->types, MonoReflectionTypeBuilder*, i), assembly);
}
(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;
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;
*/
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.
*/
*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++){
}
}
}
- 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);
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)
{
char *name;
int i;
- assembly->text_rva = 0x00002000;
+ assembly->text_rva = START_TEXT_RVA;
table = &assembly->tables [MONO_TABLE_ASSEMBLY];
alloc_table (table, 1);
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; /* .<Module> */
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];
/*
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
* 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;
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;
}
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);
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)
{
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
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 = assembly->text_rva;
- section->st_raw_data_size = 1024; /* FIXME */
+ section->st_virtual_address = START_TEXT_RVA;
+ 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;
* 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)
}
/*
- * 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)
{
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;
+ if ((t1->type != t2->type) ||
+ (t1->byref != t2->byref))
+ return FALSE;
- /*
- * 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;
+ 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);
}
- CHECK_OBJECT (MonoReflectionType *, 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;
- CACHE_OBJECT (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)
{
* 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;
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)
{
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)
{
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)
{
return NULL;
member = mono_method_get_object (domain, method);
- names = g_new (char*, method->signature->param_count);
- mono_method_get_param_names (method, names);
+ names = g_new (char *, method->signature->param_count);
+ mono_method_get_param_names (method, (const char **) names);
/* Note: the cache is based on the address of the signature into the method
* since we already cache MethodInfos with the method as keys.
*/
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]);
}
/*
+ * 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;
*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 */
*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 != ']')
+ if (*p++ != ']')
return 0;
+ info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank));
break;
case ',':
*p++ = 0;
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;
+}
+