#include "private.h"
#include "tabledefs.h"
#include "tokentype.h"
+#include <mono/io-layer/io-layer.h>
#define INVALID_ADDRESS 0xffffffff
static GHashTable *loaded_images_hash;
static GHashTable *loaded_images_guid_hash;
+static CRITICAL_SECTION images_mutex;
+
guint32
mono_cli_rva_image_map (MonoCLIImageInfo *iinfo, guint32 addr)
{
return NULL;
}
+/**
+ * mono_images_init:
+ *
+ * Initialize the global variables used by this module.
+ */
+void
+mono_images_init (void)
+{
+ InitializeCriticalSection (&images_mutex);
+
+ loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ loaded_images_guid_hash = g_hash_table_new (g_str_hash, g_str_equal);
+}
+
/**
* mono_image_ensure_section_idx:
* @image: The image we are operating on
char *ptr;
offset = mono_cli_rva_image_map (iinfo, iinfo->cli_cli_header.ch_metadata.rva);
+ if (offset == INVALID_ADDRESS)
+ return FALSE;
+
size = iinfo->cli_cli_header.ch_metadata.size;
if (!image->f) {
return FALSE;
} else {
g_message ("Unknown heap type: %s\n", ptr + 8);
- ptr += 8 + strlen (ptr) + 1;
+ ptr += 8 + strlen (ptr + 8) + 1;
}
pad = ptr - image->raw_metadata;
if (pad % 4)
module_ref = g_build_filename (base_dir, name, NULL);
image->modules [i] = mono_image_open (module_ref, status);
if (image->modules [i]) {
- image->modules [i]->assembly = image->assembly;
//g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly);
}
/*
*status = MONO_IMAGE_OK;
g_free (module_ref);
}
+
g_free (base_dir);
}
guint32 cols [MONO_TYPEDEF_SIZE];
const char *name;
const char *nspace;
- guint32 i, visib;
+ guint32 i, visib, nspace_index;
+ GHashTable *name_cache2, *nspace_table;
+
+ /* Temporary hash table to avoid lookups in the nspace_table */
+ name_cache2 = g_hash_table_new (NULL, NULL);
for (i = 1; i <= t->rows; ++i) {
mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
continue;
name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
- mono_image_add_to_name_cache (image, nspace, name, i);
+
+ nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
+ nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
+ if (!nspace_table) {
+ nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
+ g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
+ nspace_table);
+ }
+ g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
+ }
+
+ /* Load type names from EXPORTEDTYPES table */
+ {
+ MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
+ guint32 cols [MONO_EXP_TYPE_SIZE];
+ int i;
+
+ for (i = 0; i < t->rows; ++i) {
+ mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
+ name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
+ nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
+
+ nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
+ nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
+ if (!nspace_table) {
+ nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
+ g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
+ nspace_table);
+ }
+ g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
+ }
}
+
+ g_hash_table_destroy (name_cache2);
+}
+
+static void
+register_guid (gpointer key, gpointer value, gpointer user_data)
+{
+ MonoImage *image = (MonoImage*)value;
+
+ if (!g_hash_table_lookup (loaded_images_guid_hash, image))
+ g_hash_table_insert (loaded_images_guid_hash, image->guid, image);
+}
+
+static void
+build_guid_table (void)
+{
+ g_hash_table_foreach (loaded_images_hash, register_guid, NULL);
}
void
mono_image_init (MonoImage *image)
{
- image->method_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
- image->class_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
+ image->method_cache = g_hash_table_new (NULL, NULL);
+ image->class_cache = g_hash_table_new (NULL, NULL);
+ image->field_cache = g_hash_table_new (NULL, NULL);
image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
image->array_cache = g_hash_table_new (NULL, NULL);
g_hash_table_new ((GHashFunc)mono_signature_hash,
(GCompareFunc)mono_metadata_signature_equal);
- image->runtime_invoke_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
- image->managed_wrapper_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
- image->native_wrapper_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
- image->remoting_invoke_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
- image->synchronized_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
+ image->runtime_invoke_cache = g_hash_table_new (NULL, NULL);
+ image->managed_wrapper_cache = g_hash_table_new (NULL, NULL);
+ image->native_wrapper_cache = g_hash_table_new (NULL, NULL);
+ image->remoting_invoke_cache = g_hash_table_new (NULL, NULL);
+ image->synchronized_cache = g_hash_table_new (NULL, NULL);
- image->generics_cache = g_hash_table_new (mono_metadata_type_hash, mono_metadata_type_equal);
+ image->typespec_cache = g_hash_table_new (NULL, NULL);
+ image->generic_inst_cache =
+ g_hash_table_new ((GHashFunc)mono_metadata_generic_inst_hash,
+ (GCompareFunc)mono_metadata_generic_inst_equal);
}
static MonoImage *
image = g_new0 (MonoImage, 1);
image->ref_count = 1;
image->f = filed;
- image->name = g_strdup (fname);
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
+ if (g_path_is_absolute (fname))
+ image->name = g_strdup (fname);
+ else {
+ gchar *path = g_get_current_dir ();
+ image->name = g_build_filename (path, fname, NULL);
+ g_free (path);
+ }
+
return do_mono_image_load (image, status);
}
MonoImage *
-mono_image_loaded (const char *name) {
- if (strcmp (name, "mscorlib") == 0)
- name = "corlib";
- if (loaded_images_hash)
- return g_hash_table_lookup (loaded_images_hash, name);
- return NULL;
+mono_image_loaded (const char *name)
+{
+ MonoImage *res;
+
+ EnterCriticalSection (&images_mutex);
+ res = g_hash_table_lookup (loaded_images_hash, name);
+ LeaveCriticalSection (&images_mutex);
+ return res;
}
MonoImage *
-mono_image_loaded_by_guid (const char *guid) {
- if (loaded_images_guid_hash)
- return g_hash_table_lookup (loaded_images_guid_hash, guid);
- return NULL;
+mono_image_loaded_by_guid (const char *guid)
+{
+ MonoImage *res;
+
+ EnterCriticalSection (&images_mutex);
+ res = g_hash_table_lookup (loaded_images_guid_hash, guid);
+ LeaveCriticalSection (&images_mutex);
+ return res;
}
MonoImage *
MonoImage *
mono_image_open (const char *fname, MonoImageOpenStatus *status)
{
- MonoImage *image;
+ MonoImage *image, *image2;
g_return_val_if_fail (fname != NULL, NULL);
- if (loaded_images_hash){
- image = g_hash_table_lookup (loaded_images_hash, fname);
- if (image){
- image->ref_count++;
- return image;
- }
+ /*
+ * The easiest solution would be to do all the loading inside the mutex,
+ * but that would lead to scalability problems. So we let the loading
+ * happen outside the mutex, and if multiple threads happen to load
+ * the same image, we discard all but the first copy.
+ */
+ EnterCriticalSection (&images_mutex);
+ image = g_hash_table_lookup (loaded_images_hash, fname);
+ if (image){
+ image->ref_count++;
+ LeaveCriticalSection (&images_mutex);
+ return image;
}
+ LeaveCriticalSection (&images_mutex);
image = do_mono_image_open (fname, status);
if (image == NULL)
return NULL;
- if (!loaded_images_hash)
- loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ EnterCriticalSection (&images_mutex);
+ image2 = g_hash_table_lookup (loaded_images_hash, fname);
+ if (image2) {
+ /* Somebody else beat us to it */
+ image2->ref_count ++;
+ LeaveCriticalSection (&images_mutex);
+ mono_image_close (image);
+
+ return image2;
+ }
g_hash_table_insert (loaded_images_hash, image->name, image);
if (image->assembly_name)
- g_hash_table_insert (loaded_images_hash, (char *) image->assembly_name, image);
-
- if (!loaded_images_guid_hash)
- loaded_images_guid_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (loaded_images_hash, (char *) image->assembly_name, image);
g_hash_table_insert (loaded_images_guid_hash, image->guid, image);
+ LeaveCriticalSection (&images_mutex);
return image;
}
static void
-free_hash_table(gpointer key, gpointer val, gpointer user_data)
+free_hash_table (gpointer key, gpointer val, gpointer user_data)
{
g_hash_table_destroy ((GHashTable*)val);
}
+/**
+ * mono_image_close:
+ * @image: The image file we wish to add a reference to
+ *
+ * Increases the reference count of an image.
+ */
+void
+mono_image_addref (MonoImage *image)
+{
+ InterlockedIncrement (&image->ref_count);
+}
+
/**
* mono_image_close:
* @image: The image file we wish to close
void
mono_image_close (MonoImage *image)
{
+ MonoImage *image2;
+
g_return_if_fail (image != NULL);
- if (--image->ref_count)
+ EnterCriticalSection (&images_mutex);
+ if (--image->ref_count) {
+ LeaveCriticalSection (&images_mutex);
return;
+ }
+ image2 = g_hash_table_lookup (loaded_images_hash, image->name);
+ if (image == image2) {
+ /* This is not true if we are called from mono_image_open () */
+ g_hash_table_remove (loaded_images_hash, image->name);
+ if (image->assembly_name)
+ g_hash_table_remove (loaded_images_hash, (char *) image->assembly_name);
+ g_hash_table_remove (loaded_images_guid_hash, image->guid);
+ /* Multiple images might have the same guid */
+ build_guid_table ();
+ }
+ LeaveCriticalSection (&images_mutex);
- if (!loaded_images_hash)
- loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_remove (loaded_images_hash, image->name);
-
if (image->f)
fclose (image->f);
if (image->raw_data_allocated)
g_free (image->raw_data);
g_free (image->name);
+ g_free (image->files);
g_hash_table_destroy (image->method_cache);
g_hash_table_destroy (image->class_cache);
+ g_hash_table_destroy (image->field_cache);
g_hash_table_destroy (image->array_cache);
g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
g_hash_table_destroy (image->name_cache);
g_hash_table_destroy (image->delegate_invoke_cache);
g_hash_table_destroy (image->remoting_invoke_cache);
g_hash_table_destroy (image->runtime_invoke_cache);
+ g_hash_table_destroy (image->typespec_cache);
+ g_hash_table_destroy (image->generic_inst_cache);
if (image->raw_metadata != NULL)
mono_raw_buffer_free (image->raw_metadata);
g_free (ii->cli_sections);
g_free (image->image_info);
}
-
+
g_free (image);
}
return data;
}
+MonoImage*
+mono_image_load_file_for_image (MonoImage *image, int fileidx)
+{
+ char *base_dir, *name;
+ MonoImage *res;
+ MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
+ const char *fname;
+ guint32 fname_id;
+
+ if (fileidx < 1 || fileidx > t->rows)
+ return NULL;
+
+ if (image->files && image->files [fileidx - 1])
+ return image->files [fileidx - 1];
+
+ if (!image->files)
+ image->files = g_new0 (MonoImage*, t->rows);
+
+ fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
+ fname = mono_metadata_string_heap (image, fname_id);
+ base_dir = g_path_get_dirname (image->name);
+ name = g_build_filename (base_dir, fname, NULL);
+ res = mono_image_open (name, NULL);
+ if (res) {
+ int i;
+ t = &res->tables [MONO_TABLE_MODULEREF];
+ //g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly);
+ res->assembly = image->assembly;
+ for (i = 0; i < t->rows; ++i) {
+ if (res->modules [i] && !res->modules [i]->assembly)
+ res->modules [i]->assembly = image->assembly;
+ }
+
+ image->files [fileidx - 1] = res;
+ }
+ g_free (name);
+ g_free (base_dir);
+ return res;
+}
+
const char*
mono_image_get_strong_name (MonoImage *image, guint32 *size)
{