+/*
+ * get_image_set:
+ *
+ * Return a MonoImageSet representing the set of images in IMAGES.
+ *
+ * LOCKING: Assumes the loader lock is held.
+ */
+static MonoImageSet*
+get_image_set (MonoImage **images, int nimages)
+{
+ int i, j, k;
+ MonoImageSet *set;
+ GSList *l;
+
+ if (!image_sets)
+ image_sets = g_ptr_array_new ();
+
+ /* Common case */
+ if (nimages == 1 && images [0] == mono_defaults.corlib && mscorlib_image_set)
+ return mscorlib_image_set;
+
+ /* Happens with empty generic instances */
+ if (nimages == 0)
+ return mscorlib_image_set;
+
+ if (images [0] == mono_defaults.corlib && nimages > 1)
+ l = images [1]->image_sets;
+ else
+ l = images [0]->image_sets;
+
+ set = NULL;
+ for (; l; l = l->next) {
+ set = l->data;
+
+ if (set->nimages == nimages) {
+ for (j = 0; j < nimages; ++j) {
+ for (k = 0; k < nimages; ++k)
+ if (set->images [k] == images [j])
+ break;
+ if (k == nimages)
+ /* Not found */
+ break;
+ }
+ if (j == nimages)
+ /* Found */
+ break;
+ }
+ }
+
+ if (!l) {
+ /* Not found */
+ set = g_new0 (MonoImageSet, 1);
+ set->nimages = nimages;
+ set->images = g_new0 (MonoImage*, nimages);
+ InitializeCriticalSection (&set->lock);
+ for (i = 0; i < nimages; ++i)
+ set->images [i] = images [i];
+ set->gclass_cache = g_hash_table_new_full (mono_generic_class_hash, mono_generic_class_equal, NULL, (GDestroyNotify)free_generic_class);
+ set->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst);
+ set->gmethod_cache = g_hash_table_new_full (inflated_method_hash, inflated_method_equal, NULL, (GDestroyNotify)free_inflated_method);
+ set->gsignature_cache = g_hash_table_new_full (inflated_signature_hash, inflated_signature_equal, NULL, (GDestroyNotify)free_inflated_signature);
+
+ for (i = 0; i < nimages; ++i)
+ set->images [i]->image_sets = g_slist_prepend (set->images [i]->image_sets, set);
+
+ g_ptr_array_add (image_sets, set);
+ }
+
+ if (nimages == 1 && images [0] == mono_defaults.corlib)
+ mscorlib_image_set = set;
+
+ return set;
+}
+
+static void
+delete_image_set (MonoImageSet *set)
+{
+ int i;
+
+ g_hash_table_destroy (set->gclass_cache);
+ g_hash_table_destroy (set->ginst_cache);
+ g_hash_table_destroy (set->gmethod_cache);
+ g_hash_table_destroy (set->gsignature_cache);
+
+ for (i = 0; i < set->nimages; ++i)
+ set->images [i]->image_sets = g_slist_remove (set->images [i]->image_sets, set);
+
+ g_ptr_array_remove (image_sets, set);
+
+ if (set->mempool)
+ mono_mempool_destroy (set->mempool);
+ g_free (set->images);
+ DeleteCriticalSection (&set->lock);
+ g_free (set);
+}
+
+static void
+mono_image_set_lock (MonoImageSet *set)
+{
+ EnterCriticalSection (&set->lock);
+}
+
+static void
+mono_image_set_unlock (MonoImageSet *set)
+{
+ LeaveCriticalSection (&set->lock);
+}
+
+gpointer
+mono_image_set_alloc (MonoImageSet *set, guint size)
+{
+ gpointer res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_alloc (set->mempool, size);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
+gpointer
+mono_image_set_alloc0 (MonoImageSet *set, guint size)
+{
+ gpointer res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_alloc0 (set->mempool, size);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
+char*
+mono_image_set_strdup (MonoImageSet *set, const char *s)
+{
+ char *res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_strdup (set->mempool, s);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
+/*
+ * Structure used by the collect_..._images functions to store the image list.
+ */
+typedef struct {
+ MonoImage *image_buf [64];
+ MonoImage **images;
+ int nimages, images_len;
+} CollectData;
+
+static void
+collect_data_init (CollectData *data)
+{
+ data->images = data->image_buf;
+ data->images_len = 64;
+ data->nimages = 0;
+}
+
+static void
+collect_data_free (CollectData *data)
+{
+ if (data->images != data->image_buf)
+ g_free (data->images);
+}
+
+static void
+enlarge_data (CollectData *data)
+{
+ int new_len = data->images_len < 16 ? 16 : data->images_len * 2;
+ MonoImage **d = g_new (MonoImage *, new_len);
+
+ // FIXME: test this
+ g_assert_not_reached ();
+ memcpy (d, data->images, data->images_len);
+ if (data->images != data->image_buf)
+ g_free (data->images);
+ data->images = d;
+ data->images_len = new_len;
+}
+
+static inline void
+add_image (MonoImage *image, CollectData *data)
+{
+ int i;
+
+ /* The arrays are small, so use a linear search instead of a hash table */
+ for (i = 0; i < data->nimages; ++i)
+ if (data->images [i] == image)
+ return;
+
+ if (data->nimages == data->images_len)
+ enlarge_data (data);
+
+ data->images [data->nimages ++] = image;
+}
+
+static void
+collect_type_images (MonoType *type, CollectData *data);
+
+static void
+collect_ginst_images (MonoGenericInst *ginst, CollectData *data)
+{
+ int i;
+
+ for (i = 0; i < ginst->type_argc; ++i) {
+ collect_type_images (ginst->type_argv [i], data);
+ }
+}
+
+static void
+collect_gclass_images (MonoGenericClass *gclass, CollectData *data)
+{
+ add_image (gclass->container_class->image, data);
+ if (gclass->context.class_inst)
+ collect_ginst_images (gclass->context.class_inst, data);
+}
+
+static void
+collect_signature_images (MonoMethodSignature *sig, CollectData *data)
+{
+ gpointer iter = NULL;
+ MonoType *p;
+
+ collect_type_images (mono_signature_get_return_type (sig), data);
+ while ((p = mono_signature_get_params (sig, &iter)) != NULL)
+ collect_type_images (p, data);
+}
+
+static void
+collect_inflated_signature_images (MonoInflatedMethodSignature *sig, CollectData *data)
+{
+ collect_signature_images (sig->sig, data);
+ if (sig->context.class_inst)
+ collect_ginst_images (sig->context.class_inst, data);
+ if (sig->context.method_inst)
+ collect_ginst_images (sig->context.method_inst, data);
+}
+
+static void
+collect_method_images (MonoMethodInflated *method, CollectData *data)
+{
+ add_image (method->declaring->klass->image, data);
+ if (method->context.class_inst)
+ collect_ginst_images (method->context.class_inst, data);
+ if (method->context.method_inst)
+ collect_ginst_images (method->context.method_inst, data);
+ /*
+ if (((MonoMethod*)method)->signature)
+ collect_signature_images (mono_method_signature ((MonoMethod*)method), data);
+ */
+}
+
+static void
+collect_type_images (MonoType *type, CollectData *data)
+{
+retry:
+ switch (type->type) {
+ case MONO_TYPE_GENERICINST:
+ collect_gclass_images (type->data.generic_class, data);
+ break;
+ 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);
+ g_assert_not_reached ();
+ case MONO_TYPE_VAR: {
+ MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+ if (container) {
+ g_assert (!container->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 (!container->owner.klass)
+ add_image (container->image, data);
+ else
+ add_image (container->owner.klass->image, data);
+ } else {
+ add_image (type->data.generic_param->image, data);
+ }
+ }
+ break;
+ case MONO_TYPE_MVAR: {
+ MonoGenericContainer *container = mono_type_get_generic_param_owner (type);
+ if (type->data.generic_param->image)
+ add_image (type->data.generic_param->image, data);
+ if (container) {
+ if (!container->owner.method) {
+ /* RefEmit created generic param whose method is not finished */
+ add_image (container->image, data);
+ } else {
+ g_assert (container->is_method);
+ add_image (container->owner.method->klass->image, data);
+ }
+ } else {
+ add_image (type->data.generic_param->image, data);
+ }
+ }
+ break;
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ add_image (mono_class_from_mono_type (type)->image, data);
+ break;
+ default:
+ add_image (mono_defaults.corlib, data);
+ }
+}
+