#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>
{"Mono.Cairo", 0},
{"Mono.CompilerServices.SymbolWriter", 0},
{"Mono.Data", 0},
- {"Mono.Data.SqliteClient", 0},
{"Mono.Data.SybaseClient", 0},
{"Mono.Data.Tds", 0},
{"Mono.Data.TdsClient", 0},
#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;
return res;
}
+/**
+ * mono_public_tokens_are_equal:
+ * @pubt1: first public key token
+ * @pubt2: second public key token
+ *
+ * Compare two public key tokens and return #TRUE is they are equal and #FALSE
+ * otherwise.
+ */
+gboolean
+mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
+{
+ return g_strcasecmp ((char*)pubt1, (char*)pubt2) == 0;
+}
+
static void
check_path_env (void)
{
const char *path;
- char **splitted;
+ char **splitted, **dest;
path = g_getenv ("MONO_PATH");
if (!path)
splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
if (assemblies_path)
g_strfreev (assemblies_path);
- assemblies_path = splitted;
+ assemblies_path = dest = splitted;
+ while (*splitted){
+ if (**splitted)
+ *dest++ = *splitted;
+ splitted++;
+ }
+ *dest = *splitted;
+
if (g_getenv ("MONO_DEBUG") == NULL)
return;
static void
check_extra_gac_path_env (void) {
const char *path;
- char **splitted;
+ char **splitted, **dest;
path = g_getenv ("MONO_GAC_PREFIX");
if (!path)
splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
if (extra_gac_paths)
g_strfreev (extra_gac_paths);
- extra_gac_paths = splitted;
+ extra_gac_paths = dest = splitted;
+ while (*splitted){
+ if (**splitted)
+ *dest++ = *splitted;
+ splitted++;
+ }
+ *dest = *splitted;
+
if (g_getenv ("MONO_DEBUG") == NULL)
return;
if (info->culture && strcmp (info->culture, aname->culture))
return FALSE;
- if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token))
+ if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
return FALSE;
return TRUE;
* @r: second assembly.
*
* Compares two MonoAssemblyNames and returns whether they are equal.
+ *
* This compares the names, the cultures, the release version and their
* public tokens.
*
if (!l->public_key_token [0] || !r->public_key_token [0])
return TRUE;
- if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token))
+ if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
return FALSE;
return TRUE;
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;
}
* @root_dir: The pathname of the root directory where we will locate assemblies
*
* This routine sets the internal default root directory for looking up
- * assemblies. This is used by Windows installations to compute dynamically
- * the place where the Mono assemblies are located.
+ * assemblies.
+ *
+ * This is used by Windows installations to compute dynamically the
+ * place where the Mono assemblies are located.
*
*/
void
/**
* mono_assembly_getrootdir:
+ *
+ * Obtains the root directory used for looking up assemblies.
*
- * Returns: The internal root directory used for looking up assemblies
+ * Returns: a string with the directory, this string should not be freed.
*/
G_CONST_RETURN gchar *
mono_assembly_getrootdir (void)
* @config_dir: the base directory for configuration files
*
* This routine is used internally and by developers embedding
- * the runtime into their own applications. There are a number
- * of cases to consider: Mono as a system-installed package that
- * is available on the location preconfigured or Mono in a relocated
- * location.
+ * the runtime into their own applications.
+ *
+ * There are a number of cases to consider: Mono as a system-installed
+ * package that is available on the location preconfigured or Mono in
+ * a relocated location.
*
* If you are using a system-installed Mono, you can pass NULL
* to both parameters. If you are not, you should compute both
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
aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
- gchar* token = g_malloc (8);
+ guchar* token = g_malloc (8);
gchar* encoded;
+ const gchar* pkey;
int len;
- aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
- len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
+ pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+ len = mono_metadata_decode_blob_size (pkey, &pkey);
+ aname->public_key = (guchar*)pkey;
mono_digest_get_public_token (token, aname->public_key, len);
encoded = encode_public_tok (token, 8);
- g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+ g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
g_free (encoded);
g_free (token);
}
if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
- aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+ aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
}
else
aname->public_key = 0;
return TRUE;
}
-/*
+/**
* mono_stringify_assembly_name:
+ * @aname: the assembly name.
*
- * Convert @aname into its string format. The returned string is dynamically
+ * Convert @aname into its string format. The returned string is dynamically
* allocated and should be freed by the caller.
+ *
+ * Returns: a newly allocated string with a string representation of
+ * the assembly name.
*/
char*
mono_stringify_assembly_name (MonoAssemblyName *aname)
{
return g_strdup_printf (
- "%s, Version=%d.%d.%d.%d, Culture=%s%s%s",
+ "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
aname->name,
aname->major, aname->minor, aname->build, aname->revision,
aname->culture && *aname->culture? aname->culture: "neutral",
- aname->public_key_token [0] ? ", PublicKeyToken=" : "",
- aname->public_key_token [0] ? (char *)aname->public_key_token : "");
+ aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
+ (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
}
static gchar*
len = mono_metadata_decode_blob_size (public_tok, &public_tok);
if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
- gchar token [8];
- mono_digest_get_public_token (token, public_tok, len);
+ guchar token [8];
+ mono_digest_get_public_token (token, (guchar*)public_tok, len);
return encode_public_tok (token, 8);
}
- return encode_public_tok (public_tok, len);
+ return encode_public_tok ((guchar*)public_tok, len);
}
/**
if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
- g_strlcpy (aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+ g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
g_free (token);
} else {
memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
* it inside a critical section.
*/
mono_assemblies_lock ();
+ 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)
mono_assembly_get_assemblyref (image, index, &aname);
- if (image->assembly->ref_only) {
+ if (image->assembly && image->assembly->ref_only) {
/* 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
if (!reference)
reference = REFERENCE_MISSING;
} else
- reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
+ reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
if (reference == NULL){
char *extra_msg = g_strdup ("");
" Public Key: %s\n%s",
image->name, aname.name, index,
aname.major, aname.minor, aname.build, aname.revision,
- strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
+ strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
g_free (extra_msg);
}
if (!image->references [index]) {
if (reference != REFERENCE_MISSING){
mono_assembly_addref (reference);
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
+ if (image->assembly)
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
} else {
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
+ if (image->assembly)
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
image->assembly->aname.name, image->assembly);
}
void
mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
{
- MonoTableInfo *t;
- int i;
-
+ /* 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);
-
- /* resolve assembly references for modules */
- for (i = 0; i < image->module_count; i++){
- if (image->modules [i]) {
- image->modules [i]->assembly = image->assembly;
- mono_assembly_load_references (image->modules [i], status);
- }
- }
}
typedef struct AssemblyLoadHook AssemblyLoadHook;
list = g_list_reverse (list);
/* Ignores last data pointer, which should be the filename */
- for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
+ for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
if (tmp->data)
g_string_append_printf (result, "%s%c", (char *) tmp->data,
G_DIR_SEPARATOR);
-
+ }
+
res = result->str;
g_string_free (result, FALSE);
g_list_free (list);
* defined bundles, if found, returns the MonoImage for it, if not found
* returns NULL
*/
-static MonoImage *
+MonoImage *
mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
{
int i;
- char *name = g_path_get_basename (filename);
+ char *name;
MonoImage *image = NULL;
/*
* we do a very simple search for bundled assemblies: it's not a general
* purpose assembly loading mechanism.
*/
+
+ if (!bundles)
+ return NULL;
+
+ name = g_path_get_basename (filename);
+
mono_assemblies_lock ();
for (i = 0; !image && bundles [i]; ++i) {
if (strcmp (bundles [i]->name, name) == 0) {
}
/*
- * 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);
for (i = 0; i < attrs->num_attrs; ++i) {
MonoCustomAttrEntry *attr = &attrs->attrs [i];
MonoAssemblyName *aname;
- const guchar *data;
+ const gchar *data;
guint slen;
/* Do some sanity checking */
if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
continue;
if (attr->data_size < 4)
continue;
- data = attr->data;
+ data = (const char*)attr->data;
/* 0xFF means null string, see custom attr format */
- if (data [0] != 1 || data [1] != 0 || data [2] == 0xFF)
+ if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
continue;
slen = mono_metadata_decode_value (data + 2, &data);
aname = g_new0 (MonoAssemblyName, 1);
/*g_print ("friend ass: %s\n", data);*/
- if (mono_assembly_name_parse_full (data, aname, TRUE, NULL)) {
+ if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname);
} else {
g_free (aname);
{
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 */
+ *status = MONO_IMAGE_IMAGE_INVALID;
+ return NULL;
+ }
#if defined (PLATFORM_WIN32)
{
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);
+ if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
+ // MS.NET doesn't support loading other mscorlibs
+ g_free (ass);
+ g_free (base_dir);
+ mono_image_addref (mono_defaults.corlib);
+ *status = MONO_IMAGE_OK;
+ return mono_defaults.corlib->assembly;
+ }
+
+ /* 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);
/*
/* avoid loading the same assembly twice for now... */
ass2 = search_loaded (&ass->aname, refonly);
if (ass2) {
+ mono_assemblies_unlock ();
g_free (ass);
g_free (base_dir);
mono_image_close (image);
*status = MONO_IMAGE_OK;
- mono_assemblies_unlock ();
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;
}
}
/**
-* mono_assembly_name_free:
-* @aname: assembly name to free
-*
-* Frees the provided assembly name object.
-* (it does not frees the object itself, only the name members).
-*/
+ * mono_assembly_name_free:
+ * @aname: assembly name to free
+ *
+ * Frees the provided assembly name object.
+ * (it does not frees the object itself, only the name members).
+ */
void
mono_assembly_name_free (MonoAssemblyName *aname)
{
}
static gboolean
-build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, MonoAssemblyName *aname, gboolean save_public_key)
+build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, MonoAssemblyName *aname, gboolean save_public_key)
{
gint major, minor, build, revision;
gint len;
aname->revision = 0;
}
+ aname->flags = flags;
aname->name = g_strdup (name);
if (culture) {
}
if (token && strncmp (token, "null", 4) != 0) {
- char *lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+ char *lower;
+
+ /* the constant includes the ending NULL, hence the -1 */
+ if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
+ return FALSE;
+ }
+ lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
g_free (lower);
}
- if (key && strncmp (key, "null", 4) != 0) {
- if (!parse_public_key (key, &pkey)) {
+ if (key) {
+ if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) {
mono_assembly_name_free (aname);
return FALSE;
}
else
g_free (pkey);
}
-
+
return TRUE;
}
return FALSE;
}
- res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, aname, FALSE);
+ res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE);
g_strfreev (parts);
return res;
}
gboolean
-mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined)
+mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
{
gchar *dllname;
gchar *version = NULL;
gchar *culture = NULL;
gchar *token = NULL;
gchar *key = NULL;
+ gchar *retargetable = NULL;
gboolean res;
gchar *value;
gchar **parts;
gchar **tmp;
gboolean version_defined;
+ gboolean token_defined;
+ guint32 flags = 0;
if (!is_version_defined)
is_version_defined = &version_defined;
*is_version_defined = FALSE;
+ if (!is_token_defined)
+ is_token_defined = &token_defined;
+ *is_token_defined = FALSE;
- parts = tmp = g_strsplit (name, ",", 4);
+ parts = tmp = g_strsplit (name, ",", 6);
if (!tmp || !*tmp) {
g_strfreev (tmp);
return FALSE;
if (!g_ascii_strncasecmp (value, "Version=", 8)) {
*is_version_defined = TRUE;
version = g_strstrip (value + 8);
+ if (strlen (version) == 0) {
+ return FALSE;
+ }
tmp++;
continue;
}
if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
culture = g_strstrip (value + 8);
+ if (strlen (culture) == 0) {
+ return FALSE;
+ }
tmp++;
continue;
}
if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
+ *is_token_defined = TRUE;
token = g_strstrip (value + 15);
+ if (strlen (token) == 0) {
+ return FALSE;
+ }
tmp++;
continue;
}
if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
key = g_strstrip (value + 10);
+ if (strlen (key) == 0) {
+ return FALSE;
+ }
tmp++;
continue;
}
-
+
+ if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) {
+ retargetable = g_strstrip (value + 13);
+ if (strlen (retargetable) == 0) {
+ return FALSE;
+ }
+ if (!g_ascii_strcasecmp (retargetable, "yes")) {
+ flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
+ } else if (g_ascii_strcasecmp (retargetable, "no")) {
+ return FALSE;
+ }
+ tmp++;
+ continue;
+ }
+
+ if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
+ /* this is ignored for now, until we can change MonoAssemblyName */
+ tmp++;
+ continue;
+ }
+
g_strfreev (parts);
return FALSE;
}
- res = build_assembly_name (dllname, version, culture, token, key, aname, save_public_key);
+ /* if retargetable flag is set, then we must have a fully qualified name */
+ if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
+ return FALSE;
+ }
+
+ res = build_assembly_name (dllname, version, culture, token, key, flags,
+ aname, save_public_key);
g_strfreev (parts);
return res;
}
/**
-* mono_assembly_name_parse:
-* @name: name to parse
-* @aname: the destination assembly name
-*
-* Parses an assembly qualified type name and assigns the name,
-* version, culture and token to the provided assembly name object.
-*
-* Returns: true if the name could be parsed.
-*/
+ * mono_assembly_name_parse:
+ * @name: name to parse
+ * @aname: the destination assembly name
+ *
+ * Parses an assembly qualified type name and assigns the name,
+ * version, culture and token to the provided assembly name object.
+ *
+ * Returns: true if the name could be parsed.
+ */
gboolean
mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
{
- return mono_assembly_name_parse_full (name, aname, FALSE, NULL);
+ return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
}
static MonoAssembly*
while ((direntry = g_dir_read_name (dirhandle))) {
gboolean match = TRUE;
- parse_assembly_directory_name (aname->name, direntry, &gac_aname);
+ if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
+ continue;
if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
match = FALSE;
if (match && strlen ((char*)aname->public_key_token) > 0 &&
- strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
+ !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
match = FALSE;
if (match) {
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);
gchar *name, *version, *culture, *fullpath, *subpath;
gint32 len;
gchar **paths;
+ char *pubtok;
if (aname->public_key_token [0] == 0) {
return NULL;
culture = g_strdup ("");
}
+ pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
aname->minor, aname->build, aname->revision,
- culture, aname->public_key_token);
+ culture, pubtok);
+ g_free (pubtok);
subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
g_free (name);
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)
+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;