X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Floader.c;h=fa9db19419fbb778e8d1f401cd93f46c3e9eaf03;hb=8a764ef32a6dd6d465d916dd7166a0dcfd3d4a7b;hp=1778abc309eb499e880f9087e4d7c7bd4a677ced;hpb=5980d617f27d174552860b89f56612474ffa4b6b;p=mono.git diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 1778abc309e..fa9db19419f 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -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,18 +35,25 @@ #include #include #include +#include #include #include #include +#include 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; +/* Statistics */ +static guint32 inflated_signatures_size; /* * This TLS variable contains the last type load error encountered by the loader. @@ -63,6 +70,9 @@ mono_loader_init () loader_error_thread_id = TlsAlloc (); + mono_counters_register ("Inflated signatures size", + MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_signatures_size); + inited = TRUE; } } @@ -339,6 +349,48 @@ mono_loader_error_prepare_exception (MonoLoaderError *error) return ex; } +/* + * find_cached_memberref_sig: + * + * Return a cached copy of the memberref signature identified by SIG_IDX. + * We use a gpointer since the cache stores both MonoTypes and MonoMethodSignatures. + * A cache is needed since the type/signature parsing routines allocate everything + * from a mempool, so without a cache, multiple requests for the same signature would + * lead to unbounded memory growth. For normal methods/fields this is not a problem + * since the resulting methods/fields are cached, but inflated methods/fields cannot + * be cached. + * LOCKING: Acquires the loader lock. + */ +static gpointer +find_cached_memberref_sig (MonoImage *image, guint32 sig_idx) +{ + gpointer res; + + mono_loader_lock (); + res = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx)); + mono_loader_unlock (); + + return res; +} + +static gpointer +cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig) +{ + gpointer prev_sig; + + mono_loader_lock (); + prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx)); + if (prev_sig) { + /* Somebody got in before us */ + sig = prev_sig; + } + else + g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (sig_idx), sig); + mono_loader_unlock (); + + return sig; +} + static MonoClassField* field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, MonoGenericContext *context) @@ -367,7 +419,14 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, mono_loader_set_error_bad_image (g_strdup_printf ("Bad field signature class token %08x field name %s token %08x", class, fname, token)); return NULL; } - sig_type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr); + /* FIXME: This needs a cache, especially for generic instances, since + * mono_metadata_parse_type () allocates everything from a mempool. + */ + sig_type = find_cached_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE]); + if (!sig_type) { + sig_type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr); + sig_type = cache_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE], sig_type); + } switch (class) { case MONO_MEMBERREF_PARENT_TYPEDEF: @@ -503,14 +562,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]); + + 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 (in_class); - for (i = 0; i < in_class->method.count; ++i) { - MonoMethod *m = in_class->methods [i]; + 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 +609,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 +644,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); @@ -647,12 +730,9 @@ inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context) res->clauses = g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses); for (i = 0; i < header->num_clauses; ++i) { MonoExceptionClause *clause = &res->clauses [i]; - MonoType *t; if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE) continue; - t = mono_class_inflate_generic_type (&clause->data.catch_class->byval_arg, context); - clause->data.catch_class = mono_class_from_mono_type (t); - mono_metadata_free_type (t); + clause->data.catch_class = mono_class_inflate_generic_class (clause->data.catch_class, context); } } return res; @@ -666,8 +746,9 @@ mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 to { int table = mono_metadata_token_table (token); int idx = mono_metadata_token_index (token); + int sig_idx; guint32 cols [MONO_MEMBERREF_SIZE]; - MonoMethodSignature *sig, *prev_sig; + MonoMethodSignature *sig; const char *ptr; /* !table is for wrappers: we should really assign their own token to them */ @@ -689,25 +770,16 @@ mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 to /* FIXME: This might be incorrect for vararg methods */ return mono_method_signature (method); - mono_loader_lock (); - sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token)); - mono_loader_unlock (); - if (!sig) { - mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE); + mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE); + sig_idx = cols [MONO_MEMBERREF_SIGNATURE]; - ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]); + sig = find_cached_memberref_sig (image, sig_idx); + if (!sig) { + ptr = mono_metadata_blob_heap (image, sig_idx); mono_metadata_decode_blob_size (ptr, &ptr); sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL); - mono_loader_lock (); - prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (token)); - if (prev_sig) { - /* Somebody got in before us */ - sig = prev_sig; - } - else - g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (token), sig); - mono_loader_unlock (); + sig = cache_memberref_sig (image, sig_idx, sig); } if (context) { @@ -718,6 +790,8 @@ mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 to cached = mono_metadata_get_inflated_signature (sig, context); if (cached != sig) mono_metadata_free_inflated_signature (sig); + else + inflated_signatures_size += mono_metadata_signature_size (cached); sig = cached; } @@ -731,10 +805,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) @@ -751,7 +828,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp MonoMethod *method = NULL; MonoTableInfo *tables = image->tables; guint32 cols[6]; - guint32 nindex, class; + guint32 nindex, class, sig_idx; const char *mname; MonoMethodSignature *sig; const char *ptr; @@ -821,12 +898,19 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp g_assert (klass); mono_class_init (klass); - ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]); + sig_idx = cols [MONO_MEMBERREF_SIGNATURE]; + + ptr = mono_metadata_blob_heap (image, sig_idx); mono_metadata_decode_blob_size (ptr, &ptr); - sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL); - if (sig == NULL) - return NULL; + sig = find_cached_memberref_sig (image, sig_idx); + if (!sig) { + sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL); + if (sig == NULL) + return NULL; + + sig = cache_memberref_sig (image, sig_idx, sig); + } switch (class) { case MONO_MEMBERREF_PARENT_TYPEREF: @@ -847,7 +931,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; @@ -876,7 +960,6 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp g_free (msig); g_free (class_name); } - mono_metadata_free_method_signature (sig); return method; } @@ -1332,7 +1415,7 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, MonoTableInfo *tables = image->tables; MonoGenericContainer *generic_container = NULL, *container = NULL; const char *sig = NULL; - int size, i; + int size; guint32 cols [MONO_TYPEDEF_SIZE]; if (image->dynamic) { @@ -1397,9 +1480,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, mono_metadata_load_generic_param_constraints (image, token, generic_container); - for (i = 0; i < generic_container->type_argc; i++) - mono_class_from_generic_parameter (&generic_container->type_params [i], image, TRUE); - container = generic_container; } @@ -1593,6 +1673,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 (); @@ -1901,6 +1983,9 @@ mono_method_signature (MonoMethod *m) /* the lock is recursive */ signature = mono_method_signature (imethod->declaring); signature = inflate_generic_signature (imethod->declaring->klass->image, signature, mono_method_get_context (m)); + + inflated_signatures_size += mono_metadata_signature_size (signature); + mono_memory_barrier (); m->signature = signature; mono_loader_unlock (); @@ -2023,6 +2108,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 +2120,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 +2150,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;