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
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.
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
62 static MonoCoopMutex loader_mutex
;
63 static mono_mutex_t global_loader_data_mutex
;
64 static gboolean loader_lock_inited
;
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
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")
89 global_loader_data_lock (void)
91 mono_locks_os_acquire (&global_loader_data_mutex
, LoaderGlobalDataLock
);
95 global_loader_data_unlock (void)
97 mono_locks_os_release (&global_loader_data_mutex
, LoaderGlobalDataLock
);
103 static gboolean 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
);
127 mono_loader_cleanup (void)
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
149 * LOCKING: Acquires the loader lock.
152 find_cached_memberref_sig (MonoImage
*image
, guint32 sig_idx
)
156 mono_image_lock (image
);
157 res
= g_hash_table_lookup (image
->memberref_signatures
, GUINT_TO_POINTER (sig_idx
));
158 mono_image_unlock (image
);
164 cache_memberref_sig (MonoImage
*image
, guint32 sig_idx
, gpointer sig
)
168 mono_image_lock (image
);
169 prev_sig
= g_hash_table_lookup (image
->memberref_signatures
, GUINT_TO_POINTER (sig_idx
));
171 /* Somebody got in before us */
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
);
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
;
193 guint32 nindex
, class_index
;
196 guint32 idx
= mono_metadata_token_index (token
);
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
))
209 switch (class_index
) {
210 case MONO_MEMBERREF_PARENT_TYPEDEF
:
211 klass
= mono_class_get_checked (image
, MONO_TOKEN_TYPE_DEF
| nindex
, error
);
213 case MONO_MEMBERREF_PARENT_TYPEREF
:
214 klass
= mono_class_from_typeref_checked (image
, MONO_TOKEN_TYPE_REF
| nindex
, error
);
216 case MONO_MEMBERREF_PARENT_TYPESPEC
:
217 klass
= mono_class_get_and_inflate_typespec_checked (image
, MONO_TOKEN_TYPE_SPEC
| nindex
, context
, error
);
220 mono_error_set_bad_image (error
, image
, "Bad field field '%u' signature 0x%08x", class_index
, token
);
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... */
231 mono_error_set_field_missing (error
, klass
, fname
, NULL
, "Bad field signature class token %08x field token %08x", class_index
, token
);
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
]);
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
);
249 sig_type
= (MonoType
*)cache_memberref_sig (image
, cols
[MONO_MEMBERREF_SIGNATURE
], sig_type
);
252 mono_class_init (klass
); /*FIXME is this really necessary?*/
255 field
= mono_class_get_field_from_name_full (klass
, fname
, sig_type
);
258 mono_error_set_field_missing (error
, klass
, fname
, sig_type
, "Could not find field in class");
265 * mono_field_from_token:
266 * \deprecated use the \c _checked variant
267 * Notes: runtime code MUST not use this function
270 mono_field_from_token (MonoImage
*image
, guint32 token
, MonoClass
**retklass
, MonoGenericContext
*context
)
273 MonoClassField
*res
= mono_field_from_token_checked (image
, token
, retklass
, context
, error
);
274 mono_error_assert_ok (error
);
279 mono_field_from_token_checked (MonoImage
*image
, guint32 token
, MonoClass
**retklass
, MonoGenericContext
*context
, MonoError
*error
)
283 MonoClassField
*field
;
287 if (image_is_dynamic (image
)) {
288 MonoClassField
*result
;
289 MonoClass
*handle_class
;
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
);
300 *retklass
= result
->parent
;
304 if ((field
= (MonoClassField
*)mono_conc_hashtable_lookup (image
->field_cache
, GUINT_TO_POINTER (token
)))) {
305 *retklass
= field
->parent
;
309 if (mono_metadata_token_table (token
) == MONO_TABLE_MEMBERREF
) {
310 field
= field_from_memberref (image
, token
, retklass
, context
, error
);
312 type
= mono_metadata_typedef_from_field (image
, mono_metadata_token_index (token
));
314 mono_error_set_bad_image (error
, image
, "Invalid field token 0x%08x", token
);
317 k
= mono_class_get_checked (image
, MONO_TOKEN_TYPE_DEF
| type
, error
);
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
);
331 field
= mono_class_get_field (k
, token
);
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
);
348 mono_metadata_signature_vararg_match (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
352 if (sig1
->hasthis
!= sig2
->hasthis
||
353 sig1
->sentinelpos
!= sig2
->sentinelpos
)
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)
363 if (!mono_metadata_type_equal (p1
, p2
))
367 if (!mono_metadata_type_equal (sig1
->ret
, sig2
->ret
))
373 find_method_in_class (MonoClass
*klass
, const char *name
, const char *qname
, const char *fqname
,
374 MonoMethodSignature
*sig
, MonoClass
*from_class
, MonoError
*error
)
378 /* Search directly in the metadata to avoid calling setup_methods () */
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
];
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
))))
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
405 other_sig
= mono_method_signature_checked (method
, error
);
406 if (!mono_error_ok (error
)) //bail out if we hit a loader error
408 if (other_sig
&& (sig
->call_convention
!= MONO_CALL_VARARG
) && mono_metadata_signature_equal (sig
, other_sig
))
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
);
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. */
437 if (!((fqname
&& !strcmp (m
->name
, fqname
)) ||
438 (qname
&& !strcmp (m
->name
, qname
)) ||
439 (name
&& !strcmp (m
->name
, name
))))
441 msig
= mono_method_signature_checked (m
, error
);
442 if (!mono_error_ok (error
)) //bail out if we hit a loader error
448 if (sig
->call_convention
== MONO_CALL_VARARG
) {
449 if (mono_metadata_signature_vararg_match (sig
, msig
))
452 if (mono_metadata_signature_equal (sig
, msig
))
458 return mono_class_get_method_by_index (from_class
, i
);
463 find_method (MonoClass
*in_class
, MonoClass
*ic
, const char* name
, MonoMethodSignature
*sig
, MonoClass
*from_class
, MonoError
*error
)
466 char *qname
, *fqname
, *class_name
;
467 gboolean is_interface
;
468 MonoMethod
*result
= NULL
;
469 MonoClass
*initial_class
= in_class
;
472 is_interface
= MONO_CLASS_IS_INTERFACE_INTERNAL (in_class
);
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
);
484 class_name
= qname
= fqname
= NULL
;
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
))
492 if (name
[0] == '.' && (!strcmp (name
, ".ctor") || !strcmp (name
, ".cctor")))
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
);
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
);
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
);
525 if (result
|| !mono_error_ok (error
))
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
);
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
);
548 static MonoMethodSignature
*
549 inflate_generic_signature_checked (MonoImage
*image
, MonoMethodSignature
*sig
, MonoGenericContext
*context
, MonoError
*error
)
551 MonoMethodSignature
*res
;
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
))
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
))
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;
586 mono_metadata_free_type (res
->ret
);
587 for (i
= 0; i
< sig
->param_count
; ++i
) {
589 mono_metadata_free_type (res
->params
[i
]);
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.
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
))
608 cached
= mono_metadata_get_inflated_signature (res
, context
);
610 mono_metadata_free_inflated_signature (res
);
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
;
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
)
644 clause
->data
.catch_class
= mono_class_inflate_generic_class_checked (clause
->data
.catch_class
, context
, error
);
645 goto_if_nok (error
, fail
);
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
661 mono_method_get_signature_full (MonoMethod
*method
, MonoImage
*image
, guint32 token
, MonoGenericContext
*context
)
664 MonoMethodSignature
*res
= mono_method_get_signature_checked (method
, image
, token
, context
, error
);
665 mono_error_cleanup (error
);
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
);
675 guint32 cols
[MONO_MEMBERREF_SIZE
];
676 MonoMethodSignature
*sig
;
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");
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
);
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
);
708 if (!mono_verifier_verify_memberref_method_signature (image
, sig_idx
, error
))
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
);
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
);
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
))
738 cached
= mono_metadata_get_inflated_signature (sig
, context
);
740 mono_metadata_free_inflated_signature (sig
);
742 mono_atomic_fetch_add_i32 (&inflated_signatures_size
, mono_metadata_signature_size (cached
));
746 g_assert (mono_error_ok (error
));
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
757 mono_method_get_signature (MonoMethod
*method
, MonoImage
*image
, guint32 token
)
760 MonoMethodSignature
*res
= mono_method_get_signature_checked (method
, image
, token
, NULL
, error
);
761 mono_error_cleanup (error
);
765 /* this is only for the typespec array methods */
767 mono_method_search_in_array_class (MonoClass
*klass
, const char *name
, MonoMethodSignature
*sig
)
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
)
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
;
791 guint32 nindex
, class_index
, sig_idx
;
793 MonoMethodSignature
*sig
;
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.
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
);
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
);
828 case MONO_MEMBERREF_PARENT_TYPEDEF
:
829 klass
= mono_class_get_checked (image
, MONO_TOKEN_TYPE_DEF
| nindex
, error
);
833 case MONO_MEMBERREF_PARENT_METHODDEF
: {
834 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| nindex
, NULL
, NULL
, error
);
840 mono_error_set_bad_image (error
, image
, "Memberref parent unknown: class: %d, index %d", class_index
, nindex
);
845 mono_class_init (klass
);
847 sig_idx
= cols
[MONO_MEMBERREF_SIGNATURE
];
849 if (!mono_verifier_verify_memberref_method_signature (image
, sig_idx
, error
))
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
);
857 sig
= mono_metadata_parse_method_signature_full (image
, NULL
, 0, ptr
, NULL
, error
);
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
);
870 case MONO_MEMBERREF_PARENT_TYPESPEC
: {
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
);
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
);
886 mono_error_set_bad_image (error
, image
,"Memberref parent unknown: class: %d, index %d", class_index
, nindex
);
890 if (!method
&& mono_error_ok (error
))
891 mono_error_set_method_missing (error
, klass
, mname
, sig
, "Failed to load due to unknown reasons");
896 g_assert (!mono_error_ok (error
));
901 method_from_methodspec (MonoImage
*image
, MonoGenericContext
*context
, guint32 idx
, MonoError
*error
)
905 MonoTableInfo
*tables
= image
->tables
;
906 MonoGenericContext new_context
;
907 MonoGenericInst
*inst
;
909 guint32 cols
[MONO_METHODSPEC_SIZE
];
910 guint32 token
, nindex
, param_count
;
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
))
921 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_METHODSPEC_SIGNATURE
]);
923 mono_metadata_decode_value (ptr
, &ptr
);
925 param_count
= mono_metadata_decode_value (ptr
, &ptr
);
927 inst
= mono_metadata_parse_generic_inst (image
, NULL
, param_count
, ptr
, &ptr
, error
);
931 if (context
&& inst
->is_open
) {
932 inst
= mono_metadata_inflate_generic_inst (inst
, context
, error
);
933 if (!mono_error_ok (error
))
937 if ((token
& MONO_METHODDEFORREF_MASK
) == MONO_METHODDEFORREF_METHODDEF
) {
938 method
= mono_get_method_checked (image
, MONO_TOKEN_METHOD_DEF
| nindex
, NULL
, context
, error
);
942 method
= method_from_memberref (image
, nindex
, context
, NULL
, error
);
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
);
970 static MonoDllMap
*global_dll_map
;
973 mono_dllmap_lookup_list (MonoDllMap
*dll_map
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
) {
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
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
))
992 } else if (strcmp (dll_map
->dll
, dll
)) {
995 if (!found
&& dll_map
->target
) {
996 *rdll
= dll_map
->target
;
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
;
1009 global_loader_data_unlock ();
1014 mono_dllmap_lookup (MonoImage
*assembly
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
)
1017 if (assembly
&& assembly
->dll_map
) {
1018 res
= mono_dllmap_lookup_list (assembly
->dll_map
, dll
, func
, rdll
, rfunc
);
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.
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.
1056 mono_dllmap_insert (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
1059 dllmap_insert_global (dll
, func
, tdll
, tfunc
);
1061 MONO_ENTER_GC_UNSAFE
;
1062 dllmap_insert_image (assembly
, dll
, func
, tdll
, tfunc
);
1063 MONO_EXIT_GC_UNSAFE
;
1068 dllmap_insert_global (const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
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 ();
1087 dllmap_insert_image (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
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
);
1107 free_dllmap (MonoDllMap
*map
)
1110 MonoDllMap
*next
= map
->next
;
1113 g_free (map
->target
);
1115 g_free (map
->target_func
);
1122 dllmap_cleanup (void)
1124 free_dllmap (global_dll_map
);
1125 global_dll_map
= NULL
;
1128 static GHashTable
*global_module_map
;
1131 cached_module_load (const char *name
, int flags
, char **err
)
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
);
1142 global_loader_data_unlock ();
1145 res
= mono_dl_open (name
, flags
, err
);
1147 g_hash_table_insert (global_module_map
, g_strdup (name
), res
);
1148 global_loader_data_unlock ();
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
);
1161 remove_cached_module(gpointer key
, gpointer value
, gpointer user_data
)
1163 mono_dl_close((MonoDl
*)value
);
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
;
1180 is_absolute_path (const char *path
)
1183 if (!strncmp (path
, "@executable_path/", 17) || !strncmp (path
, "@loader_path/", 13) ||
1184 !strncmp (path
, "@rpath/", 7))
1187 return g_path_is_absolute (path
);
1191 * mono_lookup_pinvoke_call:
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
;
1207 char *full_name
, *file_name
, *found_name
= NULL
;
1209 MonoDl
*module
= NULL
;
1210 gboolean cached
= FALSE
;
1211 gpointer addr
= NULL
;
1213 g_assert (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
);
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
);
1230 import
= method_aux
->dllentry
;
1231 orig_scope
= method_aux
->dll
;
1234 if (!piinfo
->implmap_idx
|| piinfo
->implmap_idx
> im
->rows
)
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
)
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
);
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
);
1262 found_name
= g_strdup (found_name
);
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
);
1286 /* Try the original name */
1287 file_name
= g_strdup (new_scope
);
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';
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
);
1306 file_name
= g_strdup_printf ("%s%s%s", dir_name
, G_DIR_SEPARATOR_S
, base_name
);
1309 } else if (strstr (new_scope
, "lib") != new_scope
) {
1310 file_name
= g_strdup_printf ("lib%s", new_scope
);
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
);
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");
1332 #ifndef TARGET_WIN32
1339 dir_name
= g_path_get_dirname (file_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
);
1347 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1348 "DllImport error loading library '%s': '%s'.",
1349 file_name
, error_msg
);
1352 found_name
= g_strdup (file_name
);
1356 if (!module
&& !is_absolute
) {
1360 for (j
= 0; j
< 3; ++j
) {
1365 mdirname
= g_path_get_dirname (image
->name
);
1367 case 1: /* @executable_path@/../lib */
1371 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
1373 char *base
, *newbase
;
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
);
1389 case 2: /* @executable_path@/../Libraries */
1393 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
1395 char *base
, *newbase
;
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
);
1416 while ((full_name
= mono_dl_build_path (mdirname
, file_name
, &iter
))) {
1417 module
= cached_module_load (full_name
, MONO_DL_LAZY
, &error_msg
);
1419 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1420 "DllImport error loading library '%s': '%s'.",
1421 full_name
, error_msg
);
1424 found_name
= g_strdup (full_name
);
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
);
1444 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1445 "DllImport error loading library '%s': '%s'.",
1446 full_name
, error_msg
);
1449 found_name
= g_strdup (full_name
);
1458 module
= cached_module_load (file_name
, MONO_DL_LAZY
, &error_msg
);
1460 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1461 "DllImport error loading library '%s': '%s'.",
1462 file_name
, error_msg
);
1464 found_name
= g_strdup (file_name
);
1479 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_DLLIMPORT
,
1480 "DllImport unable to load library '%s'.",
1485 *exc_class
= "DllNotFoundException";
1486 *exc_arg
= new_scope
;
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
);
1507 if (import
&& import
[0] == '#' && isdigit (import
[1])) {
1511 id
= strtol (import
+ 1, &end
, 10);
1512 if (id
> 0 && *end
== '\0')
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
);
1522 char *mangled_name
= NULL
, *mangled_name2
= NULL
;
1525 int mangle_param_count
;
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
;
1537 if (mangle_stdcall
> 0)
1538 need_param_count
= TRUE
;
1540 for (mangle_param_count
= 0; mangle_param_count
<= (need_param_count
? 256 : 0); mangle_param_count
+= 4) {
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
);
1552 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1554 if (mangle_charset
== 0)
1555 mangled_name
= g_strconcat (import
, "W", NULL
);
1557 /* Try the mangled name last */
1558 if (mangle_charset
== 1)
1559 mangled_name
= g_strconcat (import
, "A", NULL
);
1562 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1564 /* Try the mangled name last */
1565 if (mangle_charset
== 1)
1566 mangled_name
= g_strconcat (import
, "A", NULL
);
1571 if (mangle_param_count
== 0)
1572 param_count
= mono_method_signature_internal (method
)->param_count
* sizeof (gpointer
);
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
);
1585 mangled_name2
= mangled_name
;
1587 mangled_name2
= mangled_name
;
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
);
1596 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1597 "Found as '%s'.", mangled_name2
);
1599 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
,
1600 "Could not find '%s' due to '%s'.", mangled_name2
, error_msg
);
1605 if (mangled_name
!= mangled_name2
)
1606 g_free (mangled_name2
);
1607 if (mangled_name
!= import
)
1608 g_free (mangled_name
);
1617 *exc_class
= "EntryPointNotFoundException";
1622 piinfo
->addr
= addr
;
1627 * LOCKING: assumes the loader lock to be taken.
1630 mono_get_method_from_token (MonoImage
*image
, guint32 token
, MonoClass
*klass
,
1631 MonoGenericContext
*context
, gboolean
*used_context
, MonoError
*error
)
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
];
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
);
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
);
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
);
1677 guint32 type
= mono_metadata_typedef_from_method (image
, token
);
1679 mono_error_set_bad_image (error
, image
, "Bad method token 0x%08x (could not find corresponding typedef).", token
);
1682 klass
= mono_class_get_checked (image
, MONO_TOKEN_TYPE_DEF
| type
, error
);
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
));
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
);
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
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
))
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
;
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
);
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
);
1757 mono_get_method (MonoImage
*image
, guint32 token
, MonoClass
*klass
)
1760 MonoMethod
*result
= mono_get_method_checked (image
, token
, klass
, NULL
, error
);
1761 mono_error_cleanup (error
);
1766 * mono_get_method_full:
1769 mono_get_method_full (MonoImage
*image
, guint32 token
, MonoClass
*klass
,
1770 MonoGenericContext
*context
)
1773 MonoMethod
*result
= mono_get_method_checked (image
, token
, klass
, context
, error
);
1774 mono_error_cleanup (error
);
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 */
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
);
1805 result
= mono_get_method_from_token (image
, token
, klass
, context
, &used_context
, error
);
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
));
1819 mono_image_unlock (image
);
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
);
1835 get_method_constrained (MonoImage
*image
, MonoMethod
*method
, MonoClass
*constrained_class
, MonoGenericContext
*context
, MonoError
*error
)
1837 MonoClass
*base_class
= method
->klass
;
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
);
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
))
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
);
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)
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
);
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
);
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. */
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
);
1930 mono_get_method_constrained_with_method (MonoImage
*image
, MonoMethod
*method
, MonoClass
*constrained_class
,
1931 MonoGenericContext
*context
, MonoError
*error
)
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.
1946 mono_get_method_constrained (MonoImage
*image
, guint32 token
, MonoClass
*constrained_class
,
1947 MonoGenericContext
*context
, MonoMethod
**cil_method
)
1950 MonoMethod
*result
= mono_get_method_constrained_checked (image
, token
, constrained_class
, context
, cil_method
, error
);
1951 mono_error_cleanup (error
);
1956 mono_get_method_constrained_checked (MonoImage
*image
, guint32 token
, MonoClass
*constrained_class
, MonoGenericContext
*context
, MonoMethod
**cil_method
, MonoError
*error
)
1960 *cil_method
= mono_get_method_checked (image
, token
, NULL
, context
, error
);
1964 return get_method_constrained (image
, *cil_method
, constrained_class
, context
, error
);
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 ()))
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
;
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
);
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
);
2011 * mono_method_get_param_names:
2014 mono_method_get_param_names (MonoMethod
*method
, const char **names
)
2018 MonoTableInfo
*methodt
;
2019 MonoTableInfo
*paramt
;
2020 MonoMethodSignature
*signature
;
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
)
2032 if (!signature
->param_count
)
2035 for (i
= 0; i
< signature
->param_count
; ++i
)
2038 klass
= method
->klass
;
2039 if (m_class_get_rank (klass
))
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];
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
);
2066 for (i
= 0; i
< signature
->param_count
; ++i
)
2067 names
[i
] = pnames
[i
];
2072 methodt
= &klass_image
->tables
[MONO_TABLE_METHOD
];
2073 paramt
= &klass_image
->tables
[MONO_TABLE_PARAM
];
2074 idx
= mono_method_get_index (method
);
2076 guint32 cols
[MONO_PARAM_SIZE
];
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
);
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:
2097 mono_method_get_param_token (MonoMethod
*method
, int index
)
2099 MonoClass
*klass
= method
->klass
;
2100 MonoTableInfo
*methodt
;
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
);
2111 guint param_index
= mono_metadata_decode_row_col (methodt
, idx
- 1, MONO_METHOD_PARAMLIST
);
2115 return mono_metadata_make_token (MONO_TABLE_PARAM
, 0);
2117 return mono_metadata_make_token (MONO_TABLE_PARAM
, param_index
+ index
);
2124 * mono_method_get_marshal_info:
2127 mono_method_get_marshal_info (MonoMethod
*method
, MonoMarshalSpec
**mspecs
)
2130 MonoClass
*klass
= method
->klass
;
2131 MonoTableInfo
*methodt
;
2132 MonoTableInfo
*paramt
;
2133 MonoMethodSignature
*signature
;
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
)
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
);
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
);
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
);
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
) {
2179 tp
= mono_metadata_get_marshal_info (klass_image
, i
- 1, FALSE
);
2181 mspecs
[cols
[MONO_PARAM_SEQUENCE
]]= mono_metadata_parse_marshal_spec (klass_image
, tp
);
2190 * mono_method_has_marshal_info:
2193 mono_method_has_marshal_info (MonoMethod
*method
)
2196 MonoClass
*klass
= method
->klass
;
2197 MonoTableInfo
*methodt
;
2198 MonoTableInfo
*paramt
;
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
;
2207 for (i
= 0; i
< mono_method_signature_internal (method
)->param_count
+ 1; ++i
)
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
);
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
);
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
)
2240 mono_method_get_wrapper_data (MonoMethod
*method
, guint32 id
)
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
));
2255 } StackWalkUserData
;
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
:
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
);
2275 g_assert_not_reached ();
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:
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
);
2298 MonoStackWalkAsyncSafe func
;
2300 } AsyncStackWalkUserData
;
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
:
2315 case FRAME_TYPE_MANAGED
:
2316 case FRAME_TYPE_INTERP
:
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
);
2325 g_assert_not_reached ();
2332 * mono_stack_walk_async_safe:
2333 * Async safe version callable from signal handlers.
2336 mono_stack_walk_async_safe (MonoStackWalkAsyncSafe func
, void *initial_sig_context
, void *user_data
)
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
);
2346 last_managed (MonoMethod
*m
, gint no
, gint ilo
, gboolean managed
, gpointer data
)
2348 MonoMethod
**dest
= (MonoMethod
**)data
;
2350 /*g_print ("In %s::%s [%d] [%d]\n", m->klass->name, m->name, no, ilo);*/
2356 * mono_method_get_last_managed:
2359 mono_method_get_last_managed (void)
2361 MonoMethod
*m
= NULL
;
2362 mono_stack_walk_no_il (last_managed
, &m
);
2366 static gboolean loader_lock_track_ownership
= FALSE
;
2371 * See \c docs/thread-safety.txt for the locking strategy.
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:
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.
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.
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 ().
2428 mono_loader_lock_if_inited (void)
2430 if (loader_lock_inited
)
2431 mono_loader_lock ();
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
)
2452 gboolean can_cache_signature
;
2453 MonoGenericContainer
*container
;
2454 MonoMethodSignature
*signature
= NULL
, *sig2
;
2457 /* We need memory barriers below because of the double-checked locking pattern */
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
))
2474 mono_atomic_fetch_add_i32 (&inflated_signatures_size
, mono_metadata_signature_size (signature
));
2476 mono_image_lock (img
);
2478 mono_memory_barrier ();
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
);
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
);
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
))
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
);
2523 if (can_cache_signature
) {
2524 mono_image_lock (img
);
2525 sig2
= (MonoMethodSignature
*)g_hash_table_lookup (img
->method_signatures
, sig
);
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
);
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
);
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
);
2548 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
2549 signature
->pinvoke
= 1;
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
;
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
;
2567 case PINVOKE_ATTRIBUTE_CALL_CONV_CDECL
:
2570 case PINVOKE_ATTRIBUTE_CALL_CONV_STDCALL
:
2571 conv
= MONO_CALL_STDCALL
;
2573 case PINVOKE_ATTRIBUTE_CALL_CONV_THISCALL
:
2574 conv
= MONO_CALL_THISCALL
;
2576 case PINVOKE_ATTRIBUTE_CALL_CONV_FASTCALL
:
2577 conv
= MONO_CALL_FASTCALL
;
2579 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC
:
2580 case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST
:
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
);
2586 signature
->call_convention
= conv
;
2589 mono_image_lock (img
);
2591 mono_memory_barrier ();
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
)
2608 MonoMethodSignature
*sig
= mono_method_signature_checked (m
, error
);
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
));
2614 mono_error_cleanup (error
);
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
;
2633 * mono_method_get_name:
2636 mono_method_get_name (MonoMethod
*method
)
2638 return method
->name
;
2642 * mono_method_get_class:
2645 mono_method_get_class (MonoMethod
*method
)
2647 return method
->klass
;
2651 * mono_method_get_token:
2654 mono_method_get_token (MonoMethod
*method
)
2656 return method
->token
;
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.
2671 mono_method_get_header_internal (MonoMethod
*method
, MonoError
*error
)
2677 MonoGenericContainer
*container
;
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
2684 if (mono_method_has_no_body (method
)) {
2685 mono_error_set_bad_image (error
, img
, "Method has no body");
2689 if (method
->is_inflated
) {
2690 MonoMethodInflated
*imethod
= (MonoMethodInflated
*) method
;
2691 MonoMethodHeader
*header
, *iheader
;
2693 header
= mono_method_get_header_checked (imethod
->declaring
, error
);
2697 iheader
= inflate_generic_header (header
, mono_method_get_context (method
), error
);
2698 mono_metadata_free_mh (header
);
2706 if (method
->wrapper_type
!= MONO_WRAPPER_NONE
|| method
->sre_method
) {
2707 MonoMethodWrapper
*mw
= (MonoMethodWrapper
*)method
;
2708 g_assert (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
))
2723 loc
= mono_image_rva_map (img
, rva
);
2725 mono_error_set_bad_image (error
, img
, "Method has zero rva");
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
);
2735 container
= mono_class_try_get_generic_container (method
->klass
);
2736 return mono_metadata_parse_mh_full (img
, container
, (const char *)loc
, error
);
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:
2750 mono_method_get_header (MonoMethod
*method
)
2753 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, error
);
2754 mono_error_cleanup (error
);
2760 * mono_method_get_flags:
2763 mono_method_get_flags (MonoMethod
*method
, guint32
*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.
2775 mono_method_get_index (MonoMethod
*method
)
2777 MonoClass
*klass
= method
->klass
;
2780 if (m_class_get_rank (klass
))
2781 /* constructed array methods are not in the MethodDef table */
2785 return mono_metadata_token_index (method
->token
);
2787 mono_class_setup_methods (klass
);
2788 if (mono_class_has_failure (klass
))
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);
2798 return first_idx
+ i
+ 1;