static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only);
static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
gboolean signature_only);
+static void free_generic_inst (MonoGenericInst *ginst);
+static void free_generic_class (MonoGenericClass *ginst);
+static void free_inflated_method (MonoMethodInflated *method);
/*
* This enumeration is used to describe the data types in the metadata
#endif
+/* Auxiliary structure used for caching inflated signatures */
+typedef struct {
+ MonoMethodSignature *sig;
+ MonoGenericContext context;
+} MonoInflatedMethodSignature;
+
/**
* mono_meta_table_name:
* @table: table index
return meta->heap_guid.data + index;
}
-static const char *
-dword_align (const char *ptr)
+static const unsigned char *
+dword_align (const unsigned char *ptr)
{
#if SIZEOF_VOID_P == 8
- return (const char *) (((guint64) (ptr + 3)) & ~3);
+ return (const unsigned char *) (((guint64) (ptr + 3)) & ~3);
#else
- return (const char *) (((guint32) (ptr + 3)) & ~3);
+ return (const unsigned char *) (((guint32) (ptr + 3)) & ~3);
#endif
}
ptr += 4;
}
if (rptr)
- *rptr = ptr;
+ *rptr = (char*)ptr;
return size;
}
ptr += 4;
}
if (rptr)
- *rptr = ptr;
+ *rptr = (char*)ptr;
return len;
}
}
/*
- * mono_metadata_parse_array:
+ * mono_metadata_parse_array_full:
* @m: a metadata context.
* @ptr: a pointer to an encoded array description.
* @rptr: pointer updated to match the end of the decoded stream
* Decodes the compressed array description found in the metadata @m at @ptr.
*
* Returns: a #MonoArrayType structure describing the array type
- * and dimensions.
+ * and dimensions. Memory is allocated from the image mempool.
+ *
+ * LOCKING: Assumes the loader lock is held.
*/
MonoArrayType *
mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
const char *ptr, const char **rptr)
{
int i;
- MonoArrayType *array = g_new0 (MonoArrayType, 1);
+ MonoArrayType *array = mono_mempool_alloc0 (m->mempool, sizeof (MonoArrayType));
MonoType *etype;
etype = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
static GHashTable *generic_class_cache = NULL;
static int next_generic_inst_id = 0;
+/*
+ * Protected by the loader lock.
+ * It has a MonoMethodInflated* as key and value.
+ * The key lookup will just access the declaring and context fields
+ */
+static GHashTable *generic_method_cache = NULL;
+
+/*
+ * Protected by the loader lock.
+ * It has a MonoInflatedMethodSignature* as key and value.
+ */
+static GHashTable *generic_signature_cache = NULL;
+
static guint mono_generic_class_hash (gconstpointer data);
/*
const MonoGenericInst *b = (const MonoGenericInst *) kb;
int i;
- if ((a->is_open != b->is_open) || (a->type_argc != b->type_argc) || (a->is_reference != b->is_reference))
+ if (a->is_open != b->is_open || a->type_argc != b->type_argc)
return FALSE;
for (i = 0; i < a->type_argc; ++i) {
if (!do_mono_metadata_type_equal (a->type_argv [i], b->type_argv [i], FALSE))
guint hash = mono_metadata_type_hash (&gclass->container_class->byval_arg);
hash *= 13;
- hash += mono_generic_inst_hash (gclass->inst);
+ hash += mono_metadata_generic_context_hash (&gclass->context);
return hash;
}
int i;
type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
- generic_inst_cache = g_hash_table_new (mono_generic_inst_hash, mono_generic_inst_equal);
- generic_class_cache = g_hash_table_new (mono_generic_class_hash, mono_generic_class_equal);
+ generic_inst_cache = g_hash_table_new_full (mono_generic_inst_hash, mono_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
+ generic_class_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
for (i = 0; i < NBUILTIN_TYPES (); ++i)
g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]);
g_hash_table_destroy (type_cache);
g_hash_table_destroy (generic_inst_cache);
g_hash_table_destroy (generic_class_cache);
+ if (generic_method_cache)
+ g_hash_table_destroy (generic_method_cache);
+ if (generic_signature_cache)
+ g_hash_table_destroy (generic_signature_cache);
+ type_cache = NULL;
+ generic_inst_cache = NULL;
+ generic_class_cache = NULL;
+ generic_method_cache = NULL;
+ generic_signature_cache = NULL;
}
/**
* this MonoGenericContainer.
* This is a Mono runtime internal function.
*
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Acquires the loader lock.
*
* Returns: a #MonoType structure representing the decoded type.
*/
int count = 0;
gboolean found;
+ mono_loader_lock ();
/*
* According to the spec, custom modifiers should come before the byref
* flag, but the IL produced by ilasm from the following signature:
type->pinned = pinned ? 1 : 0;
if (!do_mono_metadata_parse_type (type, m, container, ptr, &ptr)) {
- if (type != &stype)
- g_free (type);
+ mono_loader_unlock ();
return NULL;
}
if (rptr)
*rptr = ptr;
- if (!type->num_mods) {
+ if (!type->num_mods) {
/* no need to free type here, because it is on the stack */
if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
MonoType *ret = type->byref ? &type->data.klass->this_arg : &type->data.klass->byval_arg;
LOCKING: even though we don't explicitly hold a lock, in the problematic case 'ret' is a field
of a MonoClass which currently holds the loader lock. 'type' is local.
*/
- if (ret->data.klass == type->data.klass)
+ if (ret->data.klass == type->data.klass) {
+ mono_loader_unlock ();
return ret;
+ }
}
/* No need to use locking since nobody is modifying the hash table */
- if ((cached = g_hash_table_lookup (type_cache, type)))
+ if ((cached = g_hash_table_lookup (type_cache, type))) {
+ mono_loader_unlock ();
return cached;
+ }
}
/* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
type = mono_mempool_alloc (m->mempool, sizeof (MonoType));
memcpy (type, &stype, sizeof (MonoType));
}
+ mono_loader_unlock ();
return type;
}
const char *ptr;
if (image->dynamic)
- return mono_lookup_dynamic_token (image, token);
+ return mono_lookup_dynamic_token (image, token, NULL);
g_assert (mono_metadata_token_table(token) == MONO_TABLE_STANDALONESIG);
{
MonoMethodSignature *sig;
+ mono_loader_lock ();
sig = mono_mempool_alloc0 (m->mempool, sizeof (MonoMethodSignature) + ((gint32)nparams - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType*));
sig->param_count = nparams;
sig->sentinelpos = -1;
+ mono_loader_unlock ();
return sig;
}
*/
void
mono_metadata_free_method_signature (MonoMethodSignature *sig)
+{
+ /* Everything is allocated from mempools */
+ /*
+ int i;
+ if (sig->ret)
+ mono_metadata_free_type (sig->ret);
+ for (i = 0; i < sig->param_count; ++i) {
+ if (sig->params [i])
+ mono_metadata_free_type (sig->params [i]);
+ }
+ */
+}
+
+void
+mono_metadata_free_inflated_signature (MonoMethodSignature *sig)
{
int i;
+
+ /* Allocated in inflate_generic_signature () */
if (sig->ret)
mono_metadata_free_type (sig->ret);
for (i = 0; i < sig->param_count; ++i) {
if (sig->params [i])
mono_metadata_free_type (sig->params [i]);
}
+ /* FIXME: The signature is allocated from a mempool */
+ //g_free (sig);
+}
+
+static gboolean
+inflated_method_equal (gconstpointer a, gconstpointer b)
+{
+ const MonoMethodInflated *ma = a;
+ const MonoMethodInflated *mb = b;
+ if (ma->declaring != mb->declaring)
+ return FALSE;
+ return mono_metadata_generic_context_equal (&ma->context, &mb->context);
+}
+
+static guint
+inflated_method_hash (gconstpointer a)
+{
+ const MonoMethodInflated *ma = a;
+ return mono_metadata_generic_context_hash (&ma->context) ^ mono_aligned_addr_hash (ma->declaring);
+}
+
+static gboolean
+inflated_signature_equal (gconstpointer a, gconstpointer b)
+{
+ const MonoInflatedMethodSignature *sig1 = a;
+ const MonoInflatedMethodSignature *sig2 = b;
+
+ /* sig->sig is assumed to be canonized */
+ if (sig1->sig != sig2->sig)
+ return FALSE;
+ /* The generic instances are canonized */
+ return mono_metadata_generic_context_equal (&sig1->context, &sig2->context);
+}
+
+static guint
+inflated_signature_hash (gconstpointer a)
+{
+ const MonoInflatedMethodSignature *sig = a;
+
+ /* sig->sig is assumed to be canonized */
+ return mono_metadata_generic_context_hash (&sig->context) ^ mono_aligned_addr_hash (sig->sig);
+}
+
+/*static void
+dump_ginst (MonoGenericInst *ginst)
+{
+ int i;
+ char *name;
+
+ g_print ("Ginst: <");
+ for (i = 0; i < ginst->type_argc; ++i) {
+ if (i != 0)
+ g_print (", ");
+ name = mono_type_get_name (ginst->type_argv [i]);
+ g_print ("%s", name);
+ g_free (name);
+ }
+ g_print (">");
+}*/
+
+static gboolean gclass_in_image (gpointer key, gpointer value, gpointer data);
+
+typedef struct {
+ MonoImage *image;
+ GSList *ginst_list;
+ GSList *gclass_list;
+} CleanForImageUserData;
+
+static gboolean
+type_in_image (MonoType *type, CleanForImageUserData *user_data)
+{
+ MonoClass *klass;
+
+ /* Avoid allocations. We just want _some_ MonoClass reachable from @type. */
+retry:
+ switch (type->type) {
+ case MONO_TYPE_GENERICINST:
+ return gclass_in_image (type->data.generic_class, NULL, user_data);
+ case MONO_TYPE_PTR:
+ type = type->data.type;
+ goto retry;
+ case MONO_TYPE_SZARRAY:
+ klass = type->data.klass;
+ break;
+ case MONO_TYPE_ARRAY:
+ klass = type->data.array->eklass;
+ break;
+ case MONO_TYPE_FNPTR: {
+ gpointer iter = NULL;
+ MonoMethodSignature *sig = type->data.method;
+ MonoType *p;
+ if (type_in_image (mono_signature_get_return_type (sig), user_data))
+ return TRUE;
+ while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+ if (type_in_image (p, user_data))
+ return TRUE;
+ return FALSE;
+ }
+ default:
+ /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
+ klass = mono_class_from_mono_type (type);
+ break;
+ }
+
+ return klass->image == user_data->image;
+}
+
+static gboolean
+ginst_in_image (gpointer key, gpointer value, gpointer data)
+{
+ CleanForImageUserData *user_data = data;
+ MonoGenericInst *ginst = key;
+ int i;
+
+ for (i = 0; i < ginst->type_argc; ++i) {
+ if (type_in_image (ginst->type_argv [i], user_data))
+ break;
+ }
+
+ if (i == ginst->type_argc)
+ return FALSE;
+
+ if (!g_slist_find (user_data->ginst_list, ginst))
+ user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
+
+ return TRUE;
+}
+
+static gboolean
+gclass_in_image (gpointer key, gpointer value, gpointer data)
+{
+ CleanForImageUserData *user_data = data;
+ MonoGenericClass *gclass = key;
+
+ if (gclass->container_class->image != user_data->image &&
+ !ginst_in_image (gclass->context.class_inst, NULL, data))
+ return FALSE;
+
+ if (!g_slist_find (user_data->gclass_list, gclass))
+ user_data->gclass_list = g_slist_append (user_data->gclass_list, gclass);
+
+ return TRUE;
+}
+
+static gboolean
+inflated_method_in_image (gpointer key, gpointer value, gpointer data)
+{
+ CleanForImageUserData *user_data = (CleanForImageUserData*)data;
+ MonoImage *image = user_data->image;
+ MonoMethodInflated *method = key;
+
+ if (method->declaring->klass->image == image)
+ return TRUE;
+ if (method->context.class_inst && ginst_in_image (method->context.class_inst, NULL, data))
+ return TRUE;
+ if (method->context.method_inst && ginst_in_image (method->context.method_inst, NULL, data))
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoInflatedMethodSignature *sig = key;
+
+ if (sig->context.class_inst && ginst_in_image (sig->context.class_inst, NULL, data))
+ return TRUE;
+ if (sig->context.method_inst && ginst_in_image (sig->context.method_inst, NULL, data))
+ return TRUE;
+ return FALSE;
+}
+
+void
+mono_metadata_clean_for_image (MonoImage *image)
+{
+ CleanForImageUserData user_data;
+ GSList *l;
+
+ /* The data structures could reference each other so we delete them in two phases */
+ user_data.image = image;
+ user_data.ginst_list = NULL;
+ user_data.gclass_list = NULL;
+
+ mono_loader_lock ();
+ /* Collect the items to delete and remove them from the hash table */
+ g_hash_table_foreach_steal (generic_inst_cache, ginst_in_image, &user_data);
+ g_hash_table_foreach_steal (generic_class_cache, gclass_in_image, &user_data);
+ if (generic_method_cache)
+ g_hash_table_foreach_remove (generic_method_cache, inflated_method_in_image, &user_data);
+ if (generic_signature_cache)
+ g_hash_table_foreach_remove (generic_signature_cache, inflated_signature_in_image, &user_data);
+ /* Delete the removed items */
+ for (l = user_data.ginst_list; l; l = l->next)
+ free_generic_inst (l->data);
+ for (l = user_data.gclass_list; l; l = l->next)
+ free_generic_class (l->data);
+ g_slist_free (user_data.ginst_list);
+ g_slist_free (user_data.gclass_list);
+ mono_loader_unlock ();
+}
+
+static void
+free_inflated_method (MonoMethodInflated *imethod)
+{
+ int i;
+ MonoMethod *method = (MonoMethod*)imethod;
+
+ if (method->signature)
+ mono_metadata_free_inflated_signature (method->signature);
+
+ if (!((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))) {
+ MonoMethodNormal* mn = (MonoMethodNormal*) method;
+ MonoMethodHeader *header = mn->header;
+
+ if (header) {
+ /* Allocated in inflate_generic_header () */
+ for (i = 0; i < header->num_locals; ++i)
+ mono_metadata_free_type (header->locals [i]);
+ g_free (header->clauses);
+ g_free (header);
+ }
+ }
+
+ g_free (method);
+}
+
+static void
+free_generic_inst (MonoGenericInst *ginst)
+{
+ int i;
+
+ for (i = 0; i < ginst->type_argc; ++i)
+ mono_metadata_free_type (ginst->type_argv [i]);
+ g_free (ginst->type_argv);
+ g_free (ginst);
+}
+
+
+static void
+free_generic_class (MonoGenericClass *gclass)
+{
+ int i;
+
+ /* FIXME: The dynamic case */
+ if (gclass->cached_class && !gclass->cached_class->image->dynamic) {
+ MonoClass *class = gclass->cached_class;
+
+ /* Allocated in mono_class_init () */
+ g_free (class->methods);
+ g_free (class->properties);
+ /* Allocated in mono_class_setup_fields () */
+ if (class->fields) {
+ for (i = 0; i < class->field.count; ++i) {
+ g_free (class->fields [i].generic_info);
+ mono_metadata_free_type (class->fields [i].type);
+ }
+ }
+ /* Allocated in mono_generic_class_get_class () */
+ g_free (class->interfaces);
+ g_free (class);
+ }
+ g_free (gclass);
+}
+
+static void
+free_inflated_signature (MonoInflatedMethodSignature *sig)
+{
+ mono_metadata_free_inflated_signature (sig->sig);
+ g_free (sig);
}
/*
- * mono_metadata_lookup_generic_inst:
+ * LOCKING: assumes the loader lock is held.
+ */
+MonoMethodInflated*
+mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
+{
+ if (cache) {
+ if (!generic_method_cache)
+ generic_method_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
+ g_hash_table_insert (generic_method_cache, method, method);
+ return method;
+ } else {
+ if (generic_method_cache)
+ return g_hash_table_lookup (generic_method_cache, method);
+ return NULL;
+ }
+}
+
+/*
+ * mono_metadata_get_inflated_signature:
*
- * Check whether the newly created generic instantiation @ginst already exists
- * in the cache and return the cached value in this case. Otherwise insert
- * it into the cache.
+ * Given an inflated signature and a generic context, return a canonical copy of the
+ * signature. The returned signature might be equal to SIG or it might be a cached copy.
+ */
+MonoMethodSignature *
+mono_metadata_get_inflated_signature (MonoMethodSignature *sig, MonoGenericContext *context)
+{
+ MonoInflatedMethodSignature helper;
+ MonoInflatedMethodSignature *res;
+
+ mono_loader_lock ();
+ if (!generic_signature_cache)
+ generic_signature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
+
+ helper.sig = sig;
+ helper.context.class_inst = context->class_inst;
+ helper.context.method_inst = context->method_inst;
+ res = g_hash_table_lookup (generic_signature_cache, &helper);
+ if (!res) {
+ res = g_new0 (MonoInflatedMethodSignature, 1);
+ res->sig = sig;
+ res->context.class_inst = context->class_inst;
+ res->context.method_inst = context->method_inst;
+ g_hash_table_insert (generic_signature_cache, res, res);
+ }
+
+ mono_loader_unlock ();
+ return res->sig;
+}
+
+/*
+ * mono_metadata_get_generic_inst:
*
- * Use this method each time you create a new `MonoGenericInst' to ensure
- * proper caching. Only use the returned value as the argument passed to this
- * method may be freed.
+ * Given a list of types, return a MonoGenericInst that represents that list.
+ * The returned MonoGenericInst has its own copy of the list of types. The list
+ * passed in the argument can be freed, modified or disposed of.
*
*/
MonoGenericInst *
-mono_metadata_lookup_generic_inst (MonoGenericInst *ginst)
+mono_metadata_get_generic_inst (int type_argc, MonoType **type_argv)
{
- MonoGenericInst *cached;
+ MonoGenericInst *ginst;
+ MonoGenericInst helper;
int i;
- cached = g_hash_table_lookup (generic_inst_cache, ginst);
- if (cached) {
- for (i = 0; i < ginst->type_argc; i++)
- mono_metadata_free_type (ginst->type_argv [i]);
- g_free (ginst->type_argv);
- g_free (ginst);
- return cached;
+ helper.type_argc = type_argc;
+ helper.type_argv = type_argv;
+ helper.id = 0;
+
+ for (i = 0; i < type_argc; ++i)
+ if (mono_class_is_open_constructed_type (type_argv [i]))
+ break;
+ helper.is_open = (i < type_argc);
+
+ /*dump_ginst (&helper);*/
+ mono_loader_lock ();
+ ginst = g_hash_table_lookup (generic_inst_cache, &helper);
+ if (ginst) {
+ mono_loader_unlock ();
+ /*g_print (" found cached\n");*/
+ return ginst;
}
+ ginst = g_new0 (MonoGenericInst, 1);
+ ginst->type_argc = type_argc;
+ ginst->type_argv = g_new (MonoType*, type_argc);
ginst->id = ++next_generic_inst_id;
+ ginst->is_open = helper.is_open;
+
+ for (i = 0; i < type_argc; ++i)
+ ginst->type_argv [i] = mono_metadata_type_dup (NULL, type_argv [i]);
+
g_hash_table_insert (generic_inst_cache, ginst, ginst);
+ mono_loader_unlock ();
+ /*g_print (" inserted\n");*/
return ginst;
}
/*
* mono_metadata_lookup_generic_class:
*
- * Check whether the newly created generic class @gclass already exists
- * in the cache and return the cached value in this case. Otherwise insert
- * it into the cache and return NULL.
- *
- * Returns: the previosly cached generic class or NULL if it has been newly
- * inserted into the cache.
+ * Returns a MonoGenericClass with the given properties.
*
*/
MonoGenericClass *
-mono_metadata_lookup_generic_class (MonoGenericClass *gclass)
+mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst *inst, gboolean is_dynamic)
{
- MonoGenericClass *cached;
+ MonoGenericClass *gclass;
+
+ MonoGenericClass helper;
+ helper.container_class = container_class;
+ helper.context.class_inst = inst;
+ helper.context.method_inst = NULL;
+ helper.is_dynamic = is_dynamic; /* We use this in a hash lookup, which does not attempt to downcast the pointer */
+ helper.cached_class = NULL;
+
+ mono_loader_lock ();
+
+ gclass = g_hash_table_lookup (generic_class_cache, &helper);
+
+ /* A tripwire just to keep us honest */
+ g_assert (!helper.cached_class);
- cached = g_hash_table_lookup (generic_class_cache, gclass);
- if (cached)
- return cached;
+ if (gclass) {
+ mono_loader_unlock ();
+ return gclass;
+ }
+
+ if (is_dynamic) {
+ MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+ gclass = &dgclass->generic_class;
+ gclass->is_dynamic = 1;
+ } else {
+ gclass = g_new0 (MonoGenericClass, 1);
+ }
+
+ gclass->container_class = container_class;
+ gclass->context.class_inst = inst;
+ gclass->context.method_inst = NULL;
g_hash_table_insert (generic_class_cache, gclass, gclass);
- return NULL;
+
+ mono_loader_unlock ();
+
+ return gclass;
}
/*
MonoGenericInst *
mono_metadata_inflate_generic_inst (MonoGenericInst *ginst, MonoGenericContext *context)
{
+ MonoType **type_argv;
MonoGenericInst *nginst;
int i;
if (!ginst->is_open)
return ginst;
- nginst = g_new0 (MonoGenericInst, 1);
- nginst->type_argc = ginst->type_argc;
- nginst->type_argv = g_new0 (MonoType*, nginst->type_argc);
- nginst->is_reference = 1;
+ type_argv = g_new0 (MonoType*, ginst->type_argc);
- for (i = 0; i < nginst->type_argc; i++) {
- MonoType *t = mono_class_inflate_generic_type (ginst->type_argv [i], context);
+ for (i = 0; i < ginst->type_argc; i++)
+ type_argv [i] = mono_class_inflate_generic_type (ginst->type_argv [i], context);
- if (!nginst->is_open)
- nginst->is_open = mono_class_is_open_constructed_type (t);
- if (nginst->is_reference)
- nginst->is_reference = MONO_TYPE_IS_REFERENCE (t);
+ nginst = mono_metadata_get_generic_inst (ginst->type_argc, type_argv);
- nginst->type_argv [i] = t;
- }
+ for (i = 0; i < ginst->type_argc; i++)
+ mono_metadata_free_type (type_argv [i]);
+ g_free (type_argv);
- return mono_metadata_lookup_generic_inst (nginst);
+ return nginst;
}
MonoGenericInst *
mono_metadata_parse_generic_inst (MonoImage *m, MonoGenericContainer *container,
int count, const char *ptr, const char **rptr)
{
+ MonoType **type_argv;
MonoGenericInst *ginst;
int i;
- ginst = g_new0 (MonoGenericInst, 1);
- ginst->type_argc = count;
- ginst->type_argv = g_new0 (MonoType*, count);
- ginst->is_reference = 1;
+ type_argv = g_new0 (MonoType*, count);
- for (i = 0; i < ginst->type_argc; i++) {
+ for (i = 0; i < count; i++) {
MonoType *t = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
-
if (!t) {
- g_free (ginst->type_argv);
- g_free (ginst);
+ g_free (type_argv);
return NULL;
}
- ginst->type_argv [i] = t;
- if (!ginst->is_open)
- ginst->is_open = mono_class_is_open_constructed_type (t);
- if (ginst->is_reference)
- ginst->is_reference = MONO_TYPE_IS_REFERENCE (t);
+ type_argv [i] = t;
}
if (rptr)
*rptr = ptr;
- return mono_metadata_lookup_generic_inst (ginst);
+ ginst = mono_metadata_get_generic_inst (count, type_argv);
+
+ g_free (type_argv);
+
+ return ginst;
}
static gboolean
do_mono_metadata_parse_generic_class (MonoType *type, MonoImage *m, MonoGenericContainer *container,
const char *ptr, const char **rptr)
{
- MonoInflatedGenericClass *igclass;
- MonoGenericClass *gclass, *cached;
+ MonoGenericInst *inst;
MonoClass *gklass;
MonoType *gtype;
int count;
- igclass = g_new0 (MonoInflatedGenericClass, 1);
- gclass = &igclass->generic_class;
- gclass->is_inflated = TRUE;
-
- type->data.generic_class = gclass;
-
- gclass->context = g_new0 (MonoGenericContext, 1);
- gclass->context->gclass = gclass;
-
- /*
- * Create the klass before parsing the type arguments.
- * This is required to support "recursive" definitions.
- * See mcs/tests/gen-23.cs for an example.
- */
- igclass->klass = g_new0 (MonoClass, 1);
-
gtype = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
if (gtype == NULL)
return FALSE;
- gclass->container_class = gklass = mono_class_from_mono_type (gtype);
- g_assert (gklass->generic_container);
- gclass->context->container = gklass->generic_container;
+ gklass = mono_class_from_mono_type (gtype);
+ if (!gklass->generic_container)
+ return FALSE;
count = mono_metadata_decode_value (ptr, &ptr);
-
- gclass->inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr);
+ inst = mono_metadata_parse_generic_inst (m, container, count, ptr, &ptr);
+ if (inst == NULL)
+ return FALSE;
if (rptr)
*rptr = ptr;
- /* If we failed to parse, return, the error has been flagged. */
- if (gclass->inst == NULL)
- return FALSE;
-
- /*
- * We may be called multiple times on different metadata to create the same
- * instantiated type. This happens for instance if we're part of a method or
- * local variable signature.
- *
- * It's important to return the same MonoGenericClass * for each particualar
- * instantiation of a generic type (ie "Stack<Int32>") to make static fields
- * work.
- *
- * According to the spec ($26.1.5), a static variable in a generic class
- * declaration is shared amongst all instances of the same closed constructed
- * type.
- */
-
- cached = g_hash_table_lookup (generic_class_cache, gclass);
- if (cached) {
- g_free (igclass->klass);
- g_free (gclass);
-
- type->data.generic_class = cached;
- return TRUE;
- } else {
- g_hash_table_insert (generic_class_cache, gclass, gclass);
-
- mono_stats.generic_instance_count++;
- mono_stats.generics_metadata_size += sizeof (MonoGenericClass) +
- sizeof (MonoGenericContext) +
- gclass->inst->type_argc * sizeof (MonoType);
- }
+ type->data.generic_class = mono_metadata_lookup_generic_class (gklass, inst, FALSE);
return TRUE;
}
* @generic_container: Our MonoClass's or MonoMethodNormal's MonoGenericContainer;
* see mono_metadata_parse_type_full() for details.
* Internal routine to parse a generic type parameter.
+ * LOCKING: Assumes the loader lock is held.
*/
static MonoGenericParam *
mono_metadata_parse_generic_param (MonoImage *m, MonoGenericContainer *generic_container,
generic_container = select_container (generic_container, type);
if (!generic_container) {
/* Create dummy MonoGenericParam */
- MonoGenericParam *param = g_new0 (MonoGenericParam, 1);
- param->name = g_strdup_printf ("%d", index);
+ MonoGenericParam *param = mono_mempool_alloc0 (m->mempool, sizeof (MonoGenericParam));
+ param->name = mono_mempool_alloc0 (m->mempool, 8);
+ sprintf ((char*)param->name, "%d", index);
param->num = index;
return param;
if (!etype)
return FALSE;
type->data.klass = mono_class_from_mono_type (etype);
- mono_metadata_free_type (etype);
break;
}
case MONO_TYPE_PTR:
* mono_metadata_free_type:
* @type: type to free
*
- * Free the memory allocated for type @type which is assumed to be created by
- * mono_metadata_parse_type ().
+ * Free the memory allocated for type @type which is allocated on the heap.
*/
void
mono_metadata_free_type (MonoType *type)
break;
}
- /* Allocated from a mempool, no need to free it */
+ g_free (type);
}
#if 0
while (1) {
/* align on 32-bit boundary */
- /* FIXME: not 64-bit clean code */
sptr = ptr = dword_align (ptr);
sect_data_flags = *ptr;
ptr++;
g_return_val_if_fail (ptr != NULL, NULL);
+ mono_loader_lock ();
switch (format) {
case METHOD_HEADER_TINY_FORMAT:
mh = mono_mempool_alloc0 (m->mempool, sizeof (MonoMethodHeader));
mh->max_stack = 8;
local_var_sig_tok = 0;
mh->code_size = flags >> 2;
- mh->code = ptr;
+ mh->code = (unsigned char*)ptr;
+ mono_loader_unlock ();
return mh;
case METHOD_HEADER_TINY_FORMAT1:
mh = mono_mempool_alloc0 (m->mempool, sizeof (MonoMethodHeader));
* incorrect
*/
mh->code_size = flags >> 2;
- mh->code = ptr;
+ mh->code = (unsigned char*)ptr;
+ mono_loader_unlock ();
return mh;
case METHOD_HEADER_FAT_FORMAT:
fat_flags = read16 (ptr);
else
init_locals = 0;
- code = ptr;
+ code = (unsigned char*)ptr;
if (!(fat_flags & METHOD_HEADER_MORE_SECTS))
break;
/*
* There are more sections
*/
- ptr = code + code_size;
+ ptr = (char*)code + code_size;
break;
default:
+ mono_loader_unlock ();
return NULL;
}
mh->locals [i] = mono_metadata_parse_type_full (
m, container, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr);
if (!mh->locals [i]) {
+ mono_loader_unlock ();
return NULL;
}
}
mh->init_locals = init_locals;
if (fat_flags & METHOD_HEADER_MORE_SECTS)
parse_section_data (m, mh, (const unsigned char*)ptr);
+ mono_loader_unlock ();
return mh;
}
++pos;
}
+ mono_loader_lock ();
result = mono_mempool_alloc0 (meta->mempool, sizeof (MonoClass*) * (pos - start));
+ mono_loader_unlock ();
pos = start;
while (pos < tdef->rows) {
if (t->data.klass->enumtype)
return mono_type_size (t->data.klass->enum_basetype, align);
else
- return mono_class_value_size (t->data.klass, align);
+ return mono_class_value_size (t->data.klass, (guint32*)align);
}
case MONO_TYPE_CLASS:
case MONO_TYPE_SZARRAY:
*align = __alignof__(gpointer);
return sizeof (gpointer);
case MONO_TYPE_TYPEDBYREF:
- return mono_class_value_size (mono_defaults.typed_reference_class, align);
+ return mono_class_value_size (mono_defaults.typed_reference_class, (guint32*)align);
case MONO_TYPE_GENERICINST: {
- MonoInflatedGenericClass *gclass;
- MonoClass *container_class;
-
- gclass = mono_get_inflated_generic_class (t->data.generic_class);
- // g_assert (!gclass->generic_class.inst->is_open);
- // g_assert (!gclass->klass->generic_container);
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoClass *container_class = gclass->container_class;
- container_class = gclass->generic_class.container_class;
+ // g_assert (!gclass->inst->is_open);
if (container_class->valuetype) {
if (container_class->enumtype)
return mono_type_size (container_class->enum_basetype, align);
else
- return mono_class_value_size (gclass->klass, align);
+ return mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
} else {
*align = __alignof__(gpointer);
return sizeof (gpointer);
int
mono_type_stack_size (MonoType *t, int *align)
{
- guint32 tmp;
+ int tmp;
g_assert (t != NULL);
if (t->data.klass->enumtype)
return mono_type_stack_size (t->data.klass->enum_basetype, align);
else {
- size = mono_class_value_size (t->data.klass, align);
+ size = mono_class_value_size (t->data.klass, (guint32*)align);
*align = *align + __alignof__(gpointer) - 1;
*align &= ~(__alignof__(gpointer) - 1);
}
}
case MONO_TYPE_GENERICINST: {
- MonoInflatedGenericClass *gclass;
- MonoClass *container_class;
+ MonoGenericClass *gclass = t->data.generic_class;
+ MonoClass *container_class = gclass->container_class;
- gclass = mono_get_inflated_generic_class (t->data.generic_class);
- container_class = gclass->generic_class.container_class;
-
- g_assert (!gclass->generic_class.inst->is_open);
- g_assert (!gclass->klass->generic_container);
+ g_assert (!gclass->context.class_inst->is_open);
if (container_class->valuetype) {
if (container_class->enumtype)
return mono_type_stack_size (container_class->enum_basetype, align);
else {
- guint32 size = mono_class_value_size (gclass->klass, align);
+ guint32 size = mono_class_value_size (mono_class_from_mono_type (t), (guint32*)align);
*align = *align + __alignof__(gpointer) - 1;
*align &= ~(__alignof__(gpointer) - 1);
_mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2, gboolean signature_only)
{
int i;
+ MonoGenericInst *i1 = g1->context.class_inst;
+ MonoGenericInst *i2 = g2->context.class_inst;
- if ((g1->inst->type_argc != g2->inst->type_argc) || (g1->is_dynamic != g2->is_dynamic) ||
- (g1->inst->is_reference != g2->inst->is_reference))
+ if (i1->type_argc != i2->type_argc || g1->is_dynamic != g2->is_dynamic)
return FALSE;
if (!mono_metadata_class_equal (g1->container_class, g2->container_class, signature_only))
return FALSE;
- for (i = 0; i < g1->inst->type_argc; ++i) {
- if (!do_mono_metadata_type_equal (g1->inst->type_argv [i], g2->inst->type_argv [i], signature_only))
+ for (i = 0; i < i1->type_argc; ++i) {
+ if (!do_mono_metadata_type_equal (i1->type_argv [i], i2->type_argv [i], signature_only))
return FALSE;
}
return TRUE;
}
guint
-mono_metadata_generic_method_hash (MonoGenericMethod *gmethod)
-{
- return gmethod->inst->id;
+mono_metadata_generic_context_hash (const MonoGenericContext *context)
+{
+ /* FIXME: check if this seed is good enough */
+ guint hash = 0xc01dfee7;
+ if (context->class_inst)
+ hash = ((hash << 5) - hash) ^ context->class_inst->id;
+ if (context->method_inst)
+ hash = ((hash << 5) - hash) ^ context->method_inst->id;
+ return hash;
}
gboolean
-mono_metadata_generic_method_equal (MonoGenericMethod *g1, MonoGenericMethod *g2)
+mono_metadata_generic_context_equal (const MonoGenericContext *g1, const MonoGenericContext *g2)
{
- return (g1->container == g2->container) && (g1->generic_class == g2->generic_class) &&
- (g1->inst == g2->inst);
+ return g1->class_inst == g2->class_inst && g1->method_inst == g2->method_inst;
}
-
/*
* mono_metadata_type_hash:
* @t1: a type
if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
return FALSE;
+ if (sig1->generic_param_count != sig2->generic_param_count)
+ return FALSE;
+
/*
* We're just comparing the signatures of two methods here:
*
}
/**
- * mono_metadata_type_dup_mp:
- * @image: image type is defined in
+ * mono_metadata_type_dup:
+ * @mp: mempool to use
* @original: type to duplicate
*
- * Returns: copy of type allocated from mempool.
+ * Returns: copy of type allocated from mempool (or from the heap, if @mp is null).
*/
MonoType *
-mono_metadata_type_dup_mp (MonoImage *image, const MonoType *original)
+mono_metadata_type_dup (MonoMemPool *mp, const MonoType *o)
{
MonoType *r = NULL;
+ int sizeof_o = sizeof (MonoType);
+ if (o->num_mods)
+ sizeof_o += (o->num_mods - MONO_ZERO_LEN_ARRAY) * sizeof (MonoCustomMod);
+
mono_loader_lock ();
- r = mono_mempool_alloc0 (image->mempool, sizeof(MonoType));
+ r = mp ? mono_mempool_alloc0 (mp, sizeof_o) : g_malloc (sizeof_o);
mono_loader_unlock ();
- *r = *original;
- /* FIXME: we don't handle these yet because they need to duplicate memory
- * but the current routines used are not using the mempools
- */
- if (original->type == MONO_TYPE_PTR ||
- original->type == MONO_TYPE_ARRAY ||
- original->type == MONO_TYPE_FNPTR)
- g_assert_not_reached ();
+
+ memcpy (r, o, sizeof_o);
+
+ if (o->type == MONO_TYPE_PTR) {
+ r->data.type = mono_metadata_type_dup (mp, o->data.type);
+ } else if (o->type == MONO_TYPE_ARRAY) {
+ /* FIXME: should mono_dup_array_type() use mempools? */
+ g_assert (!mp);
+ r->data.array = mono_dup_array_type (o->data.array);
+ } else if (o->type == MONO_TYPE_FNPTR) {
+ /* FIXME: should mono_metadata_signature_deep_dup() use mempools? */
+ g_assert (!mp);
+ r->data.method = mono_metadata_signature_deep_dup (o->data.method);
+ }
return r;
}
guint32 cols [MONO_TYPESPEC_SIZE];
const char *ptr;
guint32 len;
- MonoType *type;
+ MonoType *type, *type2;
mono_loader_lock ();
ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
len = mono_metadata_decode_value (ptr, &ptr);
- type = g_new0 (MonoType, 1);
-
- g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+ type = mono_mempool_alloc0 (image->mempool, sizeof (MonoType));
if (*ptr == MONO_TYPE_BYREF) {
type->byref = 1;
}
if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) {
- g_hash_table_remove (image->typespec_cache, GUINT_TO_POINTER (type_spec));
g_free (type);
mono_loader_unlock ();
return NULL;
}
+ type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
+
+ if (type2) {
+ mono_loader_unlock ();
+ return type2;
+ }
+
+ g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+
mono_loader_unlock ();
return type;
}
g_free (spec);
}
-
+
+/**
+ * mono_type_to_unmanaged:
+ *
+ * Returns: A MonoMarshalNative enumeration value (MONO_NATIVE_) value
+ * describing the underlying native reprensetation of the type.
+ *
+ * In addition the value pointed by
+ * "conv" will contain the kind of marshalling required for this
+ * particular type one of the MONO_MARSHAL_CONV_ enumeration values.
+ */
guint32
mono_type_to_unmanaged (MonoType *type, MonoMarshalSpec *mspec, gboolean as_field,
gboolean unicode, MonoMarshalConv *conv)
g_error ("Can not marshal string to native type '%02x': Invalid managed/unmanaged type combination (String fields must be paired with LPStr, LPWStr, BStr or ByValTStr).", mspec->native);
}
}
- *conv = MONO_MARSHAL_CONV_STR_LPTSTR;
- return MONO_NATIVE_LPTSTR;
+ if (unicode) {
+ *conv = MONO_MARSHAL_CONV_STR_LPWSTR;
+ return MONO_NATIVE_LPWSTR;
+ }
+ else {
+ *conv = MONO_MARSHAL_CONV_STR_LPSTR;
+ return MONO_NATIVE_LPSTR;
+ }
case MONO_TYPE_PTR: return MONO_NATIVE_UINT;
case MONO_TYPE_VALUETYPE: /*FIXME*/
if (type->data.klass->enumtype) {
t = type->data.klass->enum_basetype->type;
goto handle_enum;
}
+ if (type->data.klass == mono_defaults.handleref_class){
+ *conv = MONO_MARSHAL_CONV_HANDLEREF;
+ return MONO_NATIVE_INT;
+ }
return MONO_NATIVE_STRUCT;
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
switch (mspec->native) {
case MONO_NATIVE_STRUCT:
return MONO_NATIVE_STRUCT;
+ case MONO_NATIVE_CUSTOM:
+ return MONO_NATIVE_CUSTOM;
case MONO_NATIVE_INTERFACE:
*conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE;
return MONO_NATIVE_INTERFACE;
*conv = MONO_MARSHAL_CONV_DEL_FTN;
return MONO_NATIVE_FUNC;
}
+ if (mono_defaults.safehandle_class && type->data.klass == mono_defaults.safehandle_class){
+ *conv = MONO_MARSHAL_CONV_SAFEHANDLE;
+ return MONO_NATIVE_INT;
+ }
*conv = MONO_MARSHAL_CONV_OBJECT_STRUCT;
return MONO_NATIVE_STRUCT;
}
GList *cons = NULL, *tmp;
MonoGenericContext *context = &container->context;
- /* FIXME: !container->klass => this is probably monodis */
- g_assert (!container->klass || context->gclass || context->gmethod);
-
*constraints = NULL;
found = 0;
for (i = 0; i < tdef->rows; ++i) {
*
* Returns: NULL if @token is not a generic type or method definition or the new generic container.
*
+ * LOCKING: Assumes the loader lock is held.
+ *
*/
MonoGenericContainer *
mono_metadata_load_generic_params (MonoImage *image, guint32 token, MonoGenericContainer *parent_container)
guint32 i, owner = 0, n;
MonoGenericContainer *container;
MonoGenericParam *params;
+ MonoGenericContext *context;
if (!(i = mono_metadata_get_generic_param_row (image, token, &owner)))
return NULL;
mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE);
params = NULL;
n = 0;
- container = g_new0 (MonoGenericContainer, 1);
+ container = mono_mempool_alloc0 (image->mempool, sizeof (MonoGenericContainer));
do {
n++;
params = g_realloc (params, sizeof (MonoGenericParam) * n);
params [n - 1].owner = container;
params [n - 1].pklass = NULL;
- params [n - 1].method = NULL;
params [n - 1].flags = cols [MONO_GENERICPARAM_FLAGS];
params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
params [n - 1].name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
} while (cols [MONO_GENERICPARAM_OWNER] == owner);
container->type_argc = n;
- container->type_params = params;
+ container->type_params = mono_mempool_alloc0 (image->mempool, sizeof (MonoGenericParam) * n);
+ memcpy (container->type_params, params, sizeof (MonoGenericParam) * n);
+ g_free (params);
container->parent = parent_container;
if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
container->is_method = 1;
- container->context.container = container;
+ g_assert (container->parent == NULL || container->is_method);
+
+ context = &container->context;
+ if (container->is_method) {
+ context->class_inst = container->parent ? container->parent->context.class_inst : NULL;
+ context->method_inst = mono_get_shared_generic_inst (container);
+ } else {
+ context->class_inst = mono_get_shared_generic_inst (container);
+ }
return container;
}
+MonoGenericInst *
+mono_get_shared_generic_inst (MonoGenericContainer *container)
+{
+ MonoType **type_argv;
+ MonoType *helper;
+ MonoGenericInst *nginst;
+ int i;
+
+ type_argv = g_new0 (MonoType *, container->type_argc);
+ helper = g_new0 (MonoType, container->type_argc);
+
+ for (i = 0; i < container->type_argc; i++) {
+ MonoType *t = &helper [i];
+
+ t->type = container->is_method ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
+ t->data.generic_param = &container->type_params [i];
+
+ type_argv [i] = t;
+ }
+
+ nginst = mono_metadata_get_generic_inst (container->type_argc, type_argv);
+
+ g_free (type_argv);
+ g_free (helper);
+
+ return nginst;
+}
+
gboolean
mono_type_is_byref (MonoType *type)
{