#include <mono/metadata/profiler-private.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/marshal.h>
+#include <mono/metadata/lock-tracer.h>
+#include <mono/metadata/verify-internals.h>
#include <mono/utils/mono-logger.h>
#include <mono/utils/mono-dl.h>
#include <mono/utils/mono-membar.h>
/* Statistics */
static guint32 inflated_signatures_size;
+static guint32 memberref_sig_cache_size;
/*
* This TLS variable contains the last type load error encountered by the loader.
mono_counters_register ("Inflated signatures size",
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_signatures_size);
+ mono_counters_register ("Memberref signature cache size",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &memberref_sig_cache_size);
inited = TRUE;
}
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);
+ /* An approximation based on glib 2.18 */
+ memberref_sig_cache_size += sizeof (gpointer) * 4;
+ }
+
+ mono_loader_unlock ();
+
+ return sig;
+}
+
static MonoClassField*
field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
MonoGenericContext *context)
fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
+ if (!mono_verifier_verify_memberref_signature (image, cols [MONO_MEMBERREF_SIGNATURE], NULL)) {
+ 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;
+ }
+
ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
mono_metadata_decode_blob_size (ptr, &ptr);
/* we may want to check the signature here... */
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:
}
mono_loader_lock ();
- if (field && !field->parent->generic_class && !field->parent->generic_container)
+ if (field && field->parent && !field->parent->generic_class && !field->parent->generic_container)
g_hash_table_insert (image->field_cache, GUINT_TO_POINTER (token), field);
mono_loader_unlock ();
return field;
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;
{
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 */
/* 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 ();
+ mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
+ sig_idx = cols [MONO_MEMBERREF_SIGNATURE];
+
+ sig = find_cached_memberref_sig (image, sig_idx);
if (!sig) {
- mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
+ if (!mono_verifier_verify_memberref_signature (image, sig_idx, NULL)) {
+ guint32 class = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
+ const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
+
+ mono_loader_set_error_bad_image (g_strdup_printf ("Bad method signature class token %08x field name %s token %08x", class, fname, token));
+ return NULL;
+ }
- ptr = mono_metadata_blob_heap (image, 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);
- 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) {
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;
g_assert (klass);
mono_class_init (klass);
- ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
- mono_metadata_decode_blob_size (ptr, &ptr);
+ sig_idx = cols [MONO_MEMBERREF_SIGNATURE];
- sig = mono_metadata_parse_method_signature (image, 0, ptr, NULL);
- if (sig == NULL)
+ if (!mono_verifier_verify_memberref_signature (image, sig_idx, NULL)) {
+ mono_loader_set_error_method_load (klass->name, mname);
return NULL;
+ }
+
+ ptr = mono_metadata_blob_heap (image, sig_idx);
+ mono_metadata_decode_blob_size (ptr, &ptr);
+
+ 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:
case MONO_MEMBERREF_PARENT_TYPESPEC: {
MonoType *type;
- MonoMethod *result;
type = &klass->byval_arg;
}
/* we're an array and we created these methods already in klass in mono_class_init () */
- result = mono_method_search_in_array_class (klass, mname, sig);
- if (result)
- return result;
-
- g_assert_not_reached ();
+ method = mono_method_search_in_array_class (klass, mname, sig);
break;
}
default:
g_free (msig);
g_free (class_name);
}
- mono_metadata_free_method_signature (sig);
return method;
}
token = cols [MONO_METHODSPEC_METHOD];
nindex = token >> MONO_METHODDEFORREF_BITS;
+ if (!mono_verifier_verify_methodspec_signature (image, cols [MONO_METHODSPEC_SIGNATURE], NULL))
+ return NULL;
+
ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
mono_metadata_decode_value (ptr, &ptr);
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) {
result->token = token;
result->name = mono_metadata_string_heap (image, cols [3]);
+ if (!sig) /* already taken from the methodref */
+ sig = mono_metadata_blob_heap (image, cols [4]);
+ size = mono_metadata_decode_blob_size (sig, &sig);
+
container = klass->generic_container;
- generic_container = mono_metadata_load_generic_params (image, token, container);
+
+ /*
+ * load_generic_params does a binary search so only call it if the method
+ * is generic.
+ */
+ if (*sig & 0x10)
+ generic_container = mono_metadata_load_generic_params (image, token, container);
if (generic_container) {
result->is_generic = TRUE;
generic_container->owner.method = result;
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;
}
-
- if (!sig) /* already taken from the methodref */
- sig = mono_metadata_blob_heap (image, cols [4]);
- size = mono_metadata_decode_blob_size (sig, &sig);
-
if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
result->string_ctor = 1;
/* We do everything inside the lock to prevent creation races */
- mono_loader_lock ();
+ mono_image_lock (image);
if (mono_metadata_token_table (token) == MONO_TABLE_METHOD) {
if (!image->method_cache)
image->methodref_cache = g_hash_table_new (NULL, NULL);
result = g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));
}
- if (result) {
- mono_loader_unlock ();
+ mono_image_unlock (image);
+
+ if (result)
return result;
- }
result = mono_get_method_from_token (image, token, klass, context, &used_context);
+ if (!result)
+ return NULL;
- //printf ("GET: %s\n", mono_method_full_name (result, TRUE));
-
-#if 0
- g_message (G_STRLOC ": %s - %d - %d", mono_method_full_name (result, TRUE),
- result->is_inflated, used_context);
-#endif
+ mono_image_lock (image);
+ if (!used_context && !result->is_inflated) {
+ MonoMethod *result2;
+ if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
+ result2 = mono_value_hash_table_lookup (image->method_cache, GINT_TO_POINTER (token));
+ else
+ result2 = g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));
- /*
- * `used_context' specifies whether or not mono_get_method_from_token() actually
- * used the `context' to get the method. See bug #80969.
- */
+ if (result2) {
+ mono_image_unlock (image);
+ return result2;
+ }
- if (!used_context && !(result && result->is_inflated) && result) {
- if (mono_metadata_token_table (token) == MONO_TABLE_METHOD) {
+ if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
mono_value_hash_table_insert (image->method_cache, GINT_TO_POINTER (token), result);
- } else {
+ else
g_hash_table_insert (image->methodref_cache, GINT_TO_POINTER (token), result);
- }
}
- mono_loader_unlock ();
+ mono_image_unlock (image);
return result;
}
mono_marshal_free_dynamic_wrappers (method);
- mono_loader_lock ();
- mono_property_hash_remove_object (method->klass->image->property_hash, method);
- mono_loader_unlock ();
+ mono_image_property_remove (method->klass->image, method);
g_free ((char*)method->name);
if (mw->method.header) {
g_assert (method != NULL);
g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
+ if (method->is_inflated)
+ method = ((MonoMethodInflated *) method)->declaring;
data = ((MonoMethodWrapper *)method)->method_data;
g_assert (data != NULL);
g_assert (id <= GPOINTER_TO_UINT (*data));
return m;
}
+/**
+ * mono_loader_lock:
+ *
+ * See docs/thread-safety.txt for the locking strategy.
+ */
void
mono_loader_lock (void)
{
- EnterCriticalSection (&loader_mutex);
+ mono_locks_acquire (&loader_mutex, LoaderLock);
}
void
mono_loader_unlock (void)
{
- LeaveCriticalSection (&loader_mutex);
+ mono_locks_release (&loader_mutex, LoaderLock);
}
/**
MonoGenericContainer *container;
MonoMethodSignature *signature = NULL;
int *pattrs;
+ guint32 sig_offset;
/* We need memory barriers below because of the double-checked locking pattern */
idx = mono_metadata_token_index (m->token);
img = m->klass->image;
- sig = mono_metadata_blob_heap (img, mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
+ sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
g_assert (!m->klass->generic_class);
container = mono_method_get_generic_container (m);
if (!signature) {
const char *sig_body;
+ /*TODO we should cache the failure result somewhere*/
+ if (!mono_verifier_verify_method_signature (img, sig_offset, NULL)) {
+ mono_loader_unlock ();
+ return NULL;
+ }
size = mono_metadata_decode_blob_size (sig, &sig_body);
g_assert (loc);
+ if (!mono_verifier_verify_method_header (img, rva, NULL))
+ return NULL;
+
header = mono_metadata_parse_mh_full (img, mono_method_get_generic_container (method), loc);
mono_loader_lock ();