X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmetadata.c;h=7c67e451efa6c46ed9ed95b866175a866056ce5f;hb=f1d43d7b5c4973a6143fcc6e38bf54d387ad16f7;hp=ad88ae2c3dd4dcbc9ad2d13b47b10eebdec656d4;hpb=0e68f9afc3a43680985b7ccad8ea9675ca7d2e28;p=mono.git diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index ad88ae2c3dd..7c67e451efa 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -435,6 +435,12 @@ mono_tables_names [] = { #endif +/* Auxiliary structure used for caching inflated signatures */ +typedef struct { + MonoMethodSignature *sig; + MonoGenericContext context; +} MonoInflatedMethodSignature; + /** * mono_meta_table_name: * @table: table index @@ -1353,6 +1359,12 @@ static int next_generic_inst_id = 0; */ 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); /* @@ -1465,10 +1477,13 @@ mono_metadata_cleanup (void) 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; } /** @@ -1903,6 +1918,22 @@ mono_metadata_free_method_signature (MonoMethodSignature *sig) */ } +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) { @@ -1920,6 +1951,28 @@ inflated_method_hash (gconstpointer 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) { @@ -1945,59 +1998,80 @@ typedef struct { 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 @@ -2016,23 +2090,17 @@ inflated_method_in_image (gpointer key, gpointer value, gpointer data) 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) @@ -2051,6 +2119,8 @@ 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); @@ -2067,17 +2137,8 @@ free_inflated_method (MonoMethodInflated *imethod) 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; @@ -2112,7 +2173,8 @@ free_generic_class (MonoGenericClass *gclass) { 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 () */ @@ -2132,6 +2194,63 @@ free_generic_class (MonoGenericClass *gclass) 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: * @@ -4300,7 +4419,6 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec) type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec)); if (type2) { - g_free (type); mono_loader_unlock (); return type2; }