+ * mono_metadata_free_method_signature:
+ * @sig: signature to destroy
+ *
+ * Free the memory allocated in the signature @sig.
+ * This method needs to be robust and work also on partially-built
+ * signatures, so it does extra checks.
+ */
+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]);
+ }
+ 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;
+ if (ma->is_mb_open != mb->is_mb_open)
+ 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)) + ma->is_mb_open;
+}
+
+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 type_in_image (MonoType *type, MonoImage *image);
+
+static gboolean
+signature_in_image (MonoMethodSignature *sig, MonoImage *image)
+{
+ gpointer iter = NULL;
+ MonoType *p;
+
+ while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+ if (type_in_image (p, image))
+ return TRUE;
+
+ return type_in_image (mono_signature_get_return_type (sig), image);
+}
+
+static gboolean
+ginst_in_image (MonoGenericInst *ginst, MonoImage *image)
+{
+ int i;
+
+ for (i = 0; i < ginst->type_argc; ++i) {
+ if (type_in_image (ginst->type_argv [i], image))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gclass_in_image (MonoGenericClass *gclass, MonoImage *image)
+{
+ return gclass->container_class->image == image ||
+ ginst_in_image (gclass->context.class_inst, image);
+}
+
+static gboolean
+type_in_image (MonoType *type, MonoImage *image)
+{
+retry:
+ switch (type->type) {
+ case MONO_TYPE_GENERICINST:
+ return gclass_in_image (type->data.generic_class, image);
+ case MONO_TYPE_PTR:
+ type = type->data.type;
+ goto retry;
+ case MONO_TYPE_SZARRAY:
+ type = &type->data.klass->byval_arg;
+ goto retry;
+ case MONO_TYPE_ARRAY:
+ type = &type->data.array->eklass->byval_arg;
+ goto retry;
+ case MONO_TYPE_FNPTR:
+ return signature_in_image (type->data.method, image);
+ case MONO_TYPE_VAR:
+ if (type->data.generic_param->owner) {
+ g_assert (!type->data.generic_param->owner->is_method);
+ /*
+ * FIXME: The following check is here solely
+ * for monodis, which uses the internal
+ * function
+ * mono_metadata_load_generic_params(). The
+ * caller of that function needs to fill in
+ * owner->klass or owner->method of the
+ * returned struct, but monodis doesn't do
+ * that. The image unloading depends on that,
+ * however, so a crash results without this
+ * check.
+ */
+ if (!type->data.generic_param->owner->owner.klass)
+ return FALSE;
+ return type->data.generic_param->owner->owner.klass->image == image;
+ } else {
+ return type->data.generic_param->image == image;
+ }
+ case MONO_TYPE_MVAR:
+ if (type->data.generic_param->owner) {
+ g_assert (type->data.generic_param->owner->is_method);
+ if (!type->data.generic_param->owner->owner.method)
+ /* RefEmit created generic param whose method is not finished */
+ return FALSE;
+ return type->data.generic_param->owner->owner.method->klass->image == image;
+ } else {
+ return type->data.generic_param->image == image;
+ }
+ default:
+ /* At this point, we should've avoided all potential allocations in mono_class_from_mono_type () */
+ return image == mono_class_from_mono_type (type)->image;
+ }
+}
+
+typedef struct {
+ MonoImage *image;
+ GSList *list;
+} CleanForImageUserData;
+
+static gboolean
+steal_gclass_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoGenericClass *gclass = key;
+ CleanForImageUserData *user_data = data;
+
+ if (!gclass_in_image (gclass, user_data->image))
+ return FALSE;
+
+ user_data->list = g_slist_prepend (user_data->list, gclass);
+ return TRUE;
+}
+
+static gboolean
+steal_ginst_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoGenericInst *ginst = key;
+ CleanForImageUserData *user_data = data;
+
+ if (!ginst_in_image (ginst, user_data->image))
+ return FALSE;
+
+ user_data->list = g_slist_prepend (user_data->list, ginst);
+ return TRUE;
+}
+
+static gboolean
+inflated_method_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoImage *image = data;
+ MonoMethodInflated *method = key;
+
+ // FIXME:
+ // https://bugzilla.novell.com/show_bug.cgi?id=458168
+ return method->declaring->klass->image == image ||
+ (method->context.class_inst && ginst_in_image (method->context.class_inst, image)) ||
+ (method->context.method_inst && ginst_in_image (method->context.method_inst, image)) || (((MonoMethod*)method)->signature && signature_in_image (mono_method_signature ((MonoMethod*)method), image));
+}
+
+static gboolean
+inflated_signature_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoImage *image = data;
+ MonoInflatedMethodSignature *sig = key;
+
+ return signature_in_image (sig->sig, image) ||
+ (sig->context.class_inst && ginst_in_image (sig->context.class_inst, image)) ||
+ (sig->context.method_inst && ginst_in_image (sig->context.method_inst, image));
+}
+
+void
+mono_metadata_clean_for_image (MonoImage *image)
+{
+ CleanForImageUserData ginst_data, gclass_data;
+ GSList *l;
+
+ /* The data structures could reference each other so we delete them in two phases */
+ ginst_data.image = gclass_data.image = image;
+ ginst_data.list = gclass_data.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, steal_ginst_in_image, &ginst_data);
+ g_hash_table_foreach_steal (generic_class_cache, steal_gclass_in_image, &gclass_data);
+ if (generic_method_cache)
+ g_hash_table_foreach_remove (generic_method_cache, inflated_method_in_image, image);
+ if (generic_signature_cache)
+ g_hash_table_foreach_remove (generic_signature_cache, inflated_signature_in_image, image);
+ /* Delete the removed items */
+ for (l = ginst_data.list; l; l = l->next)
+ free_generic_inst (l->data);
+ for (l = gclass_data.list; l; l = l->next)
+ free_generic_class (l->data);
+ g_slist_free (ginst_data.list);
+ g_slist_free (gclass_data.list);
+ mono_class_unregister_image_generic_subclasses (image);
+ 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);
+}
+
+
+static void
+free_generic_class (MonoGenericClass *gclass)
+{
+ int i;
+
+ /* FIXME: The dynamic case */
+ if (gclass->cached_class && !gclass->cached_class->image->dynamic && !mono_generic_class_is_generic_type_definition (gclass)) {
+ MonoClass *class = gclass->cached_class;
+
+ /* Allocated in mono_class_init () */
+ g_free (class->methods);
+ g_free (class->properties);
+ /* Allocated in mono_generic_class_get_class () */
+ g_free (class->interfaces);
+ g_free (class);
+ } else if (gclass->is_dynamic) {
+ MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *)gclass;
+
+ for (i = 0; i < dgclass->count_fields; ++i) {
+ MonoClassField *field = dgclass->fields + i;
+ mono_metadata_free_type (field->type);
+ g_free ((char*)field->name);
+ }
+ for (i = 0; i < dgclass->count_properties; ++i) {
+ MonoProperty *property = dgclass->properties + i;
+ g_free ((char*)property->name);
+ }
+ for (i = 0; i < dgclass->count_events; ++i) {
+ MonoEvent *event = dgclass->events + i;
+ g_free ((char*)event->name);
+ }
+
+ g_free (dgclass->methods);
+ g_free (dgclass->ctors);
+ g_free (dgclass->fields);
+ g_free (dgclass->properties);
+ g_free (dgclass->events);
+ g_free (dgclass->field_objects);
+ g_free (dgclass->field_generic_types);
+ if (!mono_generic_class_is_generic_type_definition (gclass))
+ g_free (gclass->cached_class);
+ }
+ 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: