[image] Create MonoImageStorage to own the image raw data (mono/mono#13892)
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Sun, 7 Apr 2019 09:23:29 +0000 (05:23 -0400)
committerZoltan Varga <vargaz@gmail.com>
Sun, 7 Apr 2019 09:23:29 +0000 (05:23 -0400)
Create a new data structure: MonoImageStorage.

It is an object that will have the responsibility for the raw data of a
MonoImage.  It has a string key and a refcount that is used to share a
MonoImageStorage between multiple MonoImage objects.

The reason we need this is because the current MonoAssembly/MonoImage design is
broken for multiple domains and (more evidently) it will be broken when we add
AssemblyLoadContext support.  The issue is that a MonoImage may be shared
between multiple domains (or ALCs), but it has a 'references' field which
points to a single other MonoAssembly.

This is a problem because the references of an image may be resolved
differently in different domains (or ALCs).

The eventual solution will be to stop sharing MonoImages based on path name (or
in the case of in-memory images based on a name made up from the address of the
byte blob).

However we still don't want to open the same data more than once (if we're on a
config where we don't have mmap, we malloc some memory and dump the data in
there - we don't want to do that multiple times for the same file).

So the solution is to create this MonoImageStorage object and make it possible
to share it based on path name, but don't give it any responsibilities except
for owning the memory.  It doesn't know anything about metadata or assemblies
or any of that stuff - it just owns a chunk of memory and knows when and how to
free it.

This commit just adds the MonoImageStorage object and wires it up in MonoImage
loading.  There should be no observable behavioral changes from this commit.

Commit migrated from https://github.com/mono/mono/commit/a56573fb7c61adc4a0629a540d0ba093c1f951d8

src/mono/mono/metadata/assembly.c
src/mono/mono/metadata/coree.c
src/mono/mono/metadata/debug-mono-ppdb.c
src/mono/mono/metadata/icall-windows.c
src/mono/mono/metadata/image.c
src/mono/mono/metadata/loader.c
src/mono/mono/metadata/metadata-internals.h
src/mono/mono/metadata/metadata-verify.c
src/mono/mono/metadata/reflection.c
src/mono/mono/metadata/w32process.c
src/mono/mono/mini/debugger-agent.c

index ff78838..8ee513d 100644 (file)
@@ -2902,7 +2902,7 @@ mono_assembly_request_load_from (MonoImage *image, const char *fname,
        mono_assemblies_unlock ();
 
 #ifdef HOST_WIN32
-       if (image->is_module_handle)
+       if (m_image_is_module_handle (image))
                mono_image_fixup_vtable (image);
 #endif
 
index bb7de96..8d2e2f1 100644 (file)
@@ -103,7 +103,7 @@ BOOL STDMETHODCALLTYPE _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes
 
                        image = mono_image_open (file_name, NULL);
                        if (image) {
-                               image->has_entry_point = TRUE;
+                               image->storage->has_entry_point = TRUE;
                                mono_close_exe_image ();
                                /* Decrement reference count to zero. (Image will not be closed.) */
                                mono_image_close (image);
@@ -954,8 +954,8 @@ mono_load_coree (const char* exe_file_name)
 void
 mono_fixup_exe_image (MonoImage* image)
 {
-       if (!init_from_coree && image && image->is_module_handle)
-               MonoFixupExe ((HMODULE) image->raw_data);
+       if (!init_from_coree && image && m_image_is_module_handle (image))
+               MonoFixupExe ((HMODULE) m_image_get_raw_data (image));
 }
 
 #endif /* HOST_WIN32 */
index 994dedb..53bae70 100644 (file)
@@ -80,10 +80,10 @@ get_pe_debug_guid (MonoImage *image, guint8 *out_guid, gint32 *out_age, gint32 *
                return FALSE;
 
        int offset = mono_cli_rva_image_map (image, debug_dir_entry->rva);
-       debug_dir = (ImageDebugDirectory*)(image->raw_data + offset);
+       debug_dir = (ImageDebugDirectory*)(m_image_get_raw_data (image) + offset);
        if (debug_dir->type == 2 && debug_dir->major_version == 0x100 && debug_dir->minor_version == 0x504d) {
                /* This is a 'CODEVIEW' debug directory */
-               CodeviewDebugDirectory *dir = (CodeviewDebugDirectory*)(image->raw_data + debug_dir->pointer);
+               CodeviewDebugDirectory *dir = (CodeviewDebugDirectory*)(m_image_get_raw_data (image) + debug_dir->pointer);
 
                if (dir->signature == 0x53445352) {
                        memcpy (out_guid, dir->guid, 16);
index 05fed5c..3a8bcd2 100644 (file)
@@ -38,8 +38,8 @@ mono_icall_get_file_path_prefix (const gchar *path)
 gpointer
 mono_icall_module_get_hinstance (MonoImage *image)
 {
-       if (image && image->is_module_handle)
-               return image->raw_data;
+       if (image && m_image_is_module_handle (image))
+               return m_image_get_raw_data (image);
 
        return (gpointer) (-1);
 }
index b77cb34..73abc24 100644 (file)
@@ -113,8 +113,17 @@ static gboolean debug_assembly_unload = FALSE;
 
 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
+#define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
+#define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
 static gboolean mutex_inited;
 static mono_mutex_t images_mutex;
+static mono_mutex_t images_storage_mutex;
+
+/* Maps string keys to MonoImageStorage values.
+ *
+ * The MonoImageStorage in the hash owns the key.
+ */
+static GHashTable *images_storage_hash;
 
 static void install_pe_loader (void);
 
@@ -177,7 +186,7 @@ mono_install_image_loader (const MonoImageLoader *loader)
        image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
 }
 
-/* returns offset relative to image->raw_data */
+/* returns offset relative to m_image_get_raw_data (image) */
 guint32
 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
 {
@@ -193,7 +202,7 @@ mono_cli_rva_image_map (MonoImage *image, guint32 addr)
                if ((addr >= tables->st_virtual_address) &&
                    (addr < tables->st_virtual_address + tables->st_raw_data_size)){
 #ifdef HOST_WIN32
-                       if (image->is_module_handle)
+                       if (m_image_is_module_handle (image))
                                return addr;
 #endif
                        return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
@@ -223,9 +232,9 @@ mono_image_rva_map (MonoImage *image, guint32 addr)
        int i;
 
 #ifdef HOST_WIN32
-       if (image->is_module_handle) {
-               if (addr && addr < image->raw_data_len)
-                       return image->raw_data + addr;
+       if (m_image_is_module_handle (image)) {
+               if (addr && addr < m_image_get_raw_data_len (image))
+                       return m_image_get_raw_data (image) + addr;
                else
                        return NULL;
        }
@@ -254,8 +263,11 @@ mono_image_rva_map (MonoImage *image, guint32 addr)
 void
 mono_images_init (void)
 {
+       mono_os_mutex_init (&images_storage_mutex);
        mono_os_mutex_init_recursive (&images_mutex);
 
+       images_storage_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
        int hash_idx;
        for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
                loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
@@ -290,6 +302,10 @@ mono_images_cleanup (void)
        for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
                g_hash_table_destroy (loaded_images_hashes [hash_idx]);
 
+       g_hash_table_destroy (images_storage_hash);
+
+       mono_os_mutex_destroy (&images_storage_mutex);
+
        mutex_inited = FALSE;
 }
 
@@ -316,15 +332,15 @@ mono_image_ensure_section_idx (MonoImage *image, int section)
 
        sect = &iinfo->cli_section_tables [section];
        
-       if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
+       if (sect->st_raw_data_ptr + sect->st_raw_data_size > m_image_get_raw_data_len (image))
                return FALSE;
 #ifdef HOST_WIN32
-       if (image->is_module_handle)
-               iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
+       if (m_image_is_module_handle (image))
+               iinfo->cli_sections [section] = m_image_get_raw_data (image) + sect->st_virtual_address;
        else
 #endif
        /* FIXME: we ignore the writable flag since we don't patch the binary */
-       iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
+       iinfo->cli_sections [section] = m_image_get_raw_data (image) + sect->st_raw_data_ptr;
        return TRUE;
 }
 
@@ -366,9 +382,9 @@ load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
        for (i = 0; i < top; i++){
                MonoSectionTable *t = &iinfo->cli_section_tables [i];
 
-               if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
+               if (offset + sizeof (MonoSectionTable) > m_image_get_raw_data_len (image))
                        return FALSE;
-               memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
+               memcpy (t, m_image_get_raw_data (image) + offset, sizeof (MonoSectionTable));
                offset += sizeof (MonoSectionTable);
 
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
@@ -397,9 +413,9 @@ mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
        if (offset == INVALID_ADDRESS)
                return FALSE;
 
-       if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
+       if (offset + sizeof (MonoCLIHeader) > m_image_get_raw_data_len (image))
                return FALSE;
-       memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
+       memcpy (&iinfo->cli_cli_header, m_image_get_raw_data (image) + offset, sizeof (MonoCLIHeader));
 
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
@@ -467,9 +483,9 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
 
        size = iinfo->cli_cli_header.ch_metadata.size;
 
-       if (offset + size > image->raw_data_len)
+       if (offset + size > m_image_get_raw_data_len (image))
                return FALSE;
-       image->raw_metadata = image->raw_data + offset;
+       image->raw_metadata = m_image_get_raw_data (image) + offset;
 
        /* 24.2.1: Metadata root starts here */
        ptr = image->raw_metadata;
@@ -746,7 +762,7 @@ mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
                                image->modules [idx - 1] = moduleImage;
 
 #ifdef HOST_WIN32
-                               if (image->modules [idx - 1]->is_module_handle)
+                               if (m_image_is_module_handle (image->modules [idx - 1]))
                                        mono_image_fixup_vtable (image->modules [idx - 1]);
 #endif
                                /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
@@ -835,12 +851,12 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
        MonoDotNetHeader64 header64;
 
 #ifdef HOST_WIN32
-       if (!image->is_module_handle)
+       if (!m_image_is_module_handle (image))
 #endif
-       if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
+       if (offset + sizeof (MonoDotNetHeader32) > m_image_get_raw_data_len (image))
                return -1;
 
-       memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
+       memcpy (header, m_image_get_raw_data (image) + offset, sizeof (MonoDotNetHeader));
 
        if (header->pesig [0] != 'P' || header->pesig [1] != 'E' || header->pesig [2] || header->pesig [3])
                return -1;
@@ -878,7 +894,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
                /* PE32+ file format */
                if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
                        return -1;
-               memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
+               memcpy (&header64, m_image_get_raw_data (image) + offset, sizeof (MonoDotNetHeader64));
                offset += sizeof (MonoDotNetHeader64);
                /* copy the fields already swapped. the last field, pe_data_size, is missing */
                memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
@@ -956,8 +972,8 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
        SWAPPDE (header->datadir.pe_reserved);
 
 #ifdef HOST_WIN32
-       if (image->is_module_handle)
-               image->raw_data_len = header->nt.pe_image_size;
+       if (m_image_is_module_handle (image))
+               image->storage->raw_data_len = header->nt.pe_image_size;
 #endif
 
        return offset;
@@ -981,11 +997,11 @@ pe_image_load_pe_data (MonoImage *image)
        header = &iinfo->cli_header;
 
 #ifdef HOST_WIN32
-       if (!image->is_module_handle)
+       if (!m_image_is_module_handle (image))
 #endif
-       if (offset + sizeof (msdos) > image->raw_data_len)
+       if (offset + sizeof (msdos) > m_image_get_raw_data_len (image))
                goto invalid_image;
-       memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
+       memcpy (&msdos, m_image_get_raw_data (image) + offset, sizeof (msdos));
        
        if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
                goto invalid_image;
@@ -1100,7 +1116,7 @@ pe_image_load_tables (MonoImage *image)
 static gboolean
 pe_image_match (MonoImage *image)
 {
-       if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
+       if (m_image_get_raw_data (image) [0] == 'M' && m_image_get_raw_data (image) [1] == 'Z')
                return TRUE;
        return FALSE;
 }
@@ -1417,14 +1433,98 @@ invalid_image:
        return NULL;
 }
 
-static MonoImage *
-do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
-                                       gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
+static gboolean
+mono_image_storage_trypublish (MonoImageStorage *candidate, MonoImageStorage **out_storage)
+{
+       gboolean result;
+       mono_images_storage_lock ();
+       MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, candidate->key);
+       if (val) {
+               mono_refcount_inc (val);
+               *out_storage = val;
+               result = FALSE;
+       } else {
+               g_hash_table_insert (images_storage_hash, candidate->key, candidate);
+               result = TRUE;
+       }
+       mono_images_storage_unlock ();
+       return result;
+}
+
+static void
+mono_image_storage_unpublish (MonoImageStorage *storage)
 {
-       MonoCLIImageInfo *iinfo;
-       MonoImage *image;
-       MonoFileMap *filed;
+       mono_images_storage_lock ();
+       g_assert (storage->ref.ref == 0);
+
+       MonoImageStorage *published = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, storage->key);
+       if (published == storage) {
+               g_hash_table_remove (images_storage_hash, storage->key);
+       }
 
+       mono_images_storage_unlock ();
+}
+
+static gboolean
+mono_image_storage_tryaddref (const char *key, MonoImageStorage **found)
+{
+       gboolean result = FALSE;
+       mono_images_storage_lock ();
+       MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, key);
+       if (val) {
+               mono_refcount_inc (val);
+               *found = val;
+               result = TRUE;
+       }
+       mono_images_storage_unlock ();
+       return result;
+}
+
+static void
+mono_image_storage_dtor (gpointer self)
+{
+       MonoImageStorage *storage = (MonoImageStorage *)self;
+
+       mono_image_storage_unpublish (storage);
+       
+       if (storage->raw_buffer_used) {
+               if (storage->raw_data != NULL) {
+#ifndef HOST_WIN32
+                       if (storage->fileio_used)
+                               mono_file_unmap_fileio (storage->raw_data, storage->raw_data_handle);
+                       else
+#endif
+                               mono_file_unmap (storage->raw_data, storage->raw_data_handle);
+               }
+       }
+       if (storage->raw_data_allocated) {
+               g_free (storage->raw_data);
+       }
+
+       g_free (storage->key);
+
+       g_free (storage);
+}
+
+static void
+mono_image_storage_close (MonoImageStorage *storage)
+{
+       mono_refcount_dec (storage);
+}
+
+static MonoImageStorage *
+mono_image_storage_open (const char *fname)
+{
+       char *key = NULL;
+
+       key = mono_path_resolve_symlinks (fname);
+       MonoImageStorage *published_storage = NULL;
+       if (mono_image_storage_tryaddref (key, &published_storage)) {
+               g_free (key);
+               return published_storage;
+       }
+       
+       MonoFileMap *filed;
        if ((filed = mono_file_map_open (fname)) == NULL){
                if (IS_PORTABILITY_SET) {
                        gchar *ffname = mono_portability_find_file (fname, TRUE);
@@ -1435,24 +1535,79 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
                }
 
                if (filed == NULL) {
-                       if (status)
-                               *status = MONO_IMAGE_ERROR_ERRNO;
+                       g_free (key);
                        return NULL;
                }
        }
 
-       image = g_new0 (MonoImage, 1);
-       image->raw_buffer_used = TRUE;
-       image->raw_data_len = mono_file_map_size (filed);
-       image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+       MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+       mono_refcount_init (storage, mono_image_storage_dtor);
+       storage->raw_buffer_used = TRUE;
+       storage->raw_data_len = mono_file_map_size (filed);
+       storage->raw_data = (char*)mono_file_map (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
-       if (!image->raw_data) {
-               image->fileio_used = TRUE;
-               image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+       if (!storage->raw_data) {
+               storage->fileio_used = TRUE;
+               storage->raw_data = (char *)mono_file_map_fileio (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
        }
 #endif
-       if (!image->raw_data) {
-               mono_file_map_close (filed);
+       mono_file_map_close (filed);
+
+       storage->key = key;
+       
+       MonoImageStorage *other_storage = NULL;
+       if (!mono_image_storage_trypublish (storage, &other_storage)) {
+               mono_image_storage_close (storage);
+               storage = other_storage;
+       }
+       return storage;
+}
+
+static MonoImageStorage *
+mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_data_allocated, const char *name)
+{
+       char *key = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup (name);
+       MonoImageStorage *published_storage = NULL;
+       if (mono_image_storage_tryaddref (key, &published_storage)) {
+               g_free (key);
+               return published_storage;
+       }
+
+       MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+       mono_refcount_init (storage, mono_image_storage_dtor);
+
+       storage->raw_data = datac;
+       storage->raw_data_len = data_len;
+       storage->raw_data_allocated = raw_data_allocated;
+
+       storage->key = key;
+       MonoImageStorage *other_storage = NULL;
+       if (!mono_image_storage_trypublish (storage, &other_storage)) {
+               mono_image_storage_close (storage);
+               storage = other_storage;
+       }
+       return storage;
+}
+
+static MonoImage *
+do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
+                                       gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
+{
+       MonoCLIImageInfo *iinfo;
+       MonoImage *image;
+
+       MonoImageStorage *storage = mono_image_storage_open (fname);
+
+       if (!storage) {
+               if (status)
+                       *status = MONO_IMAGE_ERROR_ERRNO;
+               return NULL;
+       }
+
+       image = g_new0 (MonoImage, 1);
+       image->storage = storage;
+       if (!m_image_get_raw_data (image)) {
+               mono_image_storage_close (image->storage);
                g_free (image);
                if (status)
                        *status = MONO_IMAGE_IMAGE_INVALID;
@@ -1469,7 +1624,6 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
        /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
        image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
 
-       mono_file_map_close (filed);
        return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
 }
 
@@ -1629,10 +1783,9 @@ mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_
                memcpy (datac, data, data_len);
        }
 
+       MonoImageStorage *storage = mono_image_storage_new_raw_data (datac, data_len, need_copy, name);
        image = g_new0 (MonoImage, 1);
-       image->raw_data = datac;
-       image->raw_data_len = data_len;
-       image->raw_data_allocated = need_copy;
+       image->storage = storage;
        image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
        iinfo = g_new0 (MonoCLIImageInfo, 1);
        image->image_info = iinfo;
@@ -1687,6 +1840,32 @@ mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, Mon
 }
 
 #ifdef HOST_WIN32
+static MonoImageStorage *
+mono_image_storage_open_from_module_handle (HMODULE module_handle, const char *fname, gboolean has_entry_point)
+{
+       char *key = g_strdup (fname);
+       MonoImageStorage *published_storage = NULL;
+       if (mono_image_storage_tryaddref (key, &published_storage)) {
+               g_free (key);
+               return published_storage;
+       }
+
+       MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
+       mono_refcount_init (storage, mono_image_storage_dtor);
+       storage->raw_data = (char*) module_handle;
+       storage->is_module_handle = TRUE;
+       storage->has_entry_point = has_entry_point;
+
+       storage->key = key;
+
+       MonoImageStorage *other_storage = NULL;
+       if (!mono_image_storage_trypublish (storage, &other_storage)) {
+               mono_image_storage_close (storage);
+               storage = other_storage;
+       }
+       return storage;
+}
+
 /* fname is not duplicated. */
 MonoImage*
 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
@@ -1694,14 +1873,13 @@ mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean
        MonoImage* image;
        MonoCLIImageInfo* iinfo;
 
+       MonoImageStorage *storage = mono_image_storage_open_from_module_handle (module_handle, fname, has_entry_point);
        image = g_new0 (MonoImage, 1);
-       image->raw_data = (char*) module_handle;
-       image->is_module_handle = TRUE;
+       image->storage = storage;
        iinfo = g_new0 (MonoCLIImageInfo, 1);
        image->image_info = iinfo;
        image->name = fname;
        image->ref_count = has_entry_point ? 0 : 1;
-       image->has_entry_point = has_entry_point;
 
        image = do_mono_image_load (image, status, TRUE, TRUE);
        if (image == NULL)
@@ -1756,13 +1934,13 @@ mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean
                                mono_images_unlock ();
                                return NULL;
                        }
-                       g_assert (image->is_module_handle);
-                       if (image->has_entry_point && image->ref_count == 0) {
+                       g_assert (m_image_is_module_handle (image));
+                       if (m_image_has_entry_point (image) && image->ref_count == 0) {
                                /* Increment reference count on images loaded outside of the runtime. */
                                fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
                                /* The image is already loaded because _CorDllMain removes images from the hash. */
                                module_handle = LoadLibrary (fname_utf16);
-                               g_assert (module_handle == (HMODULE) image->raw_data);
+                               g_assert (module_handle == (HMODULE) m_image_get_raw_data (image));
                        }
                        mono_image_addref (image);
                        mono_images_unlock ();
@@ -1803,8 +1981,8 @@ mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean
                }
 
                if (image) {
-                       g_assert (image->is_module_handle);
-                       g_assert (image->has_entry_point);
+                       g_assert (m_image_is_module_handle (image));
+                       g_assert (m_image_has_entry_point (image));
                        g_free (absfname);
                        return image;
                }
@@ -1927,7 +2105,7 @@ mono_image_fixup_vtable (MonoImage *image)
        guint16 slot_type;
        int slot_count;
 
-       g_assert (image->is_module_handle);
+       g_assert (m_image_is_module_handle (image));
 
        iinfo = image->image_info;
        de = &iinfo->cli_cli_header.ch_vtable_fixups;
@@ -2094,11 +2272,11 @@ mono_image_close_except_pools (MonoImage *image)
        mono_images_unlock ();
 
 #ifdef HOST_WIN32
-       if (image->is_module_handle && image->has_entry_point) {
+       if (m_image_is_module_handle (image) && m_image_has_entry_point (image)) {
                mono_images_lock ();
                if (image->ref_count == 0) {
                        /* Image will be closed by _CorDllMain. */
-                       FreeLibrary ((HMODULE) image->raw_data);
+                       FreeLibrary ((HMODULE) m_image_get_raw_data (image));
                        mono_images_unlock ();
                        return FALSE;
                }
@@ -2133,41 +2311,34 @@ mono_image_close_except_pools (MonoImage *image)
                }
        }
 
-#ifdef HOST_WIN32
-       mono_images_lock ();
-       if (image->is_module_handle && !image->has_entry_point)
-               FreeLibrary ((HMODULE) image->raw_data);
-       mono_images_unlock ();
-#endif
+       /* a MonoDynamicImage doesn't have any storage */
+       g_assert (image_is_dynamic (image) || image->storage != NULL);
 
-       if (image->raw_buffer_used) {
-               if (image->raw_data != NULL) {
-#ifndef HOST_WIN32
-                       if (image->fileio_used)
-                               mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
-                       else
-#endif
-                               mono_file_unmap (image->raw_data, image->raw_data_handle);
-               }
-       }
-       
-       if (image->raw_data_allocated) {
+       if (image->storage && m_image_is_raw_data_allocated (image)) {
                /* FIXME: do we need this? (image is disposed anyway) */
-               /* image->raw_metadata and cli_sections might lie inside image->raw_data */
+               /* image->raw_metadata and cli_sections might lie inside m_image_get_raw_data (image) */
                MonoCLIImageInfo *ii = image->image_info;
 
-               if ((image->raw_metadata > image->raw_data) &&
-                       (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
+               if ((image->raw_metadata > m_image_get_raw_data (image)) &&
+                       (image->raw_metadata <= (m_image_get_raw_data (image) + m_image_get_raw_data_len (image))))
                        image->raw_metadata = NULL;
 
                for (i = 0; i < ii->cli_section_count; i++)
-                       if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
-                               ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
+                       if (((char*)(ii->cli_sections [i]) > m_image_get_raw_data (image)) &&
+                               ((char*)(ii->cli_sections [i]) <= ((char*)m_image_get_raw_data (image) + m_image_get_raw_data_len (image))))
                                ii->cli_sections [i] = NULL;
 
-               g_free (image->raw_data);
        }
 
+#ifdef HOST_WIN32
+       mono_images_lock ();
+       if (m_image_is_module_handle (image) && !m_image_has_entry_point (image))
+               FreeLibrary ((HMODULE) m_image_get_raw_data (image));
+       mono_images_unlock ();
+#endif
+       if (image->storage)
+               mono_image_storage_close (image->storage);
+
        if (debug_assembly_unload) {
                char *old_name = image->name;
                image->name = g_strdup_printf ("%s - UNLOADED", old_name);
@@ -2609,7 +2780,7 @@ mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError
                mono_image_unlock (image);
                /* vtable fixup can't happen with the image lock held */
 #ifdef HOST_WIN32
-               if (res->is_module_handle)
+               if (m_image_is_module_handle (res))
                        mono_image_fixup_vtable (res);
 #endif
        }
index f966f8f..b6072e5 100644 (file)
@@ -1943,7 +1943,7 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
 
 #ifdef TARGET_WIN32
                /* IJW is P/Invoke with a predefined function pointer. */
-               if (image->is_module_handle && (cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
+               if (m_image_is_module_handle (image) && (cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
                        piinfo->addr = mono_image_rva_map (image, cols [0]);
                        g_assert (piinfo->addr);
                }
index c2ba3ea..c1e4d57 100644 (file)
@@ -19,6 +19,7 @@
 #include "mono/utils/mono-value-hash.h"
 #include <mono/utils/mono-error.h>
 #include "mono/utils/mono-conc-hashtable.h"
+#include "mono/utils/refcount.h"
 
 struct _MonoType {
        union {
@@ -306,16 +307,24 @@ typedef struct {
        gboolean (*load_tables) (MonoImage*);
 } MonoImageLoader;
 
-struct _MonoImage {
-       /*
-        * This count is incremented during these situations:
-        *   - An assembly references this MonoImage though its 'image' field
-        *   - This MonoImage is present in the 'files' field of an image
-        *   - This MonoImage is present in the 'modules' field of an image
-        *   - A thread is holding a temporary reference to this MonoImage between
-        *     calls to mono_image_open and mono_image_close ()
-        */
-       int   ref_count;
+/* Represents the physical bytes (usually on disk, but could be in memory) for
+ * an image.
+ *
+ * The MonoImageStorage owns the raw data for an image and is responsible for
+ * cleanup.
+ *
+ * May be shared by multiple MonoImage objects if they opened the same
+ * underlying file or byte blob in memory.
+ *
+ * There is an abstract string key (usually a file path, but could be formed in
+ * other ways) that is used to share MonoImageStorage objects among images.
+ *
+ */
+typedef struct {
+       MonoRefCount ref;
+
+       /* key used for lookups.  owned by this image storage. */
+       char *key;
 
        /* If the raw data was allocated from a source such as mmap, the allocator may store resource tracking information here. */
        void *raw_data_handle;
@@ -332,6 +341,20 @@ struct _MonoImage {
        /* Module entry point is _CorDllMain. */
        guint8 has_entry_point : 1;
 #endif
+} MonoImageStorage;
+
+struct _MonoImage {
+       /*
+        * This count is incremented during these situations:
+        *   - An assembly references this MonoImage though its 'image' field
+        *   - This MonoImage is present in the 'files' field of an image
+        *   - This MonoImage is present in the 'modules' field of an image
+        *   - A thread is holding a temporary reference to this MonoImage between
+        *     calls to mono_image_open and mono_image_close ()
+        */
+       int   ref_count;
+
+       MonoImageStorage *storage;
 
        /* Whenever this is a dynamically emitted module */
        guint8 dynamic : 1;
@@ -1122,4 +1145,43 @@ mono_asmctx_get_kind (const MonoAssemblyContext *ctx);
 
 #define MONO_CLASS_IS_INTERFACE_INTERNAL(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_INTERFACE) || mono_type_is_generic_parameter (m_class_get_byval_arg (c)))
 
+static inline char*
+m_image_get_raw_data (MonoImage *image)
+{
+       return image->storage ? image->storage->raw_data : NULL;
+}
+
+static inline guint32
+m_image_get_raw_data_len (MonoImage *image)
+{
+       return image->storage ? image->storage->raw_data_len : 0;
+}
+
+static inline gboolean
+m_image_is_raw_data_allocated (MonoImage *image)
+{
+       return image->storage ? image->storage->raw_data_allocated : FALSE;
+}
+
+static inline gboolean
+m_image_is_fileio_used (MonoImage *image)
+{
+       return image->storage ? image->storage->fileio_used : FALSE;
+}
+
+#ifdef HOST_WIN32
+static inline gboolean
+m_image_is_module_handle (MonoImage *image)
+{
+       return image->storage ? image->storage->is_module_handle : FALSE;
+}
+
+static inline gboolean
+m_image_has_entry_point (MonoImage *image)
+{
+       return image->storage ? image->storage->has_entry_point : FALSE;
+}
+
+#endif
+
 #endif /* __MONO_METADATA_INTERNALS_H__ */
index 33fd435..418f5c3 100644 (file)
@@ -951,11 +951,11 @@ get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
 static gboolean
 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
 {
-       guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
+       guint32 heap_offset = (char*)image->heap_strings.data - m_image_get_raw_data (image);
        guint32 heap_size = image->heap_strings.size;
 
        glong length;
-       const char *data = image->raw_data + heap_offset;
+       const char *data = m_image_get_raw_data (image) + heap_offset;
 
        if (offset >= heap_size)
                return FALSE;
@@ -3944,8 +3944,8 @@ init_verify_context (VerifyContext *ctx, MonoImage *image)
        ctx->report_error = TRUE;
        ctx->report_warning = FALSE; //export this setting in the API
        ctx->valid = 1;
-       ctx->size = image->raw_data_len;
-       ctx->data = image->raw_data;
+       ctx->size = m_image_get_raw_data_len (image);
+       ctx->data = m_image_get_raw_data (image);
 }
 
 static gboolean
index 9242bdc..10a41a0 100644 (file)
@@ -1260,7 +1260,7 @@ method_body_object_construct (MonoDomain *domain, MonoClass *unused_class, MonoM
        if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
                (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
-           (image->raw_data && image->raw_data [1] != 'Z') ||
+           (!image_is_dynamic (image) && m_image_get_raw_data (image) && m_image_get_raw_data (image) [1] != 'Z') ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME))
                return MONO_HANDLE_CAST (MonoReflectionMethodBody, NULL_HANDLE);
 
index 875b7e3..cda8108 100644 (file)
@@ -461,7 +461,7 @@ get_domain_assemblies (MonoDomain *domain)
        mono_domain_assemblies_lock (domain);
        for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
                MonoAssembly *ass = (MonoAssembly *)tmp->data;
-               if (ass->image->fileio_used)
+               if (m_image_is_fileio_used (ass->image))
                        continue;
                g_ptr_array_add (assemblies, ass);
        }
@@ -547,8 +547,8 @@ process_get_module (MonoAssembly *assembly, MonoClass *proc_class, MonoError *er
        goto_if_nok (error, return_null);
        process_set_field_object (item, "version_info", filever);
 
-       process_set_field_intptr (item, "baseaddr", assembly->image->raw_data);
-       process_set_field_int (item, "memory_size", assembly->image->raw_data_len);
+       process_set_field_intptr (item, "baseaddr", m_image_get_raw_data (assembly->image));
+       process_set_field_int (item, "memory_size", m_image_get_raw_data_len (assembly->image));
        process_set_field_string_char (item, "filename", filename, error);
        goto_if_nok (error, return_null);
        process_set_field_string_char (item, "modulename", modulename, error);
index 26acf40..8c123ad 100644 (file)
@@ -7348,7 +7348,7 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
         if (ass->dynamic) {
             return ERR_NOT_IMPLEMENTED;
         }
-        buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
+        buffer_add_byte_array (buf, (guint8*)m_image_get_raw_data (image), m_image_get_raw_data_len (image));
         break;
     }
     case CMD_ASSEMBLY_GET_IS_DYNAMIC: {
@@ -7364,7 +7364,7 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
         MonoPPDBFile* ppdb = handle->ppdb;
         if (ppdb) {
             image = mono_ppdb_get_image (ppdb);
-            buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
+            buffer_add_byte_array (buf, (guint8*)m_image_get_raw_data (image), m_image_get_raw_data_len (image));
         } else {
             buffer_add_byte_array (buf, NULL, 0);
         }