+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 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);
+
+static gboolean
+ginst_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoImage *image = data;
+ MonoGenericInst *ginst = key;
+ MonoClass *klass;
+ int i;
+ for (i = 0; i < ginst->type_argc; ++i) {
+ MonoType *type = ginst->type_argv [i];
+
+ /* 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, image))
+ return TRUE;
+ continue;
+ }
+
+ klass = mono_class_from_mono_type (ginst->type_argv [i]);
+ if (klass->image == image) {
+ /*dump_ginst (ginst);
+ g_print (" removed\n");*/
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+gclass_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoImage *image = data;
+ MonoGenericClass *gclass = key;
+
+ if (ginst_in_image (gclass->context.class_inst, NULL, image))
+ return TRUE;
+ if (gclass->container_class->image == image)
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+inflated_method_in_image (gpointer key, gpointer value, gpointer data)
+{
+ MonoImage *image = data;
+ MonoMethodInflated *method = key;
+
+ if (method->declaring->klass->image == image)
+ return TRUE;
+ if (method->context.class_inst && ginst_in_image (method->context.class_inst, NULL, image))
+ return TRUE;
+ if (method->context.method_inst && ginst_in_image (method->context.method_inst, NULL, image))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * 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 (inflated_method_hash, inflated_method_equal);
+ 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;
+ }
+}
+
+void
+mono_metadata_clean_for_image (MonoImage *image)
+{
+ mono_loader_lock ();
+ g_hash_table_foreach_remove (generic_inst_cache, ginst_in_image, image);
+ g_hash_table_foreach_remove (generic_class_cache, gclass_in_image, image);
+ if (generic_method_cache)
+ g_hash_table_foreach_remove (generic_method_cache, inflated_method_in_image, image);
+ mono_loader_unlock ();
+}
+