New test.
[mono.git] / mono / metadata / loader.c
index b8d5a0d6e51f11b0fc961a99e861ad47b35c277a..7737080a2e12244358ea07b7e9bfc7a898520d2c 100644 (file)
@@ -7,6 +7,7 @@
  *   Patrik Torstensson (patrik.torstensson@labs2.com)
  *
  * (C) 2001 Ximian, Inc.
+ * Copyright (C) 2002-2006 Novell, Inc.
  *
  * This file is used by the interpreter and the JIT engine to locate
  * assemblies.  Used to load AssemblyRef and later to resolve various
@@ -33,6 +34,7 @@
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/reflection.h>
+#include <mono/metadata/profiler.h>
 #include <mono/utils/mono-logger.h>
 #include <mono/metadata/exception.h>
 
@@ -63,7 +65,7 @@ mono_loader_cleanup (void)
 {
        TlsFree (loader_error_thread_id);
 
-       DeleteCriticalSection (&loader_mutex);
+       /*DeleteCriticalSection (&loader_mutex);*/
 }
 
 /*
@@ -84,6 +86,36 @@ set_loader_error (MonoLoaderError *error)
        TlsSetValue (loader_error_thread_id, error);
 }
 
+/**
+ * mono_loader_set_error_assembly_load:
+ *
+ * Set the loader error for this thread. 
+ */
+void
+mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only)
+{
+       MonoLoaderError *error;
+
+       if (mono_loader_get_last_error ()) 
+               return;
+
+       error = g_new0 (MonoLoaderError, 1);
+       error->kind = MONO_LOADER_ERROR_ASSEMBLY;
+       error->assembly_name = g_strdup (assembly_name);
+       error->ref_only = ref_only;
+
+       /* 
+        * This is not strictly needed, but some (most) of the loader code still
+        * can't deal with load errors, and this message is more helpful than an
+        * assert.
+        */
+       if (ref_only)
+               g_warning ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", assembly_name);
+       else
+               g_warning ("Could not load file or assembly '%s' or one of its dependencies.", assembly_name);
+
+       set_loader_error (error);
+}
 
 /**
  * mono_loader_set_error_type_load:
@@ -181,11 +213,13 @@ mono_loader_clear_error (void)
 {
        MonoLoaderError *ex = (MonoLoaderError*)TlsGetValue (loader_error_thread_id);
 
+       if (ex) {
         g_free (ex->class_name);
         g_free (ex->assembly_name);
-       g_free (ex);
+               g_free (ex);
        
-       TlsSetValue (loader_error_thread_id, NULL);
+               TlsSetValue (loader_error_thread_id, NULL);
+       }
 }
 
 /**
@@ -199,10 +233,10 @@ mono_loader_clear_error (void)
 MonoException *
 mono_loader_error_prepare_exception (MonoLoaderError *error)
 {
-        MonoException *ex = NULL;
+       MonoException *ex = NULL;
 
-        switch (error->kind) {
-        case MONO_LOADER_ERROR_TYPE: {
+       switch (error->kind) {
+       case MONO_LOADER_ERROR_TYPE: {
                char *cname = g_strdup (error->class_name);
                char *aname = g_strdup (error->assembly_name);
                MonoString *class_name;
@@ -216,7 +250,7 @@ mono_loader_error_prepare_exception (MonoLoaderError *error)
                g_free (aname);
                 break;
         }
-        case MONO_LOADER_ERROR_METHOD: {
+       case MONO_LOADER_ERROR_METHOD: {
                char *cname = g_strdup (error->class_name);
                char *aname = g_strdup (error->member_name);
                
@@ -227,7 +261,7 @@ mono_loader_error_prepare_exception (MonoLoaderError *error)
                break;
        }
                
-        case MONO_LOADER_ERROR_FIELD: {
+       case MONO_LOADER_ERROR_FIELD: {
                char *cnspace = g_strdup (*error->klass->name_space ? error->klass->name_space : "");
                char *cname = g_strdup (error->klass->name);
                char *cmembername = g_strdup (error->member_name);
@@ -243,11 +277,26 @@ mono_loader_error_prepare_exception (MonoLoaderError *error)
                g_free (cnspace);
                 break;
         }
-        default:
-                g_assert_not_reached ();
-        }
+       
+       case MONO_LOADER_ERROR_ASSEMBLY: {
+               char *msg;
+
+               if (error->ref_only)
+                       msg = g_strdup_printf ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", error->assembly_name);
+               else
+                       msg = g_strdup_printf ("Could not load file or assembly '%s' or one of its dependencies.", error->assembly_name);
+
+               ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), error->assembly_name));
+               mono_loader_clear_error ();
+               g_free (msg);
+               break;
+       }
+       
+       default:
+               g_assert_not_reached ();
+       }
 
-        return ex;
+       return ex;
 }
 
 static MonoClassField*
@@ -1262,6 +1311,8 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
        else
                result = (MonoMethod *)mono_mempool_alloc0 (image->mempool, sizeof (MonoMethodNormal));
 
+       mono_stats.method_count ++;
+
        if (!klass) {
                guint32 type = mono_metadata_typedef_from_method (image, token);
                klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
@@ -1361,10 +1412,14 @@ mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
  * mono_get_method_constrained:
  *
  * This is used when JITing the `constrained.' opcode.
+ *
+ * This returns two values: the contrained method, which has been inflated
+ * as the function return value;   And the original CIL-stream method as
+ * declared in cil_method.  The later is used for verification.
  */
 MonoMethod *
 mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
-                            MonoGenericContext *context)
+                            MonoGenericContext *context, MonoMethod **cil_method)
 {
        MonoMethod *method, *result;
        MonoClass *ic = NULL;
@@ -1373,14 +1428,14 @@ mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constra
 
        mono_loader_lock ();
 
-       method = mono_get_method_from_token (image, token, NULL, context);
-       if (!method) {
+       *cil_method = mono_get_method_from_token (image, token, NULL, context);
+       if (!*cil_method) {
                mono_loader_unlock ();
                return NULL;
        }
 
        mono_class_init (constrained_class);
-       method = mono_get_inflated_method (method);
+       method = mono_get_inflated_method (*cil_method);
        sig = mono_method_signature (method);
 
        if (method->is_inflated && sig->generic_param_count) {
@@ -1415,6 +1470,9 @@ mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constra
 void
 mono_free_method  (MonoMethod *method)
 {
+       if (mono_profiler_get_events () != MONO_PROFILE_NONE)
+               return;
+       
        if (method->signature) {
                /* 
                 * FIXME: This causes crashes because the types inside signatures and
@@ -1692,6 +1750,11 @@ mono_loader_unlock (void)
        LeaveCriticalSection (&loader_mutex);
 }
 
+/**
+ * mono_method_signature:
+ *
+ * Return the signature of the method M. On failure, returns NULL.
+ */
 MonoMethodSignature*
 mono_method_signature (MonoMethod *m)
 {
@@ -1754,6 +1817,10 @@ mono_method_signature (MonoMethod *m)
                size = mono_metadata_decode_blob_size (sig, &sig_body);
 
                m->signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL);
+               if (!m->signature) {
+                       mono_loader_unlock ();
+                       return NULL;
+               }
 
                if (can_cache_signature)
                        g_hash_table_insert (img->method_signatures, (gpointer)sig, m->signature);