2009-02-04 Marek Habersack <mhabersack@novell.com>
[mono.git] / mono / metadata / loader.c
index 1778abc309eb499e880f9087e4d7c7bd4a677ced..5d0cf48e9c3c9ed301dc46ae35b83b3ea2a35ad5 100644 (file)
@@ -6,8 +6,8 @@
  *   Miguel de Icaza (miguel@ximian.com)
  *   Patrik Torstensson (patrik.torstensson@labs2.com)
  *
- * (C) 2001 Ximian, Inc.
- * Copyright (C) 2002-2006 Novell, Inc.
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  *
  * This file is used by the interpreter and the JIT engine to locate
  * assemblies.  Used to load AssemblyRef and later to resolve various
@@ -35,6 +35,7 @@
 #include <mono/metadata/profiler.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/exception.h>
+#include <mono/metadata/marshal.h>
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-dl.h>
 #include <mono/utils/mono-membar.h>
@@ -44,6 +45,9 @@ MonoDefaults mono_defaults;
 /*
  * This lock protects the hash tables inside MonoImage used by the metadata 
  * loading functions in class.c and loader.c.
+ *
+ * See domain-internals.h for locking policy in combination with the
+ * domain lock.
  */
 static CRITICAL_SECTION loader_mutex;
 
@@ -503,14 +507,38 @@ mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSigna
 }
 
 static MonoMethod *
-find_method_in_class (MonoClass *in_class, const char *name, const char *qname, const char *fqname,
+find_method_in_class (MonoClass *klass, const char *name, const char *qname, const char *fqname,
                      MonoMethodSignature *sig, MonoClass *from_class)
 {
-       int i;
+       int i;
+
+       /* Search directly in the metadata to avoid calling setup_methods () */
+
+       /* FIXME: !from_class->generic_class condition causes test failures. */
+       if (klass->type_token && !klass->image->dynamic && !klass->methods && !klass->rank && klass == from_class && !from_class->generic_class) {
+               for (i = 0; i < klass->method.count; ++i) {
+                       guint32 cols [MONO_METHOD_SIZE];
+                       MonoMethod *method;
+                       const char *m_name;
+
+                       mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
+
+                       m_name = mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]);
 
-       mono_class_setup_methods (in_class);
-       for (i = 0; i < in_class->method.count; ++i) {
-               MonoMethod *m = in_class->methods [i];
+                       if (!((fqname && !strcmp (m_name, fqname)) ||
+                                 (qname && !strcmp (m_name, qname)) ||
+                                 (name && !strcmp (m_name, name))))
+                               continue;
+
+                       method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass);
+                       if (method && (sig->call_convention != MONO_CALL_VARARG) && mono_metadata_signature_equal (sig, mono_method_signature (method)))
+                               return method;
+               }
+       }
+
+       mono_class_setup_methods (klass);
+       for (i = 0; i < klass->method.count; ++i) {
+               MonoMethod *m = klass->methods [i];
 
                if (!((fqname && !strcmp (m->name, fqname)) ||
                      (qname && !strcmp (m->name, qname)) ||
@@ -526,7 +554,7 @@ find_method_in_class (MonoClass *in_class, const char *name, const char *qname,
                }
        }
 
-       if (i < in_class->method.count)
+       if (i < klass->method.count)
                return mono_class_get_method_by_index (from_class, i);
        return NULL;
 }
@@ -561,10 +589,10 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig
                if (name [0] == '.' && (!strcmp (name, ".ctor") || !strcmp (name, ".cctor")))
                        break;
 
-               g_assert (from_class->interface_count == in_class->interface_count);
-               for (i = 0; i < in_class->interface_count; i++) {
-                       MonoClass *in_ic = in_class->interfaces [i];
-                       MonoClass *from_ic = from_class->interfaces [i];
+               g_assert (from_class->interface_offsets_count == in_class->interface_offsets_count);
+               for (i = 0; i < in_class->interface_offsets_count; i++) {
+                       MonoClass *in_ic = in_class->interfaces_packed [i];
+                       MonoClass *from_ic = from_class->interfaces_packed [i];
                        char *ic_qname, *ic_fqname, *ic_class_name;
                        
                        ic_class_name = mono_type_get_name_full (&in_ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
@@ -731,10 +759,13 @@ mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
 }
 
 /* this is only for the typespec array methods */
-static MonoMethod*
-search_in_array_class (MonoClass *klass, const char *name, MonoMethodSignature *sig)
+MonoMethod*
+mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMethodSignature *sig)
 {
        int i;
+
+       mono_class_setup_methods (klass);
+
        for (i = 0; i < klass->method.count; ++i) {
                MonoMethod *method = klass->methods [i];
                if (strcmp (method->name, name) == 0 && sig->param_count == method->signature->param_count)
@@ -847,7 +878,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp
                }
 
                /* we're an array and we created these methods already in klass in mono_class_init () */
-               result = search_in_array_class (klass, mname, sig);
+               result = mono_method_search_in_array_class (klass, mname, sig);
                if (result)
                        return result;
 
@@ -1593,6 +1624,8 @@ mono_free_method  (MonoMethod *method)
                MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
                int i;
 
+               mono_marshal_free_dynamic_wrappers (method);
+
                mono_loader_lock ();
                mono_property_hash_remove_object (method->klass->image->property_hash, method);
                mono_loader_unlock ();
@@ -2023,6 +2056,7 @@ mono_method_get_header (MonoMethod *method)
        MonoImage* img;
        gpointer loc;
        MonoMethodNormal* mn = (MonoMethodNormal*) method;
+       MonoMethodHeader *header;
 
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
                return NULL;
@@ -2034,23 +2068,28 @@ mono_method_get_header (MonoMethod *method)
 #endif
                return mn->header;
 
-       mono_loader_lock ();
-
-       if (mn->header) {
-               mono_loader_unlock ();
-               return mn->header;
-       }
-
        if (method->is_inflated) {
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
                MonoMethodHeader *header;
-               /* the lock is recursive */
+
                header = mono_method_get_header (imethod->declaring);
+
+               mono_loader_lock ();
+
+               if (mn->header) {
+                       mono_loader_unlock ();
+                       return mn->header;
+               }
+
                mn->header = inflate_generic_header (header, mono_method_get_context (method));
                mono_loader_unlock ();
                return mn->header;
        }
 
+       /* 
+        * Do most of the work outside the loader lock, to avoid assembly loader hook
+        * deadlocks.
+        */
        g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD);
        idx = mono_metadata_token_index (method->token);
        img = method->klass->image;
@@ -2059,7 +2098,19 @@ mono_method_get_header (MonoMethod *method)
 
        g_assert (loc);
 
-       mn->header = mono_metadata_parse_mh_full (img, mono_method_get_generic_container (method), loc);
+       header = mono_metadata_parse_mh_full (img, mono_method_get_generic_container (method), loc);
+
+       mono_loader_lock ();
+
+       if (mn->header) {
+               /* header is allocated from the image mempool, no need to free it */
+               mono_loader_unlock ();
+               return mn->header;
+       }
+
+       mono_memory_barrier ();
+
+       mn->header = header;
 
        mono_loader_unlock ();
        return mn->header;