#include <stdlib.h>
#include "assembly.h"
#include "image.h"
-#include "cil-coff.h"
#include "rawbuffer.h"
+#include "object-internals.h"
#include <mono/metadata/loader.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/profiler-private.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/domain-internals.h>
#include <mono/metadata/mono-endian.h>
+#include <mono/metadata/mono-debug.h>
#include <mono/io-layer/io-layer.h>
#include <mono/utils/mono-uri.h>
#include <mono/metadata/mono-config.h>
#define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
static CRITICAL_SECTION assemblies_mutex;
-/* A hastable of thread->assembly list mappings */
-static GHashTable *assemblies_loading;
-
-/* A hashtable of reflection only load thread->assemblies mappings */
-static GHashTable *assemblies_refonly_loading;
-
/* If defined, points to the bundled assembly information */
const MonoBundledAssembly **bundles;
static MonoAssembly*
search_loaded (MonoAssemblyName* aname, gboolean refonly)
{
- GList *tmp;
MonoAssembly *ass;
- GList *loading;
ass = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
if (ass)
return ass;
-
- /*
- * The assembly might be under load by this thread. In this case, it is
- * safe to return an incomplete instance to prevent loops.
- */
- loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, (gpointer)GetCurrentThreadId ());
- for (tmp = loading; tmp; tmp = tmp->next) {
- ass = tmp->data;
- if (!mono_assembly_names_equal (aname, &ass->aname))
- continue;
-
- return ass;
- }
return NULL;
}
check_extra_gac_path_env ();
InitializeCriticalSection (&assemblies_mutex);
-
- assemblies_loading = g_hash_table_new (NULL, NULL);
- assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
}
gboolean
* it inside a critical section.
*/
mono_assemblies_lock ();
- if (!image->references)
- mono_assembly_load_references (image, &status);
+ if (!image->references) {
+ MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
+
+ image->references = g_new0 (MonoAssembly *, t->rows + 1);
+ }
reference = image->references [index];
mono_assemblies_unlock ();
if (reference)
/* We use the loaded corlib */
if (!strcmp (aname.name, "mscorlib"))
reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
- else
+ else {
reference = mono_assembly_loaded_full (&aname, TRUE);
+ if (!reference)
+ /* Try a postload search hook */
+ reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
+ }
+
/*
* Here we must advice that the error was due to
* a non loaded reference using the ReflectionOnly api
void
mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
{
- MonoTableInfo *t;
-
+ /* This is a no-op now but it is part of the embedding API so we can't remove it */
*status = MONO_IMAGE_OK;
-
- t = &image->tables [MONO_TABLE_ASSEMBLYREF];
-
- image->references = g_new0 (MonoAssembly *, t->rows + 1);
}
typedef struct AssemblyLoadHook AssemblyLoadHook;
}
/*
- * load_friend_assemblies:
+ * mono_load_friend_assemblies:
* @ass: an assembly
*
* Load the list of friend assemblies that are allowed to access
* the assembly's internal types and members. They are stored as assembly
* names in custom attributes.
+ *
+ * This is an internal method, we need this because when we load mscorlib
+ * we do not have the mono_defaults.internals_visible_class loaded yet,
+ * so we need to load these after we initialize the runtime.
*/
-static void
-load_friend_assemblies (MonoAssembly* ass)
+void
+mono_assembly_load_friends (MonoAssembly* ass)
{
int i;
MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass);
{
MonoAssembly *ass, *ass2;
char *base_dir;
- GList *loading;
- GHashTable *ass_loading;
if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
/* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
return NULL;
}
-
#if defined (PLATFORM_WIN32)
{
gchar *tmp_fn;
base_dir = absolute_dir (fname);
#endif
- /*
- * To avoid deadlocks and scalability problems, we load assemblies outside
- * the assembly lock. This means that multiple threads might try to load
- * the same assembly at the same time. The first one to load it completely
- * "wins", the other threads free their copy and use the one loaded by
- * the winning thread.
- */
-
/*
* Create assembly struct, and enter it into the assembly cache
*/
ass->ref_only = refonly;
ass->image = image;
- /* Add a non-temporary reference because of ass->image */
- mono_image_addref (image);
+ mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
mono_assembly_fill_assembly_name (image, &ass->aname);
+ /* Add a non-temporary reference because of ass->image */
+ mono_image_addref (image);
+
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d\n", ass->aname.name, ass, image->name, image, image->ref_count);
/*
return ass2;
}
}
- ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
- loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
- loading = g_list_prepend (loading, ass);
- g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
- mono_assemblies_unlock ();
g_assert (image->assembly == NULL);
image->assembly = ass;
- mono_assembly_load_references (image, status);
-
- mono_assemblies_lock ();
-
- loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
- loading = g_list_remove (loading, ass);
- if (loading == NULL)
- /* Prevent memory leaks */
- g_hash_table_remove (ass_loading, (gpointer)GetCurrentThreadId ());
- else
- g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
- if (*status != MONO_IMAGE_OK) {
- mono_assemblies_unlock ();
- mono_assembly_close (ass);
- return NULL;
- }
-
- if (ass->aname.name) {
- ass2 = search_loaded (&ass->aname, refonly);
- if (ass2) {
- /* Somebody else has loaded the assembly before us */
- mono_assemblies_unlock ();
- mono_assembly_close (ass);
- return ass2;
- }
- }
-
loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
if (mono_defaults.internals_visible_class)
- load_friend_assemblies (ass);
+ mono_assembly_load_friends (ass);
mono_assemblies_unlock ();
mono_assembly_invoke_load_hook (ass);
+ mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
+
return ass;
}
if (res)
res->in_gac = TRUE;
-
+ else {
+ MonoDomain *domain = mono_domain_get ();
+ MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
+ if (refasm)
+ res = refasm->assembly;
+ }
+
g_free (fullname);
mono_assembly_name_free (aname);
return corlib;
}
-/**
- * mono_assembly_load_full:
- * @aname: A MonoAssemblyName with the assembly name to load.
- * @basedir: A directory to look up the assembly at.
- * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
- * @refonly: Whether this assembly is being opened in "reflection-only" mode.
- *
- * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
- * attempts to load the assembly from that directory before probing the standard locations.
- *
- * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
- * assembly binding takes place.
- *
- * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
- * value pointed by status is updated with an error code.
- */
-MonoAssembly*
-mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+MonoAssembly* mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
+ const char *basedir,
+ MonoImageOpenStatus *status,
+ gboolean refonly)
{
MonoAssembly *result;
char *fullpath, *filename;
return result;
}
- /* Try a postload search hook */
- result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
+ return result;
+}
+/**
+ * mono_assembly_load_full:
+ * @aname: A MonoAssemblyName with the assembly name to load.
+ * @basedir: A directory to look up the assembly at.
+ * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
+ * @refonly: Whether this assembly is being opened in "reflection-only" mode.
+ *
+ * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
+ * attempts to load the assembly from that directory before probing the standard locations.
+ *
+ * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
+ * assembly binding takes place.
+ *
+ * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
+ * value pointed by status is updated with an error code.
+ */
+MonoAssembly*
+mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+{
+ MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
+
+ if (!result)
+ /* Try a postload search hook */
+ result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
return result;
}
if (InterlockedDecrement (&assembly->ref_count) > 0)
return;
+ mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
+
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
+ mono_debug_close_image (assembly->image);
+
mono_assemblies_lock ();
loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
mono_assemblies_unlock ();
- if (assembly->image->references) {
- int i;
-
- for (i = 0; assembly->image->references [i]; i++) {
- if (assembly->image->references [i])
- mono_assembly_close (assembly->image->references [i]);
- }
-
- g_free (assembly->image->references);
- assembly->image->references = NULL;
- }
-
assembly->image->assembly = NULL;
mono_image_close (assembly->image);
} else {
g_free (assembly);
}
+
+ mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
}
MonoImage*
mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
{
- MonoImageOpenStatus status;
- MonoImage *module;
-
- module = mono_image_load_file_for_image (assembly->image, idx);
- if (module)
- mono_assembly_load_references (module, &status);
-
- return module;
+ return mono_image_load_file_for_image (assembly->image, idx);
}
void
DeleteCriticalSection (&assemblies_mutex);
- g_hash_table_destroy (assemblies_loading);
- g_hash_table_destroy (assemblies_refonly_loading);
-
for (l = loaded_assembly_bindings; l; l = l->next) {
MonoAssemblyBindingInfo *info = l->data;