#endif
+/* Auxiliary structure used for caching inflated signatures */
+typedef struct {
+ MonoMethodSignature *sig;
+ MonoGenericContext context;
+} MonoInflatedMethodSignature;
+
/**
* mono_meta_table_name:
* @table: table index
*/
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);
/*
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;
}
/**
*/
}
+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)
{
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)
{
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 = (CleanForImageUserData*)data;
- MonoImage *image = user_data->image;
+ CleanForImageUserData *user_data = data;
MonoGenericInst *ginst = key;
- MonoClass *klass;
int i;
+
for (i = 0; i < ginst->type_argc; ++i) {
- MonoType *type = ginst->type_argv [i];
+ if (type_in_image (ginst->type_argv [i], user_data))
+ break;
+ }
- /* FIXME: Avoid a possible mono_class_inst inside mono_class_from_mono_type */
- if (type->type == MONO_TYPE_GENERICINST) {
- if (gclass_in_image (type->data.generic_class, NULL, data)) {
- if (!g_slist_find (user_data->ginst_list, ginst))
- user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
- return TRUE;
- }
- continue;
- }
+ if (i == ginst->type_argc)
+ return FALSE;
- klass = mono_class_from_mono_type (ginst->type_argv [i]);
- if (klass->image == image) {
- /*dump_ginst (ginst);
- g_print (" removed\n");*/
- if (!g_slist_find (user_data->ginst_list, ginst))
- user_data->ginst_list = g_slist_append (user_data->ginst_list, ginst);
- return TRUE;
- }
- }
- 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 = (CleanForImageUserData*)data;
- MonoImage *image = user_data->image;
+ CleanForImageUserData *user_data = data;
MonoGenericClass *gclass = key;
- gboolean match = FALSE;
- if (ginst_in_image (gclass->context.class_inst, NULL, data))
- match = TRUE;
- if (gclass->container_class->image == image)
- match = TRUE;
-
- if (match) {
- if (!g_slist_find (user_data->gclass_list, gclass))
- user_data->gclass_list = g_slist_append (user_data->gclass_list, gclass);
- return TRUE;
- } else {
+ 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
return FALSE;
}
-/*
- * LOCKING: assumes the loader lock is held.
- */
-MonoMethodInflated*
-mono_method_inflated_lookup (MonoMethodInflated* method, gboolean cache)
+static gboolean
+inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
{
- 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;
- }
-}
+ 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)
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);
int i;
MonoMethod *method = (MonoMethod*)imethod;
- if (method->signature) {
- MonoMethodSignature *sig = method->signature;
-
- /* Allocated in inflate_generic_signature () */
- mono_metadata_free_type (sig->ret);
- for (i = 0; i < sig->param_count; ++i)
- mono_metadata_free_type (sig->params [i]);
-
- /* FIXME: The signature is allocated from a mempool */
- //g_free (method->signature);
- }
+ 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;
{
int i;
- if (gclass->cached_class) {
+ /* 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 (gclass);
}
+static void
+free_inflated_signature (MonoInflatedMethodSignature *sig)
+{
+ mono_metadata_free_inflated_signature (sig->sig);
+ g_free (sig);
+}
+
+/*
+ * 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:
+ *
+ * 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:
*
type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
if (type2) {
- g_free (type);
mono_loader_unlock ();
return type2;
}