[interp] Small fixes (#11667)
[mono-project.git] / mono / metadata / loader.c
blob81146341b123163c8de69cce6d74ef4c7e3b8d2e
1 /**
2 * \file
3 * Image Loader
5 * Authors:
6 * Paolo Molaro (lupus@ximian.com)
7 * Miguel de Icaza (miguel@ximian.com)
8 * Patrik Torstensson (patrik.torstensson@labs2.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
14 * This file is used by the interpreter and the JIT engine to locate
15 * assemblies. Used to load AssemblyRef and later to resolve various
16 * kinds of `Refs'.
18 * TODO:
19 * This should keep track of the assembly versions that we are loading.
21 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #include <config.h>
24 #include <glib.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <mono/metadata/metadata.h>
29 #include <mono/metadata/image.h>
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/tokentype.h>
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/metadata-internals.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/class-init.h>
36 #include <mono/metadata/class-internals.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/metadata/reflection.h>
39 #include <mono/metadata/profiler-private.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/marshal.h>
42 #include <mono/metadata/lock-tracer.h>
43 #include <mono/metadata/verify-internals.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/utils/mono-logger-internals.h>
46 #include <mono/utils/mono-dl.h>
47 #include <mono/utils/mono-membar.h>
48 #include <mono/utils/mono-counters.h>
49 #include <mono/utils/mono-error-internals.h>
50 #include <mono/utils/mono-tls.h>
51 #include <mono/utils/mono-path.h>
53 MonoDefaults mono_defaults;
56 * This lock protects the hash tables inside MonoImage used by the metadata
57 * loading functions in class.c and loader.c.
59 * See domain-internals.h for locking policy in combination with the
60 * domain lock.
62 static MonoCoopMutex loader_mutex;
63 static mono_mutex_t global_loader_data_mutex;
64 static gboolean loader_lock_inited;
66 /* Statistics */
67 static gint32 inflated_signatures_size;
68 static gint32 memberref_sig_cache_size;
69 static gint32 methods_size;
70 static gint32 signatures_size;
73 * This TLS variable holds how many times the current thread has acquired the loader
74 * lock.
76 static MonoNativeTlsKey loader_lock_nest_id;
78 static void dllmap_cleanup (void);
79 static void cached_module_cleanup(void);
81 static void dllmap_insert_global (const char *dll, const char *func, const char *tdll, const char *tfunc);
82 static void dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfun);
85 /* Class lazy loading functions */
86 GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
88 static void
89 global_loader_data_lock (void)
91 mono_locks_os_acquire (&global_loader_data_mutex, LoaderGlobalDataLock);
94 static void
95 global_loader_data_unlock (void)
97 mono_locks_os_release (&global_loader_data_mutex, LoaderGlobalDataLock);
100 void
101 mono_loader_init ()
103 static gboolean inited;
105 if (!inited) {
106 mono_coop_mutex_init_recursive (&loader_mutex);
107 mono_os_mutex_init_recursive (&global_loader_data_mutex);
108 loader_lock_inited = TRUE;
110 mono_native_tls_alloc (&loader_lock_nest_id, NULL);
112 mono_counters_init ();
113 mono_counters_register ("Inflated signatures size",
114 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_signatures_size);
115 mono_counters_register ("Memberref signature cache size",
116 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &memberref_sig_cache_size);
117 mono_counters_register ("MonoMethod size",
118 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &methods_size);
119 mono_counters_register ("MonoMethodSignature size",
120 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &signatures_size);
122 inited = TRUE;
126 void
127 mono_loader_cleanup (void)
129 dllmap_cleanup ();
130 cached_module_cleanup ();
132 mono_native_tls_free (loader_lock_nest_id);
134 mono_coop_mutex_destroy (&loader_mutex);
135 mono_os_mutex_destroy (&global_loader_data_mutex);
136 loader_lock_inited = FALSE;
140 * find_cached_memberref_sig:
142 * Return a cached copy of the memberref signature identified by SIG_IDX.
143 * We use a gpointer since the cache stores both MonoTypes and MonoMethodSignatures.
144 * A cache is needed since the type/signature parsing routines allocate everything
145 * from a mempool, so without a cache, multiple requests for the same signature would
146 * lead to unbounded memory growth. For normal methods/fields this is not a problem
147 * since the resulting methods/fields are cached, but inflated methods/fields cannot
148 * be cached.
149 * LOCKING: Acquires the loader lock.
151 static gpointer
152 find_cached_memberref_sig (MonoImage *image, guint32 sig_idx)
154 gpointer res;
156 mono_image_lock (image);
157 res = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
158 mono_image_unlock (image);
160 return res;
163 static gpointer
164 cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig)
166 gpointer prev_sig;
168 mono_image_lock (image);
169 prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
170 if (prev_sig) {
171 /* Somebody got in before us */
172 sig = prev_sig;
174 else {
175 g_hash_table_insert (image->memberref_signatures, GUINT_TO_POINTER (sig_idx), sig);
176 /* An approximation based on glib 2.18 */
177 mono_atomic_fetch_add_i32 (&memberref_sig_cache_size, sizeof (gpointer) * 4);
179 mono_image_unlock (image);
181 return sig;
184 static MonoClassField*
185 field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
186 MonoGenericContext *context, MonoError *error)
188 MonoClass *klass = NULL;
189 MonoClassField *field;
190 MonoTableInfo *tables = image->tables;
191 MonoType *sig_type;
192 guint32 cols[6];
193 guint32 nindex, class_index;
194 const char *fname;
195 const char *ptr;
196 guint32 idx = mono_metadata_token_index (token);
198 error_init (error);
200 mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
201 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
202 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
204 fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
206 if (!mono_verifier_verify_memberref_field_signature (image, cols [MONO_MEMBERREF_SIGNATURE], error))
207 return NULL;
209 switch (class_index) {
210 case MONO_MEMBERREF_PARENT_TYPEDEF:
211 klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, error);
212 break;
213 case MONO_MEMBERREF_PARENT_TYPEREF:
214 klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
215 break;
216 case MONO_MEMBERREF_PARENT_TYPESPEC:
217 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, context, error);
218 break;
219 default:
220 mono_error_set_bad_image (error, image, "Bad field field '%u' signature 0x%08x", class_index, token);
223 if (!klass)
224 return NULL;
226 ptr = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
227 mono_metadata_decode_blob_size (ptr, &ptr);
228 /* we may want to check the signature here... */
230 if (*ptr++ != 0x6) {
231 mono_error_set_field_missing (error, klass, fname, NULL, "Bad field signature class token %08x field token %08x", class_index, token);
232 return NULL;
235 /* FIXME: This needs a cache, especially for generic instances, since
236 * we ask mono_metadata_parse_type_checked () to allocates everything from a mempool.
237 * FIXME part2, mono_metadata_parse_type_checked actually allows for a transient type instead.
238 * FIXME part3, transient types are not 100% transient, so we need to take care of that first.
240 sig_type = (MonoType *)find_cached_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE]);
241 if (!sig_type) {
242 ERROR_DECL_VALUE (inner_error);
243 sig_type = mono_metadata_parse_type_checked (image, NULL, 0, FALSE, ptr, &ptr, &inner_error);
244 if (sig_type == NULL) {
245 mono_error_set_field_missing (error, klass, fname, NULL, "Could not parse field signature %08x due to: %s", token, mono_error_get_message (&inner_error));
246 mono_error_cleanup (&inner_error);
247 return NULL;
249 sig_type = (MonoType *)cache_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE], sig_type);
252 mono_class_init (klass); /*FIXME is this really necessary?*/
253 if (retklass)
254 *retklass = klass;
255 field = mono_class_get_field_from_name_full (klass, fname, sig_type);
257 if (!field) {
258 mono_error_set_field_missing (error, klass, fname, sig_type, "Could not find field in class");
261 return field;
265 * mono_field_from_token:
266 * \deprecated use the \c _checked variant
267 * Notes: runtime code MUST not use this function
269 MonoClassField*
270 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass, MonoGenericContext *context)
272 ERROR_DECL (error);
273 MonoClassField *res = mono_field_from_token_checked (image, token, retklass, context, error);
274 mono_error_assert_ok (error);
275 return res;
278 MonoClassField*
279 mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retklass, MonoGenericContext *context, MonoError *error)
281 MonoClass *k;
282 guint32 type;
283 MonoClassField *field;
285 error_init (error);
287 if (image_is_dynamic (image)) {
288 MonoClassField *result;
289 MonoClass *handle_class;
291 *retklass = NULL;
292 ERROR_DECL_VALUE (inner_error);
293 result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, &inner_error);
294 mono_error_cleanup (&inner_error);
295 // This checks the memberref type as well
296 if (!result || handle_class != mono_defaults.fieldhandle_class) {
297 mono_error_set_bad_image (error, image, "Bad field token 0x%08x", token);
298 return NULL;
300 *retklass = result->parent;
301 return result;
304 if ((field = (MonoClassField *)mono_conc_hashtable_lookup (image->field_cache, GUINT_TO_POINTER (token)))) {
305 *retklass = field->parent;
306 return field;
309 if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
310 field = field_from_memberref (image, token, retklass, context, error);
311 } else {
312 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
313 if (!type) {
314 mono_error_set_bad_image (error, image, "Invalid field token 0x%08x", token);
315 return NULL;
317 k = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, error);
318 if (!k)
319 return NULL;
321 mono_class_init (k);
322 if (retklass)
323 *retklass = k;
324 if (mono_class_has_failure (k)) {
325 ERROR_DECL_VALUE (causedby_error);
326 error_init (&causedby_error);
327 mono_error_set_for_class_failure (&causedby_error, k);
328 mono_error_set_bad_image (error, image, "Could not resolve field token 0x%08x, due to: %s", token, mono_error_get_message (&causedby_error));
329 mono_error_cleanup (&causedby_error);
330 } else {
331 field = mono_class_get_field (k, token);
332 if (!field) {
333 mono_error_set_bad_image (error, image, "Could not resolve field token 0x%08x", token);
338 if (field && field->parent && !mono_class_is_ginst (field->parent) && !mono_class_is_gtd (field->parent)) {
339 mono_image_lock (image);
340 mono_conc_hashtable_insert (image->field_cache, GUINT_TO_POINTER (token), field);
341 mono_image_unlock (image);
344 return field;
347 static gboolean
348 mono_metadata_signature_vararg_match (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
350 int i;
352 if (sig1->hasthis != sig2->hasthis ||
353 sig1->sentinelpos != sig2->sentinelpos)
354 return FALSE;
356 for (i = 0; i < sig1->sentinelpos; i++) {
357 MonoType *p1 = sig1->params[i];
358 MonoType *p2 = sig2->params[i];
360 /*if (p1->attrs != p2->attrs)
361 return FALSE;
363 if (!mono_metadata_type_equal (p1, p2))
364 return FALSE;
367 if (!mono_metadata_type_equal (sig1->ret, sig2->ret))
368 return FALSE;
369 return TRUE;
372 static MonoMethod *
373 find_method_in_class (MonoClass *klass, const char *name, const char *qname, const char *fqname,
374 MonoMethodSignature *sig, MonoClass *from_class, MonoError *error)
376 int i;
378 /* Search directly in the metadata to avoid calling setup_methods () */
379 error_init (error);
381 MonoImage *klass_image = m_class_get_image (klass);
382 /* FIXME: !mono_class_is_ginst (from_class) condition causes test failures. */
383 if (m_class_get_type_token (klass) && !image_is_dynamic (klass_image) && !m_class_get_methods (klass) && !m_class_get_rank (klass) && klass == from_class && !mono_class_is_ginst (from_class)) {
384 int first_idx = mono_class_get_first_method_idx (klass);
385 int mcount = mono_class_get_method_count (klass);
386 for (i = 0; i < mcount; ++i) {
387 guint32 cols [MONO_METHOD_SIZE];
388 MonoMethod *method;
389 const char *m_name;
390 MonoMethodSignature *other_sig;
392 mono_metadata_decode_table_row (klass_image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
394 m_name = mono_metadata_string_heap (klass_image, cols [MONO_METHOD_NAME]);
396 if (!((fqname && !strcmp (m_name, fqname)) ||
397 (qname && !strcmp (m_name, qname)) ||
398 (name && !strcmp (m_name, name))))
399 continue;
401 method = mono_get_method_checked (klass_image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
402 if (!mono_error_ok (error)) //bail out if we hit a loader error
403 return NULL;
404 if (method) {
405 other_sig = mono_method_signature_checked (method, error);
406 if (!mono_error_ok (error)) //bail out if we hit a loader error
407 return NULL;
408 if (other_sig && (sig->call_convention != MONO_CALL_VARARG) && mono_metadata_signature_equal (sig, other_sig))
409 return method;
414 mono_class_setup_methods (klass); /* FIXME don't swallow the error here. */
416 We can't fail lookup of methods otherwise the runtime will fail with MissingMethodException instead of TypeLoadException.
417 See mono/tests/generic-type-load-exception.2.il
418 FIXME we should better report this error to the caller
420 if (!m_class_get_methods (klass) || mono_class_has_failure (klass)) {
421 ERROR_DECL (cause_error);
422 mono_error_set_for_class_failure (cause_error, klass);
423 mono_error_set_type_load_class (error, klass, "Could not find method '%s' due to a type load error: %s", name, mono_error_get_message (cause_error));
424 mono_error_cleanup (cause_error);
425 return NULL;
427 int mcount = mono_class_get_method_count (klass);
428 MonoMethod **klass_methods = m_class_get_methods (klass);
429 for (i = 0; i < mcount; ++i) {
430 MonoMethod *m = klass_methods [i];
431 MonoMethodSignature *msig;
433 /* We must cope with failing to load some of the types. */
434 if (!m)
435 continue;
437 if (!((fqname && !strcmp (m->name, fqname)) ||
438 (qname && !strcmp (m->name, qname)) ||
439 (name && !strcmp (m->name, name))))
440 continue;
441 msig = mono_method_signature_checked (m, error);
442 if (!mono_error_ok (error)) //bail out if we hit a loader error
443 return NULL;
445 if (!msig)
446 continue;
448 if (sig->call_convention == MONO_CALL_VARARG) {
449 if (mono_metadata_signature_vararg_match (sig, msig))
450 break;
451 } else {
452 if (mono_metadata_signature_equal (sig, msig))
453 break;
457 if (i < mcount)
458 return mono_class_get_method_by_index (from_class, i);
459 return NULL;
462 static MonoMethod *
463 find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSignature *sig, MonoClass *from_class, MonoError *error)
465 int i;
466 char *qname, *fqname, *class_name;
467 gboolean is_interface;
468 MonoMethod *result = NULL;
469 MonoClass *initial_class = in_class;
471 error_init (error);
472 is_interface = MONO_CLASS_IS_INTERFACE_INTERNAL (in_class);
474 if (ic) {
475 class_name = mono_type_get_name_full (m_class_get_byval_arg (ic), MONO_TYPE_NAME_FORMAT_IL);
477 qname = g_strconcat (class_name, ".", name, NULL);
478 const char *ic_name_space = m_class_get_name_space (ic);
479 if (ic_name_space && ic_name_space [0])
480 fqname = g_strconcat (ic_name_space, ".", class_name, ".", name, NULL);
481 else
482 fqname = NULL;
483 } else
484 class_name = qname = fqname = NULL;
486 while (in_class) {
487 g_assert (from_class);
488 result = find_method_in_class (in_class, name, qname, fqname, sig, from_class, error);
489 if (result || !mono_error_ok (error))
490 goto out;
492 if (name [0] == '.' && (!strcmp (name, ".ctor") || !strcmp (name, ".cctor")))
493 break;
496 * This happens when we fail to lazily load the interfaces of one of the types.
497 * On such case we can't just bail out since user code depends on us trying harder.
499 if (m_class_get_interface_offsets_count (from_class) != m_class_get_interface_offsets_count (in_class)) {
500 in_class = m_class_get_parent (in_class);
501 from_class = m_class_get_parent (from_class);
502 continue;
505 int in_class_interface_offsets_count = m_class_get_interface_offsets_count (in_class);
506 MonoClass **in_class_interfaces_packed = m_class_get_interfaces_packed (in_class);
507 MonoClass **from_class_interfaces_packed = m_class_get_interfaces_packed (from_class);
508 for (i = 0; i < in_class_interface_offsets_count; i++) {
509 MonoClass *in_ic = in_class_interfaces_packed [i];
510 MonoClass *from_ic = from_class_interfaces_packed [i];
511 char *ic_qname, *ic_fqname, *ic_class_name;
513 ic_class_name = mono_type_get_name_full (m_class_get_byval_arg (in_ic), MONO_TYPE_NAME_FORMAT_IL);
514 ic_qname = g_strconcat (ic_class_name, ".", name, NULL);
515 const char *in_ic_name_space = m_class_get_name_space (in_ic);
516 if (in_ic_name_space && in_ic_name_space [0])
517 ic_fqname = g_strconcat (in_ic_name_space, ".", ic_class_name, ".", name, NULL);
518 else
519 ic_fqname = NULL;
521 result = find_method_in_class (in_ic, ic ? name : NULL, ic_qname, ic_fqname, sig, from_ic, error);
522 g_free (ic_class_name);
523 g_free (ic_fqname);
524 g_free (ic_qname);
525 if (result || !mono_error_ok (error))
526 goto out;
529 in_class = m_class_get_parent (in_class);
530 from_class = m_class_get_parent (from_class);
532 g_assert (!in_class == !from_class);
534 if (is_interface)
535 result = find_method_in_class (mono_defaults.object_class, name, qname, fqname, sig, mono_defaults.object_class, error);
537 //we did not find the method
538 if (!result && mono_error_ok (error))
539 mono_error_set_method_missing (error, initial_class, name, sig, NULL);
541 out:
542 g_free (class_name);
543 g_free (fqname);
544 g_free (qname);
545 return result;
548 static MonoMethodSignature*
549 inflate_generic_signature_checked (MonoImage *image, MonoMethodSignature *sig, MonoGenericContext *context, MonoError *error)
551 MonoMethodSignature *res;
552 gboolean is_open;
553 int i;
555 error_init (error);
556 if (!context)
557 return sig;
559 res = (MonoMethodSignature *)g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((gint32)sig->param_count) * sizeof (MonoType*));
560 res->param_count = sig->param_count;
561 res->sentinelpos = -1;
562 res->ret = mono_class_inflate_generic_type_checked (sig->ret, context, error);
563 if (!mono_error_ok (error))
564 goto fail;
565 is_open = mono_class_is_open_constructed_type (res->ret);
566 for (i = 0; i < sig->param_count; ++i) {
567 res->params [i] = mono_class_inflate_generic_type_checked (sig->params [i], context, error);
568 if (!mono_error_ok (error))
569 goto fail;
571 if (!is_open)
572 is_open = mono_class_is_open_constructed_type (res->params [i]);
574 res->hasthis = sig->hasthis;
575 res->explicit_this = sig->explicit_this;
576 res->call_convention = sig->call_convention;
577 res->pinvoke = sig->pinvoke;
578 res->generic_param_count = sig->generic_param_count;
579 res->sentinelpos = sig->sentinelpos;
580 res->has_type_parameters = is_open;
581 res->is_inflated = 1;
582 return res;
584 fail:
585 if (res->ret)
586 mono_metadata_free_type (res->ret);
587 for (i = 0; i < sig->param_count; ++i) {
588 if (res->params [i])
589 mono_metadata_free_type (res->params [i]);
591 g_free (res);
592 return NULL;
596 * mono_inflate_generic_signature:
598 * Inflate \p sig with \p context, and return a canonical copy. On error, set \p error, and return NULL.
600 MonoMethodSignature*
601 mono_inflate_generic_signature (MonoMethodSignature *sig, MonoGenericContext *context, MonoError *error)
603 MonoMethodSignature *res, *cached;
605 res = inflate_generic_signature_checked (NULL, sig, context, error);
606 if (!mono_error_ok (error))
607 return NULL;
608 cached = mono_metadata_get_inflated_signature (res, context);
609 if (cached != res)
610 mono_metadata_free_inflated_signature (res);
611 return cached;
614 static MonoMethodHeader*
615 inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context, MonoError *error)
617 size_t locals_size = sizeof (gpointer) * header->num_locals;
618 size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause);
619 size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size;
620 MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size);
621 res->num_locals = header->num_locals;
622 res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ;
623 memcpy (res->clauses, header->clauses, clauses_size);
625 res->code = header->code;
626 res->code_size = header->code_size;
627 res->max_stack = header->max_stack;
628 res->num_clauses = header->num_clauses;
629 res->init_locals = header->init_locals;
631 res->is_transient = TRUE;
633 error_init (error);
635 for (int i = 0; i < header->num_locals; ++i) {
636 res->locals [i] = mono_class_inflate_generic_type_checked (header->locals [i], context, error);
637 goto_if_nok (error, fail);
639 if (res->num_clauses) {
640 for (int i = 0; i < header->num_clauses; ++i) {
641 MonoExceptionClause *clause = &res->clauses [i];
642 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
643 continue;
644 clause->data.catch_class = mono_class_inflate_generic_class_checked (clause->data.catch_class, context, error);
645 goto_if_nok (error, fail);
648 return res;
649 fail:
650 g_free (res);
651 return NULL;
655 * mono_method_get_signature_full:
656 * \p token is the method ref/def/spec token used in a \c call IL instruction.
657 * \deprecated use the \c _checked variant
658 * Notes: runtime code MUST not use this function
660 MonoMethodSignature*
661 mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context)
663 ERROR_DECL (error);
664 MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, context, error);
665 mono_error_cleanup (error);
666 return res;
669 MonoMethodSignature*
670 mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
672 int table = mono_metadata_token_table (token);
673 int idx = mono_metadata_token_index (token);
674 int sig_idx;
675 guint32 cols [MONO_MEMBERREF_SIZE];
676 MonoMethodSignature *sig;
677 const char *ptr;
679 error_init (error);
681 /* !table is for wrappers: we should really assign their own token to them */
682 if (!table || table == MONO_TABLE_METHOD)
683 return mono_method_signature_checked (method, error);
685 if (table == MONO_TABLE_METHODSPEC) {
686 /* the verifier (do_invoke_method) will turn the NULL into a verifier error */
687 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || !method->is_inflated) {
688 mono_error_set_bad_image (error, image, "Method is a pinvoke or open generic");
689 return NULL;
692 return mono_method_signature_checked (method, error);
695 if (mono_class_is_ginst (method->klass))
696 return mono_method_signature_checked (method, error);
698 if (image_is_dynamic (image)) {
699 sig = mono_reflection_lookup_signature (image, method, token, error);
700 if (!sig)
701 return NULL;
702 } else {
703 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
704 sig_idx = cols [MONO_MEMBERREF_SIGNATURE];
706 sig = (MonoMethodSignature *)find_cached_memberref_sig (image, sig_idx);
707 if (!sig) {
708 if (!mono_verifier_verify_memberref_method_signature (image, sig_idx, error))
709 return NULL;
711 ptr = mono_metadata_blob_heap (image, sig_idx);
712 mono_metadata_decode_blob_size (ptr, &ptr);
714 sig = mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
715 if (!sig)
716 return NULL;
718 sig = (MonoMethodSignature *)cache_memberref_sig (image, sig_idx, sig);
720 /* FIXME: we probably should verify signature compat in the dynamic case too*/
721 if (!mono_verifier_is_sig_compatible (image, method, sig)) {
722 guint32 klass = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
723 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
725 mono_error_set_bad_image (error, image, "Incompatible method signature class token 0x%08x field name %s token 0x%08x", klass, fname, token);
726 return NULL;
730 if (context) {
731 MonoMethodSignature *cached;
733 /* This signature is not owned by a MonoMethod, so need to cache */
734 sig = inflate_generic_signature_checked (image, sig, context, error);
735 if (!mono_error_ok (error))
736 return NULL;
738 cached = mono_metadata_get_inflated_signature (sig, context);
739 if (cached != sig)
740 mono_metadata_free_inflated_signature (sig);
741 else
742 mono_atomic_fetch_add_i32 (&inflated_signatures_size, mono_metadata_signature_size (cached));
743 sig = cached;
746 g_assert (mono_error_ok (error));
747 return sig;
751 * mono_method_get_signature:
752 * \p token is the method_ref/def/spec token used in a call IL instruction.
753 * \deprecated use the \c _checked variant
754 * Notes: runtime code MUST not use this function
756 MonoMethodSignature*
757 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
759 ERROR_DECL (error);
760 MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, NULL, error);
761 mono_error_cleanup (error);
762 return res;
765 /* this is only for the typespec array methods */
766 MonoMethod*
767 mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMethodSignature *sig)
769 int i;
771 mono_class_setup_methods (klass);
772 g_assert (!mono_class_has_failure (klass)); /*FIXME this should not fail, right?*/
773 int mcount = mono_class_get_method_count (klass);
774 MonoMethod **klass_methods = m_class_get_methods (klass);
775 for (i = 0; i < mcount; ++i) {
776 MonoMethod *method = klass_methods [i];
777 if (strcmp (method->name, name) == 0 && sig->param_count == method->signature->param_count)
778 return method;
780 return NULL;
783 static MonoMethod *
784 method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typespec_context,
785 gboolean *used_context, MonoError *error)
787 MonoClass *klass = NULL;
788 MonoMethod *method = NULL;
789 MonoTableInfo *tables = image->tables;
790 guint32 cols[6];
791 guint32 nindex, class_index, sig_idx;
792 const char *mname;
793 MonoMethodSignature *sig;
794 const char *ptr;
796 error_init (error);
798 mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
799 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
800 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
801 /*g_print ("methodref: 0x%x 0x%x %s\n", class, nindex,
802 mono_metadata_string_heap (m, cols [MONO_MEMBERREF_NAME]));*/
804 mname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
807 * Whether we actually used the `typespec_context' or not.
808 * This is used to tell our caller whether or not it's safe to insert the returned
809 * method into a cache.
811 if (used_context)
812 *used_context = class_index == MONO_MEMBERREF_PARENT_TYPESPEC;
814 switch (class_index) {
815 case MONO_MEMBERREF_PARENT_TYPEREF:
816 klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
817 if (!klass)
818 goto fail;
819 break;
820 case MONO_MEMBERREF_PARENT_TYPESPEC:
822 * Parse the TYPESPEC in the parent's context.
824 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context, error);
825 if (!klass)
826 goto fail;
827 break;
828 case MONO_MEMBERREF_PARENT_TYPEDEF:
829 klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, error);
830 if (!klass)
831 goto fail;
832 break;
833 case MONO_MEMBERREF_PARENT_METHODDEF: {
834 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | nindex, NULL, NULL, error);
835 if (!method)
836 goto fail;
837 return method;
839 default:
840 mono_error_set_bad_image (error, image, "Memberref parent unknown: class: %d, index %d", class_index, nindex);
841 goto fail;
844 g_assert (klass);
845 mono_class_init (klass);
847 sig_idx = cols [MONO_MEMBERREF_SIGNATURE];
849 if (!mono_verifier_verify_memberref_method_signature (image, sig_idx, error))
850 goto fail;
852 ptr = mono_metadata_blob_heap (image, sig_idx);
853 mono_metadata_decode_blob_size (ptr, &ptr);
855 sig = (MonoMethodSignature *)find_cached_memberref_sig (image, sig_idx);
856 if (!sig) {
857 sig = mono_metadata_parse_method_signature_full (image, NULL, 0, ptr, NULL, error);
858 if (sig == NULL)
859 goto fail;
861 sig = (MonoMethodSignature *)cache_memberref_sig (image, sig_idx, sig);
864 switch (class_index) {
865 case MONO_MEMBERREF_PARENT_TYPEREF:
866 case MONO_MEMBERREF_PARENT_TYPEDEF:
867 method = find_method (klass, NULL, mname, sig, klass, error);
868 break;
870 case MONO_MEMBERREF_PARENT_TYPESPEC: {
871 MonoType *type;
873 type = m_class_get_byval_arg (klass);
875 if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) {
876 MonoClass *in_class = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->container_class : klass;
877 method = find_method (in_class, NULL, mname, sig, klass, error);
878 break;
881 /* we're an array and we created these methods already in klass in mono_class_init () */
882 method = mono_method_search_in_array_class (klass, mname, sig);
883 break;
885 default:
886 mono_error_set_bad_image (error, image,"Memberref parent unknown: class: %d, index %d", class_index, nindex);
887 goto fail;
890 if (!method && mono_error_ok (error))
891 mono_error_set_method_missing (error, klass, mname, sig, "Failed to load due to unknown reasons");
893 return method;
895 fail:
896 g_assert (!mono_error_ok (error));
897 return NULL;
900 static MonoMethod *
901 method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 idx, MonoError *error)
903 MonoMethod *method;
904 MonoClass *klass;
905 MonoTableInfo *tables = image->tables;
906 MonoGenericContext new_context;
907 MonoGenericInst *inst;
908 const char *ptr;
909 guint32 cols [MONO_METHODSPEC_SIZE];
910 guint32 token, nindex, param_count;
912 error_init (error);
914 mono_metadata_decode_row (&tables [MONO_TABLE_METHODSPEC], idx - 1, cols, MONO_METHODSPEC_SIZE);
915 token = cols [MONO_METHODSPEC_METHOD];
916 nindex = token >> MONO_METHODDEFORREF_BITS;
918 if (!mono_verifier_verify_methodspec_signature (image, cols [MONO_METHODSPEC_SIGNATURE], error))
919 return NULL;
921 ptr = mono_metadata_blob_heap (image, cols [MONO_METHODSPEC_SIGNATURE]);
923 mono_metadata_decode_value (ptr, &ptr);
924 ptr++;
925 param_count = mono_metadata_decode_value (ptr, &ptr);
927 inst = mono_metadata_parse_generic_inst (image, NULL, param_count, ptr, &ptr, error);
928 if (!inst)
929 return NULL;
931 if (context && inst->is_open) {
932 inst = mono_metadata_inflate_generic_inst (inst, context, error);
933 if (!mono_error_ok (error))
934 return NULL;
937 if ((token & MONO_METHODDEFORREF_MASK) == MONO_METHODDEFORREF_METHODDEF) {
938 method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | nindex, NULL, context, error);
939 if (!method)
940 return NULL;
941 } else {
942 method = method_from_memberref (image, nindex, context, NULL, error);
945 if (!method)
946 return NULL;
948 klass = method->klass;
950 if (mono_class_is_ginst (klass)) {
951 g_assert (method->is_inflated);
952 method = ((MonoMethodInflated *) method)->declaring;
955 new_context.class_inst = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->context.class_inst : NULL;
956 new_context.method_inst = inst;
958 method = mono_class_inflate_generic_method_full_checked (method, klass, &new_context, error);
959 return method;
962 struct _MonoDllMap {
963 char *dll;
964 char *target;
965 char *func;
966 char *target_func;
967 MonoDllMap *next;
970 static MonoDllMap *global_dll_map;
972 static int
973 mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
974 int found = 0;
976 *rdll = dll;
978 if (!dll_map)
979 return 0;
981 global_loader_data_lock ();
984 * we use the first entry we find that matches, since entries from
985 * the config file are prepended to the list and we document that the
986 * later entries win.
988 for (; dll_map; dll_map = dll_map->next) {
989 if (dll_map->dll [0] == 'i' && dll_map->dll [1] == ':') {
990 if (g_ascii_strcasecmp (dll_map->dll + 2, dll))
991 continue;
992 } else if (strcmp (dll_map->dll, dll)) {
993 continue;
995 if (!found && dll_map->target) {
996 *rdll = dll_map->target;
997 found = 1;
998 /* we don't quit here, because we could find a full
999 * entry that matches also function and that has priority.
1002 if (dll_map->func && strcmp (dll_map->func, func) == 0) {
1003 *rdll = dll_map->target;
1004 *rfunc = dll_map->target_func;
1005 break;
1009 global_loader_data_unlock ();
1010 return found;
1013 static int
1014 mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
1016 int res;
1017 if (assembly && assembly->dll_map) {
1018 res = mono_dllmap_lookup_list (assembly->dll_map, dll, func, rdll, rfunc);
1019 if (res)
1020 return res;
1022 return mono_dllmap_lookup_list (global_dll_map, dll, func, rdll, rfunc);
1026 * mono_dllmap_insert:
1027 * \param assembly if NULL, this is a global mapping, otherwise the remapping of the dynamic library will only apply to the specified assembly
1028 * \param dll The name of the external library, as it would be found in the \c DllImport declaration. If prefixed with <code>i:</code> the matching of the library name is done without case sensitivity
1029 * \param func if not null, the mapping will only applied to the named function (the value of <code>EntryPoint</code>)
1030 * \param tdll The name of the library to map the specified \p dll if it matches.
1031 * \param tfunc The name of the function that replaces the invocation. If NULL, it is replaced with a copy of \p func.
1033 * LOCKING: Acquires the loader lock.
1035 * This function is used to programatically add \c DllImport remapping in either
1036 * a specific assembly, or as a global remapping. This is done by remapping
1037 * references in a \c DllImport attribute from the \p dll library name into the \p tdll
1038 * name. If the \p dll name contains the prefix <code>i:</code>, the comparison of the
1039 * library name is done without case sensitivity.
1041 * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
1042 * or the name of the function as determined by \c DllImport. If you pass \p func, you
1043 * must also pass \p tfunc which is the name of the target function to invoke on a match.
1045 * Example:
1047 * <code>mono_dllmap_insert (NULL, "i:libdemo.dll", NULL, relocated_demo_path, NULL);</code>
1049 * The above will remap \c DllImport statements for \c libdemo.dll and \c LIBDEMO.DLL to
1050 * the contents of \c relocated_demo_path for all assemblies in the Mono process.
1052 * NOTE: This can be called before the runtime is initialized, for example from
1053 * \c mono_config_parse.
1055 void
1056 mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
1058 if (!assembly)
1059 dllmap_insert_global (dll, func, tdll, tfunc);
1060 else {
1061 MONO_ENTER_GC_UNSAFE;
1062 dllmap_insert_image (assembly, dll, func, tdll, tfunc);
1063 MONO_EXIT_GC_UNSAFE;
1067 void
1068 dllmap_insert_global (const char *dll, const char *func, const char *tdll, const char *tfunc)
1070 MonoDllMap *entry;
1072 mono_loader_init ();
1074 entry = (MonoDllMap *)g_malloc0 (sizeof (MonoDllMap));
1075 entry->dll = dll? g_strdup (dll): NULL;
1076 entry->target = tdll? g_strdup (tdll): NULL;
1077 entry->func = func? g_strdup (func): NULL;
1078 entry->target_func = tfunc? g_strdup (tfunc): (func? g_strdup (func): NULL);
1080 global_loader_data_lock ();
1081 entry->next = global_dll_map;
1082 global_dll_map = entry;
1083 global_loader_data_unlock ();
1086 void
1087 dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
1089 MonoDllMap *entry;
1090 g_assert (assembly != NULL);
1092 mono_loader_init ();
1094 entry = (MonoDllMap *)mono_image_alloc0 (assembly, sizeof (MonoDllMap));
1095 entry->dll = dll? mono_image_strdup (assembly, dll): NULL;
1096 entry->target = tdll? mono_image_strdup (assembly, tdll): NULL;
1097 entry->func = func? mono_image_strdup (assembly, func): NULL;
1098 entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): (func? mono_image_strdup (assembly, func): NULL);
1100 mono_image_lock (assembly);
1101 entry->next = assembly->dll_map;
1102 assembly->dll_map = entry;
1103 mono_image_unlock (assembly);
1106 static void
1107 free_dllmap (MonoDllMap *map)
1109 while (map) {
1110 MonoDllMap *next = map->next;
1112 g_free (map->dll);
1113 g_free (map->target);
1114 g_free (map->func);
1115 g_free (map->target_func);
1116 g_free (map);
1117 map = next;
1121 static void
1122 dllmap_cleanup (void)
1124 free_dllmap (global_dll_map);
1125 global_dll_map = NULL;
1128 static GHashTable *global_module_map;
1130 static MonoDl*
1131 cached_module_load (const char *name, int flags, char **err)
1133 MonoDl *res;
1135 if (err)
1136 *err = NULL;
1137 global_loader_data_lock ();
1138 if (!global_module_map)
1139 global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
1140 res = (MonoDl *)g_hash_table_lookup (global_module_map, name);
1141 if (res) {
1142 global_loader_data_unlock ();
1143 return res;
1145 res = mono_dl_open (name, flags, err);
1146 if (res)
1147 g_hash_table_insert (global_module_map, g_strdup (name), res);
1148 global_loader_data_unlock ();
1149 return res;
1152 void
1153 mono_loader_register_module (const char *name, MonoDl *module)
1155 if (!global_module_map)
1156 global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
1157 g_hash_table_insert (global_module_map, g_strdup (name), module);
1160 static void
1161 remove_cached_module(gpointer key, gpointer value, gpointer user_data)
1163 mono_dl_close((MonoDl*)value);
1166 static void
1167 cached_module_cleanup(void)
1169 if (global_module_map != NULL) {
1170 g_hash_table_foreach(global_module_map, remove_cached_module, NULL);
1172 g_hash_table_destroy(global_module_map);
1173 global_module_map = NULL;
1177 static MonoDl *internal_module;
1179 static gboolean
1180 is_absolute_path (const char *path)
1182 #ifdef HOST_DARWIN
1183 if (!strncmp (path, "@executable_path/", 17) || !strncmp (path, "@loader_path/", 13) ||
1184 !strncmp (path, "@rpath/", 7))
1185 return TRUE;
1186 #endif
1187 return g_path_is_absolute (path);
1191 * mono_lookup_pinvoke_call:
1193 gpointer
1194 mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
1196 MonoImage *image = m_class_get_image (method->klass);
1197 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
1198 MonoTableInfo *tables = image->tables;
1199 MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
1200 MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
1201 guint32 im_cols [MONO_IMPLMAP_SIZE];
1202 guint32 scope_token;
1203 const char *import = NULL;
1204 const char *orig_scope;
1205 const char *new_scope;
1206 char *error_msg;
1207 char *full_name, *file_name, *found_name = NULL;
1208 int i,j;
1209 MonoDl *module = NULL;
1210 gboolean cached = FALSE;
1211 gpointer addr = NULL;
1213 g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
1215 if (exc_class) {
1216 *exc_class = NULL;
1217 *exc_arg = NULL;
1220 if (piinfo->addr)
1221 return piinfo->addr;
1223 if (image_is_dynamic (m_class_get_image (method->klass))) {
1224 MonoReflectionMethodAux *method_aux =
1225 (MonoReflectionMethodAux *)g_hash_table_lookup (
1226 ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1227 if (!method_aux)
1228 return NULL;
1230 import = method_aux->dllentry;
1231 orig_scope = method_aux->dll;
1233 else {
1234 if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
1235 return NULL;
1237 mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
1239 if (!im_cols [MONO_IMPLMAP_SCOPE] || im_cols [MONO_IMPLMAP_SCOPE] > mr->rows)
1240 return NULL;
1242 piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
1243 import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
1244 scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
1245 orig_scope = mono_metadata_string_heap (image, scope_token);
1248 mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
1250 if (!module) {
1251 mono_image_lock (image);
1252 if (!image->pinvoke_scopes) {
1253 image->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1254 image->pinvoke_scope_filenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1256 module = (MonoDl *)g_hash_table_lookup (image->pinvoke_scopes, new_scope);
1257 found_name = (char *)g_hash_table_lookup (image->pinvoke_scope_filenames, new_scope);
1258 mono_image_unlock (image);
1259 if (module)
1260 cached = TRUE;
1261 if (found_name)
1262 found_name = g_strdup (found_name);
1265 if (!module) {
1266 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1267 "DllImport attempting to load: '%s'.", new_scope);
1269 /* we allow a special name to dlopen from the running process namespace */
1270 if (strcmp (new_scope, "__Internal") == 0){
1271 if (internal_module == NULL)
1272 internal_module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg);
1273 module = internal_module;
1278 * Try loading the module using a variety of names
1280 for (i = 0; i < 5; ++i) {
1281 char *base_name = NULL, *dir_name = NULL;
1282 gboolean is_absolute = is_absolute_path (new_scope);
1284 switch (i) {
1285 case 0:
1286 /* Try the original name */
1287 file_name = g_strdup (new_scope);
1288 break;
1289 case 1:
1290 /* Try trimming the .dll extension */
1291 if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
1292 file_name = g_strdup (new_scope);
1293 file_name [strlen (new_scope) - 4] = '\0';
1295 else
1296 continue;
1297 break;
1298 case 2:
1299 if (is_absolute) {
1300 dir_name = g_path_get_dirname (new_scope);
1301 base_name = g_path_get_basename (new_scope);
1302 if (strstr (base_name, "lib") != base_name) {
1303 char *tmp = g_strdup_printf ("lib%s", base_name);
1304 g_free (base_name);
1305 base_name = tmp;
1306 file_name = g_strdup_printf ("%s%s%s", dir_name, G_DIR_SEPARATOR_S, base_name);
1307 break;
1309 } else if (strstr (new_scope, "lib") != new_scope) {
1310 file_name = g_strdup_printf ("lib%s", new_scope);
1311 break;
1313 continue;
1314 case 3:
1315 if (!is_absolute && mono_dl_get_system_dir ()) {
1316 dir_name = (char*)mono_dl_get_system_dir ();
1317 file_name = g_path_get_basename (new_scope);
1318 base_name = NULL;
1319 } else
1320 continue;
1321 break;
1322 default:
1323 #ifndef TARGET_WIN32
1324 if (!g_ascii_strcasecmp ("user32.dll", new_scope) ||
1325 !g_ascii_strcasecmp ("kernel32.dll", new_scope) ||
1326 !g_ascii_strcasecmp ("user32", new_scope) ||
1327 !g_ascii_strcasecmp ("kernel", new_scope)) {
1328 file_name = g_strdup ("libMonoSupportW.so");
1329 } else
1330 #endif
1331 continue;
1332 #ifndef TARGET_WIN32
1333 break;
1334 #endif
1337 if (is_absolute) {
1338 if (!dir_name)
1339 dir_name = g_path_get_dirname (file_name);
1340 if (!base_name)
1341 base_name = g_path_get_basename (file_name);
1344 if (!module && is_absolute) {
1345 module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
1346 if (!module) {
1347 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1348 "DllImport error loading library '%s': '%s'.",
1349 file_name, error_msg);
1350 g_free (error_msg);
1351 } else {
1352 found_name = g_strdup (file_name);
1356 if (!module && !is_absolute) {
1357 void *iter;
1358 char *mdirname;
1360 for (j = 0; j < 3; ++j) {
1361 iter = NULL;
1362 mdirname = NULL;
1363 switch (j) {
1364 case 0:
1365 mdirname = g_path_get_dirname (image->name);
1366 break;
1367 case 1: /* @executable_path@/../lib */
1369 char buf [4096];
1370 int binl;
1371 binl = mono_dl_get_executable_path (buf, sizeof (buf));
1372 if (binl != -1) {
1373 char *base, *newbase;
1374 char *resolvedname;
1375 buf [binl] = 0;
1376 resolvedname = mono_path_resolve_symlinks (buf);
1378 base = g_path_get_dirname (resolvedname);
1379 newbase = g_path_get_dirname(base);
1380 mdirname = g_strdup_printf ("%s/lib", newbase);
1382 g_free (resolvedname);
1383 g_free (base);
1384 g_free (newbase);
1386 break;
1388 #ifdef __MACH__
1389 case 2: /* @executable_path@/../Libraries */
1391 char buf [4096];
1392 int binl;
1393 binl = mono_dl_get_executable_path (buf, sizeof (buf));
1394 if (binl != -1) {
1395 char *base, *newbase;
1396 char *resolvedname;
1397 buf [binl] = 0;
1398 resolvedname = mono_path_resolve_symlinks (buf);
1400 base = g_path_get_dirname (resolvedname);
1401 newbase = g_path_get_dirname(base);
1402 mdirname = g_strdup_printf ("%s/Libraries", newbase);
1404 g_free (resolvedname);
1405 g_free (base);
1406 g_free (newbase);
1408 break;
1410 #endif
1413 if (!mdirname)
1414 continue;
1416 while ((full_name = mono_dl_build_path (mdirname, file_name, &iter))) {
1417 module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
1418 if (!module) {
1419 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1420 "DllImport error loading library '%s': '%s'.",
1421 full_name, error_msg);
1422 g_free (error_msg);
1423 } else {
1424 found_name = g_strdup (full_name);
1426 g_free (full_name);
1427 if (module)
1428 break;
1431 g_free (mdirname);
1432 if (module)
1433 break;
1438 if (!module) {
1439 void *iter = NULL;
1440 char *file_or_base = is_absolute ? base_name : file_name;
1441 while ((full_name = mono_dl_build_path (dir_name, file_or_base, &iter))) {
1442 module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
1443 if (!module) {
1444 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1445 "DllImport error loading library '%s': '%s'.",
1446 full_name, error_msg);
1447 g_free (error_msg);
1448 } else {
1449 found_name = g_strdup (full_name);
1451 g_free (full_name);
1452 if (module)
1453 break;
1457 if (!module) {
1458 module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
1459 if (!module) {
1460 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1461 "DllImport error loading library '%s': '%s'.",
1462 file_name, error_msg);
1463 } else {
1464 found_name = g_strdup (file_name);
1468 g_free (file_name);
1469 if (is_absolute) {
1470 g_free (base_name);
1471 g_free (dir_name);
1474 if (module)
1475 break;
1478 if (!module) {
1479 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
1480 "DllImport unable to load library '%s'.",
1481 error_msg);
1482 g_free (error_msg);
1484 if (exc_class) {
1485 *exc_class = "DllNotFoundException";
1486 *exc_arg = new_scope;
1488 return NULL;
1491 if (!cached) {
1492 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1493 "DllImport loaded library '%s'.", found_name);
1494 mono_image_lock (image);
1495 if (!g_hash_table_lookup (image->pinvoke_scopes, new_scope)) {
1496 g_hash_table_insert (image->pinvoke_scopes, g_strdup (new_scope), module);
1497 g_hash_table_insert (image->pinvoke_scope_filenames, g_strdup (new_scope), g_strdup (found_name));
1499 mono_image_unlock (image);
1502 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1503 "DllImport searching in: '%s' ('%s').", new_scope, found_name);
1504 g_free (found_name);
1506 #ifdef TARGET_WIN32
1507 if (import && import [0] == '#' && isdigit (import [1])) {
1508 char *end;
1509 long id;
1511 id = strtol (import + 1, &end, 10);
1512 if (id > 0 && *end == '\0')
1513 import++;
1515 #endif
1516 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1517 "Searching for '%s'.", import);
1519 if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
1520 error_msg = mono_dl_symbol (module, import, &addr);
1521 } else {
1522 char *mangled_name = NULL, *mangled_name2 = NULL;
1523 int mangle_charset;
1524 int mangle_stdcall;
1525 int mangle_param_count;
1526 #ifdef TARGET_WIN32
1527 int param_count;
1528 #endif
1531 * Search using a variety of mangled names
1533 for (mangle_charset = 0; mangle_charset <= 1; mangle_charset ++) {
1534 for (mangle_stdcall = 0; mangle_stdcall <= 1; mangle_stdcall ++) {
1535 gboolean need_param_count = FALSE;
1536 #ifdef TARGET_WIN32
1537 if (mangle_stdcall > 0)
1538 need_param_count = TRUE;
1539 #endif
1540 for (mangle_param_count = 0; mangle_param_count <= (need_param_count ? 256 : 0); mangle_param_count += 4) {
1542 if (addr)
1543 continue;
1545 mangled_name = (char*)import;
1546 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
1547 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
1548 /* Try the mangled name first */
1549 if (mangle_charset == 0)
1550 mangled_name = g_strconcat (import, "W", NULL);
1551 break;
1552 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
1553 #ifdef TARGET_WIN32
1554 if (mangle_charset == 0)
1555 mangled_name = g_strconcat (import, "W", NULL);
1556 #else
1557 /* Try the mangled name last */
1558 if (mangle_charset == 1)
1559 mangled_name = g_strconcat (import, "A", NULL);
1560 #endif
1561 break;
1562 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
1563 default:
1564 /* Try the mangled name last */
1565 if (mangle_charset == 1)
1566 mangled_name = g_strconcat (import, "A", NULL);
1567 break;
1570 #ifdef TARGET_WIN32
1571 if (mangle_param_count == 0)
1572 param_count = mono_method_signature_internal (method)->param_count * sizeof (gpointer);
1573 else
1574 /* Try brute force, since it would be very hard to compute the stack usage correctly */
1575 param_count = mangle_param_count;
1577 /* Try the stdcall mangled name */
1579 * gcc under windows creates mangled names without the underscore, but MS.NET
1580 * doesn't support it, so we doesn't support it either.
1582 if (mangle_stdcall == 1)
1583 mangled_name2 = g_strdup_printf ("_%s@%d", mangled_name, param_count);
1584 else
1585 mangled_name2 = mangled_name;
1586 #else
1587 mangled_name2 = mangled_name;
1588 #endif
1590 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1591 "Probing '%s'.", mangled_name2);
1593 error_msg = mono_dl_symbol (module, mangled_name2, &addr);
1595 if (addr)
1596 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1597 "Found as '%s'.", mangled_name2);
1598 else
1599 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
1600 "Could not find '%s' due to '%s'.", mangled_name2, error_msg);
1602 g_free (error_msg);
1603 error_msg = NULL;
1605 if (mangled_name != mangled_name2)
1606 g_free (mangled_name2);
1607 if (mangled_name != import)
1608 g_free (mangled_name);
1614 if (!addr) {
1615 g_free (error_msg);
1616 if (exc_class) {
1617 *exc_class = "EntryPointNotFoundException";
1618 *exc_arg = import;
1620 return NULL;
1622 piinfo->addr = addr;
1623 return addr;
1627 * LOCKING: assumes the loader lock to be taken.
1629 static MonoMethod *
1630 mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
1631 MonoGenericContext *context, gboolean *used_context, MonoError *error)
1633 MonoMethod *result;
1634 int table = mono_metadata_token_table (token);
1635 int idx = mono_metadata_token_index (token);
1636 MonoTableInfo *tables = image->tables;
1637 MonoGenericContainer *generic_container = NULL, *container = NULL;
1638 const char *sig = NULL;
1639 guint32 cols [MONO_TYPEDEF_SIZE];
1641 error_init (error);
1643 if (image_is_dynamic (image)) {
1644 MonoClass *handle_class;
1646 result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, error);
1647 mono_error_assert_ok (error);
1649 // This checks the memberref type as well
1650 if (result && handle_class != mono_defaults.methodhandle_class) {
1651 mono_error_set_bad_image (error, image, "Bad method token 0x%08x on dynamic image", token);
1652 return NULL;
1654 return result;
1657 if (table != MONO_TABLE_METHOD) {
1658 if (table == MONO_TABLE_METHODSPEC) {
1659 if (used_context) *used_context = TRUE;
1660 return method_from_methodspec (image, context, idx, error);
1662 if (table != MONO_TABLE_MEMBERREF) {
1663 mono_error_set_bad_image (error, image, "Bad method token 0x%08x.", token);
1664 return NULL;
1666 return method_from_memberref (image, idx, context, used_context, error);
1669 if (used_context) *used_context = FALSE;
1671 if (idx > image->tables [MONO_TABLE_METHOD].rows) {
1672 mono_error_set_bad_image (error, image, "Bad method token 0x%08x (out of bounds).", token);
1673 return NULL;
1676 if (!klass) {
1677 guint32 type = mono_metadata_typedef_from_method (image, token);
1678 if (!type) {
1679 mono_error_set_bad_image (error, image, "Bad method token 0x%08x (could not find corresponding typedef).", token);
1680 return NULL;
1682 klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, error);
1683 if (klass == NULL)
1684 return NULL;
1687 mono_metadata_decode_row (&image->tables [MONO_TABLE_METHOD], idx - 1, cols, 6);
1689 if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1690 (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) {
1691 result = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethodPInvoke));
1692 } else {
1693 result = (MonoMethod *)mono_image_alloc0 (image, sizeof (MonoMethod));
1694 mono_atomic_fetch_add_i32 (&methods_size, sizeof (MonoMethod));
1697 mono_atomic_inc_i32 (&mono_stats.method_count);
1699 result->slot = -1;
1700 result->klass = klass;
1701 result->flags = cols [2];
1702 result->iflags = cols [1];
1703 result->token = token;
1704 result->name = mono_metadata_string_heap (image, cols [3]);
1706 if (!sig) /* already taken from the methodref */
1707 sig = mono_metadata_blob_heap (image, cols [4]);
1708 /* size = */ mono_metadata_decode_blob_size (sig, &sig);
1710 container = mono_class_try_get_generic_container (klass);
1713 * load_generic_params does a binary search so only call it if the method
1714 * is generic.
1716 if (*sig & 0x10) {
1717 generic_container = mono_metadata_load_generic_params (image, token, container, result);
1719 if (generic_container) {
1720 result->is_generic = TRUE;
1721 /*FIXME put this before the image alloc*/
1722 if (!mono_metadata_load_generic_param_constraints_checked (image, token, generic_container, error))
1723 return NULL;
1725 container = generic_container;
1728 if (cols [1] & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1729 if (result->klass == mono_defaults.string_class && !strcmp (result->name, ".ctor"))
1730 result->string_ctor = 1;
1731 } else if (cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
1732 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)result;
1734 #ifdef TARGET_WIN32
1735 /* IJW is P/Invoke with a predefined function pointer. */
1736 if (image->is_module_handle && (cols [1] & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
1737 piinfo->addr = mono_image_rva_map (image, cols [0]);
1738 g_assert (piinfo->addr);
1740 #endif
1741 piinfo->implmap_idx = mono_metadata_implmap_from_method (image, idx - 1);
1742 /* Native methods can have no map. */
1743 if (piinfo->implmap_idx)
1744 piinfo->piflags = mono_metadata_decode_row_col (&tables [MONO_TABLE_IMPLMAP], piinfo->implmap_idx - 1, MONO_IMPLMAP_FLAGS);
1747 if (generic_container)
1748 mono_method_set_generic_container (result, generic_container);
1750 return result;
1754 * mono_get_method:
1756 MonoMethod *
1757 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
1759 ERROR_DECL (error);
1760 MonoMethod *result = mono_get_method_checked (image, token, klass, NULL, error);
1761 mono_error_cleanup (error);
1762 return result;
1766 * mono_get_method_full:
1768 MonoMethod *
1769 mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
1770 MonoGenericContext *context)
1772 ERROR_DECL (error);
1773 MonoMethod *result = mono_get_method_checked (image, token, klass, context, error);
1774 mono_error_cleanup (error);
1775 return result;
1778 MonoMethod *
1779 mono_get_method_checked (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
1781 MonoMethod *result = NULL;
1782 gboolean used_context = FALSE;
1784 /* We do everything inside the lock to prevent creation races */
1786 error_init (error);
1788 mono_image_lock (image);
1790 if (mono_metadata_token_table (token) == MONO_TABLE_METHOD) {
1791 if (!image->method_cache)
1792 image->method_cache = g_hash_table_new (NULL, NULL);
1793 result = (MonoMethod *)g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)));
1794 } else if (!image_is_dynamic (image)) {
1795 if (!image->methodref_cache)
1796 image->methodref_cache = g_hash_table_new (NULL, NULL);
1797 result = (MonoMethod *)g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));
1799 mono_image_unlock (image);
1801 if (result)
1802 return result;
1805 result = mono_get_method_from_token (image, token, klass, context, &used_context, error);
1806 if (!result)
1807 return NULL;
1809 mono_image_lock (image);
1810 if (!used_context && !result->is_inflated) {
1811 MonoMethod *result2 = NULL;
1813 if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
1814 result2 = (MonoMethod *)g_hash_table_lookup (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)));
1815 else if (!image_is_dynamic (image))
1816 result2 = (MonoMethod *)g_hash_table_lookup (image->methodref_cache, GINT_TO_POINTER (token));
1818 if (result2) {
1819 mono_image_unlock (image);
1820 return result2;
1823 if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
1824 g_hash_table_insert (image->method_cache, GINT_TO_POINTER (mono_metadata_token_index (token)), result);
1825 else if (!image_is_dynamic (image))
1826 g_hash_table_insert (image->methodref_cache, GINT_TO_POINTER (token), result);
1829 mono_image_unlock (image);
1831 return result;
1834 static MonoMethod*
1835 get_method_constrained (MonoImage *image, MonoMethod *method, MonoClass *constrained_class, MonoGenericContext *context, MonoError *error)
1837 MonoClass *base_class = method->klass;
1839 error_init (error);
1841 if (!mono_class_is_assignable_from_internal (base_class, constrained_class)) {
1842 char *base_class_name = mono_type_get_full_name (base_class);
1843 char *constrained_class_name = mono_type_get_full_name (constrained_class);
1844 mono_error_set_invalid_operation (error, "constrained call: %s is not assignable from %s", base_class_name, constrained_class_name);
1845 g_free (base_class_name);
1846 g_free (constrained_class_name);
1847 return NULL;
1850 /* If the constraining class is actually an interface, we don't learn
1851 * anything new by constraining.
1853 if (MONO_CLASS_IS_INTERFACE_INTERNAL (constrained_class))
1854 return method;
1856 mono_class_setup_vtable (base_class);
1857 if (mono_class_has_failure (base_class)) {
1858 mono_error_set_for_class_failure (error, base_class);
1859 return NULL;
1862 MonoGenericContext inflated_method_ctx;
1863 memset (&inflated_method_ctx, 0, sizeof (inflated_method_ctx));
1864 inflated_method_ctx.class_inst = NULL;
1865 inflated_method_ctx.method_inst = NULL;
1866 gboolean inflated_generic_method = FALSE;
1867 if (method->is_inflated) {
1868 MonoGenericContext *method_ctx = mono_method_get_context (method);
1869 /* If method is an instantiation of a generic method definition, ie
1870 * class H<T> { void M<U> (...) { ... } }
1871 * and method is H<C>.M<D>
1872 * we will get at the end a refined HSubclass<...>.M<U> and we will need to re-instantiate it with D.
1873 * to get HSubclass<...>.M<D>
1876 if (method_ctx->method_inst != NULL) {
1877 inflated_generic_method = TRUE;
1878 inflated_method_ctx.method_inst = method_ctx->method_inst;
1881 int vtable_slot = 0;
1882 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (base_class)) {
1883 /*if the base class isn't an interface and the method isn't
1884 * virtual, there's nothing to do, we're already on the method
1885 * we want to call. */
1886 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0)
1887 return method;
1888 /* if this isn't an interface method, get the vtable slot and
1889 * find the corresponding method in the constrained class,
1890 * which is a subclass of the base class. */
1891 vtable_slot = mono_method_get_vtable_index (method);
1893 mono_class_setup_vtable (constrained_class);
1894 if (mono_class_has_failure (constrained_class)) {
1895 mono_error_set_for_class_failure (error, constrained_class);
1896 return NULL;
1898 } else {
1899 mono_class_setup_vtable (constrained_class);
1900 if (mono_class_has_failure (constrained_class)) {
1901 mono_error_set_for_class_failure (error, constrained_class);
1902 return NULL;
1905 /* Get the slot of the method in the interface. Then get the
1906 * interface base in constrained_class */
1907 int itf_slot = mono_method_get_vtable_index (method);
1908 g_assert (itf_slot >= 0);
1909 gboolean variant = FALSE;
1910 int itf_base = mono_class_interface_offset_with_variance (constrained_class, base_class, &variant);
1911 vtable_slot = itf_slot + itf_base;
1913 g_assert (vtable_slot >= 0);
1915 MonoMethod *res = mono_class_get_vtable_entry (constrained_class, vtable_slot);
1916 if (res == NULL && mono_class_is_abstract (constrained_class) ) {
1917 /* Constraining class is abstract, there may not be a refined method. */
1918 return method;
1920 g_assert (res != NULL);
1921 if (inflated_generic_method) {
1922 g_assert (res->is_generic);
1923 res = mono_class_inflate_generic_method_checked (res, &inflated_method_ctx, error);
1924 return_val_if_nok (error, NULL);
1926 return res;
1929 MonoMethod *
1930 mono_get_method_constrained_with_method (MonoImage *image, MonoMethod *method, MonoClass *constrained_class,
1931 MonoGenericContext *context, MonoError *error)
1933 g_assert (method);
1935 return get_method_constrained (image, method, constrained_class, context, error);
1939 * mono_get_method_constrained:
1940 * This is used when JITing the <code>constrained.</code> opcode.
1941 * \returns The contrained method, which has been inflated
1942 * as the function return value; and the original CIL-stream method as
1943 * declared in \p cil_method. The latter is used for verification.
1945 MonoMethod *
1946 mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constrained_class,
1947 MonoGenericContext *context, MonoMethod **cil_method)
1949 ERROR_DECL (error);
1950 MonoMethod *result = mono_get_method_constrained_checked (image, token, constrained_class, context, cil_method, error);
1951 mono_error_cleanup (error);
1952 return result;
1955 MonoMethod *
1956 mono_get_method_constrained_checked (MonoImage *image, guint32 token, MonoClass *constrained_class, MonoGenericContext *context, MonoMethod **cil_method, MonoError *error)
1958 error_init (error);
1960 *cil_method = mono_get_method_checked (image, token, NULL, context, error);
1961 if (!*cil_method)
1962 return NULL;
1964 return get_method_constrained (image, *cil_method, constrained_class, context, error);
1968 * mono_free_method:
1970 void
1971 mono_free_method (MonoMethod *method)
1973 MONO_PROFILER_RAISE (method_free, (method));
1975 /* FIXME: This hack will go away when the profiler will support freeing methods */
1976 if (G_UNLIKELY (mono_profiler_installed ()))
1977 return;
1979 if (method->signature) {
1981 * FIXME: This causes crashes because the types inside signatures and
1982 * locals are shared.
1984 /* mono_metadata_free_method_signature (method->signature); */
1985 /* g_free (method->signature); */
1988 if (method_is_dynamic (method)) {
1989 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1990 int i;
1992 mono_marshal_free_dynamic_wrappers (method);
1994 mono_image_property_remove (m_class_get_image (method->klass), method);
1996 g_free ((char*)method->name);
1997 if (mw->header) {
1998 g_free ((char*)mw->header->code);
1999 for (i = 0; i < mw->header->num_locals; ++i)
2000 g_free (mw->header->locals [i]);
2001 g_free (mw->header->clauses);
2002 g_free (mw->header);
2004 g_free (mw->method_data);
2005 g_free (method->signature);
2006 g_free (method);
2011 * mono_method_get_param_names:
2013 void
2014 mono_method_get_param_names (MonoMethod *method, const char **names)
2016 int i, lastp;
2017 MonoClass *klass;
2018 MonoTableInfo *methodt;
2019 MonoTableInfo *paramt;
2020 MonoMethodSignature *signature;
2021 guint32 idx;
2023 if (method->is_inflated)
2024 method = ((MonoMethodInflated *) method)->declaring;
2026 signature = mono_method_signature_internal (method);
2027 /*FIXME this check is somewhat redundant since the caller usally will have to get the signature to figure out the
2028 number of arguments and allocate a properly sized array. */
2029 if (signature == NULL)
2030 return;
2032 if (!signature->param_count)
2033 return;
2035 for (i = 0; i < signature->param_count; ++i)
2036 names [i] = "";
2038 klass = method->klass;
2039 if (m_class_get_rank (klass))
2040 return;
2042 mono_class_init (klass);
2044 MonoImage *klass_image = m_class_get_image (klass);
2045 if (image_is_dynamic (klass_image)) {
2046 MonoReflectionMethodAux *method_aux =
2047 (MonoReflectionMethodAux *)g_hash_table_lookup (
2048 ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
2049 if (method_aux && method_aux->param_names) {
2050 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i)
2051 if (method_aux->param_names [i + 1])
2052 names [i] = method_aux->param_names [i + 1];
2054 return;
2057 if (method->wrapper_type) {
2058 char **pnames = NULL;
2060 mono_image_lock (klass_image);
2061 if (klass_image->wrapper_param_names)
2062 pnames = (char **)g_hash_table_lookup (klass_image->wrapper_param_names, method);
2063 mono_image_unlock (klass_image);
2065 if (pnames) {
2066 for (i = 0; i < signature->param_count; ++i)
2067 names [i] = pnames [i];
2069 return;
2072 methodt = &klass_image->tables [MONO_TABLE_METHOD];
2073 paramt = &klass_image->tables [MONO_TABLE_PARAM];
2074 idx = mono_method_get_index (method);
2075 if (idx > 0) {
2076 guint32 cols [MONO_PARAM_SIZE];
2077 guint param_index;
2079 param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
2081 if (idx < methodt->rows)
2082 lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
2083 else
2084 lastp = paramt->rows + 1;
2085 for (i = param_index; i < lastp; ++i) {
2086 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
2087 if (cols [MONO_PARAM_SEQUENCE] && cols [MONO_PARAM_SEQUENCE] <= signature->param_count) /* skip return param spec and bounds check*/
2088 names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass_image, cols [MONO_PARAM_NAME]);
2094 * mono_method_get_param_token:
2096 guint32
2097 mono_method_get_param_token (MonoMethod *method, int index)
2099 MonoClass *klass = method->klass;
2100 MonoTableInfo *methodt;
2101 guint32 idx;
2103 mono_class_init (klass);
2105 MonoImage *klass_image = m_class_get_image (klass);
2106 g_assert (!image_is_dynamic (klass_image));
2108 methodt = &klass_image->tables [MONO_TABLE_METHOD];
2109 idx = mono_method_get_index (method);
2110 if (idx > 0) {
2111 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
2113 if (index == -1)
2114 /* Return value */
2115 return mono_metadata_make_token (MONO_TABLE_PARAM, 0);
2116 else
2117 return mono_metadata_make_token (MONO_TABLE_PARAM, param_index + index);
2120 return 0;
2124 * mono_method_get_marshal_info:
2126 void
2127 mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs)
2129 int i, lastp;
2130 MonoClass *klass = method->klass;
2131 MonoTableInfo *methodt;
2132 MonoTableInfo *paramt;
2133 MonoMethodSignature *signature;
2134 guint32 idx;
2136 signature = mono_method_signature_internal (method);
2137 g_assert (signature); /*FIXME there is no way to signal error from this function*/
2139 for (i = 0; i < signature->param_count + 1; ++i)
2140 mspecs [i] = NULL;
2142 if (image_is_dynamic (m_class_get_image (method->klass))) {
2143 MonoReflectionMethodAux *method_aux =
2144 (MonoReflectionMethodAux *)g_hash_table_lookup (
2145 ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
2146 if (method_aux && method_aux->param_marshall) {
2147 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
2148 for (i = 0; i < signature->param_count + 1; ++i)
2149 if (dyn_specs [i]) {
2150 mspecs [i] = g_new0 (MonoMarshalSpec, 1);
2151 memcpy (mspecs [i], dyn_specs [i], sizeof (MonoMarshalSpec));
2152 mspecs [i]->data.custom_data.custom_name = g_strdup (dyn_specs [i]->data.custom_data.custom_name);
2153 mspecs [i]->data.custom_data.cookie = g_strdup (dyn_specs [i]->data.custom_data.cookie);
2156 return;
2159 mono_class_init (klass);
2161 MonoImage *klass_image = m_class_get_image (klass);
2162 methodt = &klass_image->tables [MONO_TABLE_METHOD];
2163 paramt = &klass_image->tables [MONO_TABLE_PARAM];
2164 idx = mono_method_get_index (method);
2165 if (idx > 0) {
2166 guint32 cols [MONO_PARAM_SIZE];
2167 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
2169 if (idx < methodt->rows)
2170 lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
2171 else
2172 lastp = paramt->rows + 1;
2174 for (i = param_index; i < lastp; ++i) {
2175 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
2177 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL && cols [MONO_PARAM_SEQUENCE] <= signature->param_count) {
2178 const char *tp;
2179 tp = mono_metadata_get_marshal_info (klass_image, i - 1, FALSE);
2180 g_assert (tp);
2181 mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass_image, tp);
2185 return;
2190 * mono_method_has_marshal_info:
2192 gboolean
2193 mono_method_has_marshal_info (MonoMethod *method)
2195 int i, lastp;
2196 MonoClass *klass = method->klass;
2197 MonoTableInfo *methodt;
2198 MonoTableInfo *paramt;
2199 guint32 idx;
2201 if (image_is_dynamic (m_class_get_image (method->klass))) {
2202 MonoReflectionMethodAux *method_aux =
2203 (MonoReflectionMethodAux *)g_hash_table_lookup (
2204 ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
2205 MonoMarshalSpec **dyn_specs = method_aux->param_marshall;
2206 if (dyn_specs) {
2207 for (i = 0; i < mono_method_signature_internal (method)->param_count + 1; ++i)
2208 if (dyn_specs [i])
2209 return TRUE;
2211 return FALSE;
2214 mono_class_init (klass);
2216 methodt = &m_class_get_image (klass)->tables [MONO_TABLE_METHOD];
2217 paramt = &m_class_get_image (klass)->tables [MONO_TABLE_PARAM];
2218 idx = mono_method_get_index (method);
2219 if (idx > 0) {
2220 guint32 cols [MONO_PARAM_SIZE];
2221 guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST);
2223 if (idx + 1 < methodt->rows)
2224 lastp = mono_metadata_decode_row_col (methodt, idx, MONO_METHOD_PARAMLIST);
2225 else
2226 lastp = paramt->rows + 1;
2228 for (i = param_index; i < lastp; ++i) {
2229 mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE);
2231 if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL)
2232 return TRUE;
2234 return FALSE;
2236 return FALSE;
2239 gpointer
2240 mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
2242 void **data;
2243 g_assert (method != NULL);
2244 g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
2246 data = (void **)((MonoMethodWrapper *)method)->method_data;
2247 g_assert (data != NULL);
2248 g_assert (id <= GPOINTER_TO_UINT (*data));
2249 return data [id];
2252 typedef struct {
2253 MonoStackWalk func;
2254 gpointer user_data;
2255 } StackWalkUserData;
2257 static gboolean
2258 stack_walk_adapter (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
2260 StackWalkUserData *d = (StackWalkUserData *)data;
2262 switch (frame->type) {
2263 case FRAME_TYPE_DEBUGGER_INVOKE:
2264 case FRAME_TYPE_MANAGED_TO_NATIVE:
2265 case FRAME_TYPE_TRAMPOLINE:
2266 case FRAME_TYPE_INTERP_TO_MANAGED:
2267 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2268 return FALSE;
2269 case FRAME_TYPE_MANAGED:
2270 case FRAME_TYPE_INTERP:
2271 g_assert (frame->ji);
2272 return d->func (frame->actual_method, frame->native_offset, frame->il_offset, frame->managed, d->user_data);
2273 break;
2274 default:
2275 g_assert_not_reached ();
2276 return FALSE;
2280 void
2281 mono_stack_walk (MonoStackWalk func, gpointer user_data)
2283 StackWalkUserData ud = { func, user_data };
2284 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_LOOKUP_ALL, &ud);
2288 * mono_stack_walk_no_il:
2290 void
2291 mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data)
2293 StackWalkUserData ud = { func, user_data };
2294 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_DEFAULT, &ud);
2297 typedef struct {
2298 MonoStackWalkAsyncSafe func;
2299 gpointer user_data;
2300 } AsyncStackWalkUserData;
2303 static gboolean
2304 async_stack_walk_adapter (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
2306 AsyncStackWalkUserData *d = (AsyncStackWalkUserData *)data;
2308 switch (frame->type) {
2309 case FRAME_TYPE_DEBUGGER_INVOKE:
2310 case FRAME_TYPE_MANAGED_TO_NATIVE:
2311 case FRAME_TYPE_TRAMPOLINE:
2312 case FRAME_TYPE_INTERP_TO_MANAGED:
2313 case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
2314 return FALSE;
2315 case FRAME_TYPE_MANAGED:
2316 case FRAME_TYPE_INTERP:
2317 if (!frame->ji)
2318 return FALSE;
2320 MonoMethod *method;
2321 method = frame->ji->async ? NULL : frame->actual_method;
2323 return d->func (method, frame->domain, frame->ji->code_start, frame->native_offset, d->user_data);
2324 default:
2325 g_assert_not_reached ();
2326 return FALSE;
2332 * mono_stack_walk_async_safe:
2333 * Async safe version callable from signal handlers.
2335 void
2336 mono_stack_walk_async_safe (MonoStackWalkAsyncSafe func, void *initial_sig_context, void *user_data)
2338 MonoContext ctx;
2339 AsyncStackWalkUserData ud = { func, user_data };
2341 mono_sigctx_to_monoctx (initial_sig_context, &ctx);
2342 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (async_stack_walk_adapter, &ctx, MONO_UNWIND_SIGNAL_SAFE, &ud);
2345 static gboolean
2346 last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2348 MonoMethod **dest = (MonoMethod **)data;
2349 *dest = m;
2350 /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
2352 return managed;
2356 * mono_method_get_last_managed:
2358 MonoMethod*
2359 mono_method_get_last_managed (void)
2361 MonoMethod *m = NULL;
2362 mono_stack_walk_no_il (last_managed, &m);
2363 return m;
2366 static gboolean loader_lock_track_ownership = FALSE;
2369 * mono_loader_lock:
2371 * See \c docs/thread-safety.txt for the locking strategy.
2373 void
2374 mono_loader_lock (void)
2376 mono_locks_coop_acquire (&loader_mutex, LoaderLock);
2377 if (G_UNLIKELY (loader_lock_track_ownership)) {
2378 mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) + 1));
2383 * mono_loader_unlock:
2385 void
2386 mono_loader_unlock (void)
2388 mono_locks_coop_release (&loader_mutex, LoaderLock);
2389 if (G_UNLIKELY (loader_lock_track_ownership)) {
2390 mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) - 1));
2395 * mono_loader_lock_track_ownership:
2397 * Set whenever the runtime should track ownership of the loader lock. If set to TRUE,
2398 * the mono_loader_lock_is_owned_by_self () can be called to query whenever the current
2399 * thread owns the loader lock.
2401 void
2402 mono_loader_lock_track_ownership (gboolean track)
2404 loader_lock_track_ownership = track;
2408 * mono_loader_lock_is_owned_by_self:
2410 * Return whenever the current thread owns the loader lock.
2411 * This is useful to avoid blocking operations while holding the loader lock.
2413 gboolean
2414 mono_loader_lock_is_owned_by_self (void)
2416 g_assert (loader_lock_track_ownership);
2418 return GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) > 0;
2422 * mono_loader_lock_if_inited:
2424 * Acquire the loader lock if it has been initialized, no-op otherwise. This can
2425 * be used in runtime initialization code which can be executed before mono_loader_init ().
2427 void
2428 mono_loader_lock_if_inited (void)
2430 if (loader_lock_inited)
2431 mono_loader_lock ();
2434 void
2435 mono_loader_unlock_if_inited (void)
2437 if (loader_lock_inited)
2438 mono_loader_unlock ();
2442 * mono_method_signature_checked:
2444 * Return the signature of the method M. On failure, returns NULL, and ERR is set.
2446 MonoMethodSignature*
2447 mono_method_signature_checked (MonoMethod *m, MonoError *error)
2449 int idx;
2450 MonoImage* img;
2451 const char *sig;
2452 gboolean can_cache_signature;
2453 MonoGenericContainer *container;
2454 MonoMethodSignature *signature = NULL, *sig2;
2455 guint32 sig_offset;
2457 /* We need memory barriers below because of the double-checked locking pattern */
2459 error_init (error);
2461 if (m->signature)
2462 return m->signature;
2464 img = m_class_get_image (m->klass);
2466 if (m->is_inflated) {
2467 MonoMethodInflated *imethod = (MonoMethodInflated *) m;
2468 /* the lock is recursive */
2469 signature = mono_method_signature_internal (imethod->declaring);
2470 signature = inflate_generic_signature_checked (m_class_get_image (imethod->declaring->klass), signature, mono_method_get_context (m), error);
2471 if (!mono_error_ok (error))
2472 return NULL;
2474 mono_atomic_fetch_add_i32 (&inflated_signatures_size, mono_metadata_signature_size (signature));
2476 mono_image_lock (img);
2478 mono_memory_barrier ();
2479 if (!m->signature)
2480 m->signature = signature;
2482 mono_image_unlock (img);
2484 return m->signature;
2487 g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD);
2488 idx = mono_metadata_token_index (m->token);
2490 sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
2492 g_assert (!mono_class_is_ginst (m->klass));
2493 container = mono_method_get_generic_container (m);
2494 if (!container)
2495 container = mono_class_try_get_generic_container (m->klass);
2497 /* Generic signatures depend on the container so they cannot be cached */
2498 /* icall/pinvoke signatures cannot be cached cause we modify them below */
2499 can_cache_signature = !(m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && !(m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && !container;
2501 /* If the method has parameter attributes, that can modify the signature */
2502 if (mono_metadata_method_has_param_attrs (img, idx))
2503 can_cache_signature = FALSE;
2505 if (can_cache_signature) {
2506 mono_image_lock (img);
2507 signature = (MonoMethodSignature *)g_hash_table_lookup (img->method_signatures, sig);
2508 mono_image_unlock (img);
2511 if (!signature) {
2512 const char *sig_body;
2513 /*TODO we should cache the failure result somewhere*/
2514 if (!mono_verifier_verify_method_signature (img, sig_offset, error))
2515 return NULL;
2517 /* size = */ mono_metadata_decode_blob_size (sig, &sig_body);
2519 signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL, error);
2520 if (!signature)
2521 return NULL;
2523 if (can_cache_signature) {
2524 mono_image_lock (img);
2525 sig2 = (MonoMethodSignature *)g_hash_table_lookup (img->method_signatures, sig);
2526 if (!sig2)
2527 g_hash_table_insert (img->method_signatures, (gpointer)sig, signature);
2528 mono_image_unlock (img);
2531 mono_atomic_fetch_add_i32 (&signatures_size, mono_metadata_signature_size (signature));
2534 /* Verify metadata consistency */
2535 if (signature->generic_param_count) {
2536 if (!container || !container->is_method) {
2537 mono_error_set_method_missing (error, m->klass, m->name, signature, "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name);
2538 return NULL;
2540 if (container->type_argc != signature->generic_param_count) {
2541 mono_error_set_method_missing (error, m->klass, m->name, signature, "Inconsistent generic parameter count. Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name);
2542 return NULL;
2544 } else if (container && container->is_method && container->type_argc) {
2545 mono_error_set_method_missing (error, m->klass, m->name, signature, "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name);
2546 return NULL;
2548 if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
2549 signature->pinvoke = 1;
2550 #ifdef TARGET_WIN32
2552 * On Windows the default pinvoke calling convention is STDCALL but
2553 * we need CDECL since this is actually an icall.
2555 signature->call_convention = MONO_CALL_C;
2556 #endif
2557 } else if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2558 MonoCallConvention conv = (MonoCallConvention)0;
2559 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)m;
2560 signature->pinvoke = 1;
2562 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CALL_CONV_MASK) {
2563 case 0: /* no call conv, so using default */
2564 case PINVOKE_ATTRIBUTE_CALL_CONV_WINAPI:
2565 conv = MONO_CALL_DEFAULT;
2566 break;
2567 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL:
2568 conv = MONO_CALL_C;
2569 break;
2570 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL:
2571 conv = MONO_CALL_STDCALL;
2572 break;
2573 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL:
2574 conv = MONO_CALL_THISCALL;
2575 break;
2576 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL:
2577 conv = MONO_CALL_FASTCALL;
2578 break;
2579 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
2580 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
2581 default: {
2582 mono_error_set_method_missing (error, m->klass, m->name, signature, "Unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name);
2584 return NULL;
2586 signature->call_convention = conv;
2589 mono_image_lock (img);
2591 mono_memory_barrier ();
2592 if (!m->signature)
2593 m->signature = signature;
2595 mono_image_unlock (img);
2597 return m->signature;
2601 * mono_method_signature_internal:
2602 * \returns the signature of the method \p m. On failure, returns NULL.
2604 MonoMethodSignature*
2605 mono_method_signature_internal (MonoMethod *m)
2607 ERROR_DECL (error);
2608 MonoMethodSignature *sig = mono_method_signature_checked (m, error);
2609 if (sig)
2610 return sig;
2611 char *type_name = mono_type_get_full_name (m->klass);
2612 g_warning ("Could not load signature of %s:%s due to: %s", type_name, m->name, mono_error_get_message (error));
2613 g_free (type_name);
2614 mono_error_cleanup (error);
2615 return NULL;
2619 * mono_method_signature:
2620 * \returns the signature of the method \p m. On failure, returns NULL.
2622 MonoMethodSignature*
2623 mono_method_signature (MonoMethod *m)
2625 MonoMethodSignature *sig;
2626 MONO_ENTER_GC_UNSAFE;
2627 sig = mono_method_signature_internal (m);
2628 MONO_EXIT_GC_UNSAFE;
2629 return sig;
2633 * mono_method_get_name:
2635 const char*
2636 mono_method_get_name (MonoMethod *method)
2638 return method->name;
2642 * mono_method_get_class:
2644 MonoClass*
2645 mono_method_get_class (MonoMethod *method)
2647 return method->klass;
2651 * mono_method_get_token:
2653 guint32
2654 mono_method_get_token (MonoMethod *method)
2656 return method->token;
2659 gboolean
2660 mono_method_has_no_body (MonoMethod *method)
2662 return ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
2663 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2664 (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2665 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
2668 // FIXME Replace all internal callers of mono_method_get_header_checked with
2669 // mono_method_get_header_internal; the difference is in error initialization.
2670 MonoMethodHeader*
2671 mono_method_get_header_internal (MonoMethod *method, MonoError *error)
2673 int idx;
2674 guint32 rva;
2675 MonoImage* img;
2676 gpointer loc;
2677 MonoGenericContainer *container;
2679 error_init (error);
2680 img = m_class_get_image (method->klass);
2682 // FIXME: for internal callers maybe it makes sense to do this check at the call site, not
2683 // here?
2684 if (mono_method_has_no_body (method)) {
2685 mono_error_set_bad_image (error, img, "Method has no body");
2686 return NULL;
2689 if (method->is_inflated) {
2690 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
2691 MonoMethodHeader *header, *iheader;
2693 header = mono_method_get_header_checked (imethod->declaring, error);
2694 if (!header)
2695 return NULL;
2697 iheader = inflate_generic_header (header, mono_method_get_context (method), error);
2698 mono_metadata_free_mh (header);
2699 if (!iheader) {
2700 return NULL;
2703 return iheader;
2706 if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
2707 MonoMethodWrapper *mw = (MonoMethodWrapper *)method;
2708 g_assert (mw->header);
2709 return mw->header;
2713 * We don't need locks here: the new header is allocated from malloc memory
2714 * and is not stored anywhere in the runtime, the user needs to free it.
2716 g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD);
2717 idx = mono_metadata_token_index (method->token);
2718 rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
2720 if (!mono_verifier_verify_method_header (img, rva, error))
2721 return NULL;
2723 loc = mono_image_rva_map (img, rva);
2724 if (!loc) {
2725 mono_error_set_bad_image (error, img, "Method has zero rva");
2726 return NULL;
2730 * When parsing the types of local variables, we must pass any container available
2731 * to ensure that both VAR and MVAR will get the right owner.
2733 container = mono_method_get_generic_container (method);
2734 if (!container)
2735 container = mono_class_try_get_generic_container (method->klass);
2736 return mono_metadata_parse_mh_full (img, container, (const char *)loc, error);
2739 MonoMethodHeader*
2740 mono_method_get_header_checked (MonoMethod *method, MonoError *error)
2741 // Public function that must initialize MonoError for compatibility.
2743 MONO_API_ERROR_INIT (error);
2744 return mono_method_get_header_internal (method, error);
2747 * mono_method_get_header:
2749 MonoMethodHeader*
2750 mono_method_get_header (MonoMethod *method)
2752 ERROR_DECL (error);
2753 MonoMethodHeader *header = mono_method_get_header_checked (method, error);
2754 mono_error_cleanup (error);
2755 return header;
2760 * mono_method_get_flags:
2762 guint32
2763 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
2765 if (iflags)
2766 *iflags = method->iflags;
2767 return method->flags;
2771 * mono_method_get_index:
2772 * Find the method index in the metadata \c MethodDef table.
2774 guint32
2775 mono_method_get_index (MonoMethod *method)
2777 MonoClass *klass = method->klass;
2778 int i;
2780 if (m_class_get_rank (klass))
2781 /* constructed array methods are not in the MethodDef table */
2782 return 0;
2784 if (method->token)
2785 return mono_metadata_token_index (method->token);
2787 mono_class_setup_methods (klass);
2788 if (mono_class_has_failure (klass))
2789 return 0;
2790 int first_idx = mono_class_get_first_method_idx (klass);
2791 int mcount = mono_class_get_method_count (klass);
2792 MonoMethod **klass_methods = m_class_get_methods (klass);
2793 for (i = 0; i < mcount; ++i) {
2794 if (method == klass_methods [i]) {
2795 if (m_class_get_image (klass)->uncompressed_metadata)
2796 return mono_metadata_translate_token_index (m_class_get_image (klass), MONO_TABLE_METHOD, first_idx + i + 1);
2797 else
2798 return first_idx + i + 1;
2801 return 0;